const DemoKey
DemoKey names the namespace gnoweb browses when no ?u= is given. It is a plain string rather than an address so it can never collide with one.
Package ns is a Plan 9 namespace server for gno.land.
gno.land/r/moul/x/plan9/ns/v0A Plan 9 namespace server for gno.land. Every account gets a private,
persistent namespace: its own RAM root plus a mount table it alone controls.
Realms publish file trees into /srv, accounts bind those trees wherever they
like, and a read-only rc shell renders the whole thing in gnoweb.
1gnokey maketx call -pkgpath gno.land/r/moul/x/plan9/ns/v0 \
2 -func Exec -args 'bind -ac /srv/dev /dev; echo hello > /tmp/greeting'
Then browse it at /r/moul/x/plan9/ns/v0:ns?u=<your address>.
This is the part of Plan 9 that gno does not otherwise have. The chain has a single global tree of realm paths that looks the same to everybody; here a name means what you bound it to. Composing two realms that were never written to work together stops being a redeploy and becomes a transaction.
| call | what it does |
|---|---|
Post(cur, name, f) |
publish a ninep.File tree under /srv/<name> |
Unpost(cur, name) |
withdraw it; only the posting realm may |
Exec(cur, line) |
run an rc command line against the caller's namespace |
Reset(cur) |
throw the caller's namespace away |
Run(key, line) |
the read-only query side, used by Render |
Namespace(key) |
the mount table, in ns(1) format |
Render routes: ns, ls/<path>, cat/<path>, stat/<path>, walk/<path>,
and rc?c=<command> for any read-only command line. ?u= picks whose namespace;
it defaults to a seeded demo one, so gnoweb shows something live with no
transaction.
This chain's /lib/namespace: a private ram root, the mount points Plan 9
requires to exist before anything can be bound onto them, /srv mounted, and
/dev bound from it when a device server has been posted.
mount #s /srv
bind /srv/dev /dev
Mounted trees are read-only by construction. ninep.File has no mutating
method, so grafting a foreign realm's tree into your namespace cannot be turned
into a write against that realm; writes only ever reach a memfs tree this realm
created for you. A crossing write method would mint this realm's frame for the
callee, which is the confused-deputy shape r/gov/dao's Executor relies on
deliberately and p/nt/grc20's Teller refuses deliberately. It is out of
scope for v0, and three abort tests pin the boundary: a second realm cannot
take over a /srv name, a write to a mounted tree fails with read-only file server, and a command line that fails part way aborts the whole call.
/srv names are first come, first served, with the posting realm recorded and
the only one allowed to unpost. Squatting is possible and accepted for an
experiment.
Built on ninep,
memfs,
ns and
rc. Design and analysis:
moul/gno-contracts#136.
Not affiliated with Plan 9. Plan 9 from Bell Labs is the work of the Computing Science Research Center at Bell Labs; the name and the marks are theirs, and the copyright is held by the Plan 9 Foundation. This realm borrows the vocabulary and none of the code: it is an independent homage, asking what that ecosystem's spirit looks like on a chain. Full attribution: NOTICE.
Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
Dependency graph:

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.
Package ns is a Plan 9 namespace server for gno.land.
Every account gets a private, persistent namespace: its own RAM root plus a mount table it alone controls. Realms publish file trees into /srv, accounts bind those trees wherever they like, and a read-only rc shell renders the whole thing in gnoweb.
This is the part of Plan 9 that gno does not otherwise have. The chain has a single global tree of realm paths that looks the same to everybody; here a name means what YOU bound it to. Composing two realms that were never written to work together stops being a redeploy and becomes a transaction:
1gnokey maketx call -pkgpath gno.land/r/moul/x/plan9/ns/v0 -func Exec \
2 -args 'bind -ac /srv/dev /dev; echo hello > /tmp/greeting'
SECURITY. Mounted trees are READ-ONLY by construction: ninep.File has no mutating method, so grafting a foreign realm's tree into your namespace cannot be turned into a write against that realm. Writes only ever reach a memfs tree this realm created for you. A crossing write method would mint THIS realm's frame for the callee, which is the confused-deputy shape that r/gov/dao's Executor relies on deliberately and p/nt/grc20's Teller refuses deliberately; it is out of scope for v0. See moul/gno-contracts#136.
NOTICE. Plan 9 from Bell Labs is the work of the Computing Science Research Center at Bell Labs; the name and the marks are theirs, and the copyright is held by the Plan 9 Foundation (https://p9f.org). This realm is not affiliated with, endorsed by, or sponsored by them, and contains no Plan 9 code: it borrows the vocabulary so that the design reads without a glossary, and it is an homage, asking what that ecosystem's spirit looks like on a chain. Full attribution: NOTICE.md at the root of moul/gno-contracts.
Exec runs a command line against the CALLER's namespace and returns its output. The namespace belongs to cur.Previous().Address(), so a user gets theirs and a realm gets its own.
An error panics, so a half-applied command line reverts with the transaction rather than leaving a namespace nobody asked for.
Keys lists the namespaces that exist, in order.
Namespace returns key's mount table, in ns(1) format.
Post publishes a file tree under name in /srv, where any account can bind it. The posting realm is recorded and is the only one that may Unpost.
Names are first come, first served, which is fine for an experiment and would not be for anything else.
Render browses a namespace.
1Render("") overview, posted services, how to drive it
2Render("ns?u=<key>") the mount table
3Render("ls/bin?u=<key>") a directory listing (ls -l)
4Render("cat/tmp/greeting") a file
5Render("stat/bin") the 9P stat, with the union width
6Render("walk/bin/rc") how each element of a path resolves
7Render("rc?c=<command>") any read-only rc command line
?u= selects the namespace; it defaults to the demo one.
Reset discards the caller's namespace, so the next use rebuilds the default.
ResetDemo rebuilds the demo namespace. Anyone may call it: it is a demo, and the alternative is a demo that the first visitor ruins for everybody.
Run executes a READ-ONLY command line against key's namespace. It is the query side of Exec: no transaction, no writes, safe from Render.
Services lists the posted service names, in order.
Unpost withdraws a service. Only the realm that posted it may do so.