Namespaces

A namespace is a path. It is the HKDF info string for a key, the unit of a grant, and the line on the key rail.

ns()

namespaces.ts
import { ns } from "satchel-sdk";

const memory = ns("memory/assistant");   // ok
ns("Memory/Assistant");              // throws INVALID_NAMESPACE: uppercase
ns("memory//assistant");             // throws INVALID_NAMESPACE: empty segment

A path is 3 to 64 characters of lowercase letters and digits joined by / or -. ns() returns a branded string, so passing a raw string where a Namespace is expected is a type error. See ns.

What separates two namespaces

satchel/ns/memory/assistant and satchel/ns/memory/notes are different HKDF info strings, so they derive unrelated keys from the same passkey output. A record sealed under one opens under the other zero times: its header carries the keccak256 hash of the info string, and unseal compares it with the namespace you asked for before decrypting. The mismatch is a named error, NAMESPACE_MISMATCH, not a decryption failure. The proof page triggers it from a real wrong-namespace call.

What each app owns

One convention keeps apps from colliding: the first segment is the app or domain, the rest names the data.

NamespaceOwned byHolds
memory/assistantPip, readable by Fern through a grantwhat the assistant remembers about you
memory/notesPipa second folder under the same passkey, used on the proof page
trustset/notestrustsetsealed notes, see the migration guide

Fingerprints

fingerprint(ns) returns eight hex characters of SHA-256 over a fixed label and the namespace key. It is safe to show and compare: two devices that hold the same passkey print the same value for the same namespace.