Skip to main content

Community Packages

Gno packages under examples/gno.land/p/... are useful references and may be deployed on public networks, but many are community-maintained rather than official APIs. Treat them like dependencies:

  • read the package docs and tests;
  • check whether the package is maintained and used by other realms;
  • verify the exact escaping, ordering, storage, and error semantics you rely on;
  • prefer small, focused packages that are easy to replace;
  • write and publish better alternatives when the current package does not fit.

This page is not an endorsement list. It is a starting point for discovering patterns that may be useful when designing your own realm or package.

Some packages below are marked (quarantined) — they currently live under examples/quarantined/ and are not yet deployed on public networks. Treat them as design references; their import paths are not importable on-chain until they graduate out of quarantine.

Markdown Helpers​

Start with the official markdown sanitizer for untrusted text when your target Gno version provides it. See Raw public text in Render for the recommended gno.land/p/nt/markdown/sanitize/v0 shape:

import "gno.land/p/nt/markdown/sanitize/v0"

func Render(path string) string {
return "# Echo\n\n" + sanitize.InlineText(path)
}

Community markdown builders are still useful for composing output after you know whether each helper sanitizes internally or expects sanitized input.

  • gno.land/p/moul/md/v0: helpers for building markdown links, headings, lists, images, code blocks, and text escaping.

    import "gno.land/p/moul/md/v0"

    func Render(_ string) string {
    return md.H1("Tasks") + md.TodoList([]string{"review", "ship"}, []bool{true, false})
    }
  • gno.land/p/moul/mdtable/v0: helpers for markdown tables. Use this when your Render output is tabular and you want pipe escaping handled consistently.

    import "gno.land/p/moul/mdtable/v0"

    func Render(_ string) string {
    table := mdtable.Table{Headers: []string{"ID", "Status"}}
    table.Append([]string{"1", "open"})
    return table.String()
    }
  • gno.land/p/nt/mdalert/v0: helpers for Gno-Flavored Markdown alert blocks.

  • gno.land/p/sunspirit/md/v0: a builder-oriented markdown package. It is convenient when a view is assembled from optional fragments.

    import "gno.land/p/sunspirit/md/v0"

    func Render(_ string) string {
    return md.NewBuilder().Add(md.H1("Profile"), md.Bold("active")).Render("\n")
    }

Storage Helpers​

Use these as references for access-pattern-specific storage, not as a reason to skip your own review. If a package almost fits but has unclear semantics, consider improving it or publishing a clearer alternative.

For append-only feeds, a list helper can replace a hand-rolled nextID plus tree pattern:

import "gno.land/p/moul/ulist/v0"

var posts = ulist.New()

func AddPost(post Post) {
posts.Append(post)
}

func RecentPosts(offset, count int) []ulist.Entry {
return posts.GetByOffset(offset, count)
}

For ordered tree keys, combine avl.Tree with seqid instead of stringified integers:

import (
"gno.land/p/nt/avl/v0"
"gno.land/p/nt/seqid/v0"
)

var ids seqid.ID
var posts avl.Tree

func AddPost(post *Post) {
posts.Set(ids.Next().Binary(), post)
}

For compact allowlists over numeric IDs, a bitset can be cheaper than storing one map or tree entry per flag:

import "gno.land/p/jeronimoalbi/bitset"

var claimed = bitset.New(1024)

func MarkClaimed(id uint64) {
claimed.Set(id)
}

func IsClaimed(id uint64) bool {
return claimed.IsSet(id)
}

Access-Control Helpers​

  • gno.land/p/nt/ownable/v0: owner-gated administration with explicit cur realm checks.
  • gno.land/p/nt/pausable/v0 (quarantined): pause switches layered on an ownable.Ownable.
  • gno.land/p/moul/authz/v0: authorization helper patterns worth studying when a single owner is not enough.

Use these packages to reduce repeated authorization code, but keep the realm's identity model explicit. A realm method should still pass its own captured cur into the helper:

import "gno.land/p/nt/ownable/v0"

var owner = ownable.NewWithAddress("g1...")

func SetName(cur realm, name string) {
if !cur.IsCurrent() {
panic("invalid realm")
}
owner.AssertOwnedBy(cur.Previous().Address())
displayName = name
}

Structured Data Helpers​

Prefer explicit parsing over ad-hoc string splitting when the input format has nesting, quoting, or escaping rules:

import "gno.land/p/onbloc/json/v0"

func DecodeTitle(input string) (string, bool) {
root, err := json.Unmarshal([]byte(input))
if err != nil {
return "", false
}
title, err := root.GetKey("title")
if err != nil || !title.IsString() {
return "", false
}
value, err := title.GetString()
return value, err == nil
}

Application Patterns​

  • gno.land/p/agherasie/forms (quarantined): form creation, typed answers, deadlines, and validation.
  • gno.land/p/lou/blog (quarantined): a larger package split across posts, comments, moderation, rendering, and query helpers.
  • gno.land/p/morgan/chess (quarantined): domain-heavy package structure with tests around game rules.

Use these as source-reading material for package boundaries and tests, not as drop-in frameworks. A good reuse decision should identify the one piece you need instead of copying an entire application shape.