Forum

Forum is a public-read, registered-author-write Lace application. Its Deno CLI, browser, registrar, and waypoint host share the same TypeScript records, authority checks, projections, actions, and synchronization policy. The host has no Forum authority of its own. The browser keeps OPFS status in profile details and shows a main-page warning only when Lace falls back to localStorage or memory.

Workspace and keys

Every CLI workspace has one $FORUM_HOME/forum.json. Create a key, initialize the workspace, and set a public profile:

export FORUM_HOME="$PWD/.alice"
deno task forum key create keys/alice.json
deno task forum config init \
  --steward 'V.<forum-steward>.H3' \
  --waypoint 'ws:127.0.0.1:8798/interlace' \
  --key keys/alice.json
deno task forum profile set Alice

config init --key initially maps every task to that key. The task map contains direct key-file paths for registration.request, post.write, registration.manage, moderation.manage, and capability.manage. Edit those paths when duties use different keys. There is no identity-name registry or key directory scan.

Configured relative paths resolve below the workspace and must remain inside it. Global --as KEY-FILE overrides the selected task key for one invocation; absolute paths are accepted explicitly. Key files contain only by_value and bySecret. Loading re-derives the By value and, on Unix-like systems, rejects group- or world-readable files. Creation uses a 0700 directory and exclusive 0600 file.

deno task forum config show
deno task forum key show keys/alice.json
deno task forum key list
deno task forum --as keys/staff.json profile set 'Forum staff'

The host operational key/store and registrar store are separate from task keys and the normal CLI Lace.

CLI usage

forum [--home PATH] [--as KEY-FILE] COMMAND

registration request [--message TEXT] [--sync]
registration status
registration pending [--format text|jsonl]
registration grant|deny REQUEST [--sync]
registration revoke SUBJECT [--sync]
capability grant|revoke SUBJECT registration.manage|moderation.manage [--sync]
moderation hide|restore TARGET [--reason-code CODE] [--sync]
post TITLE [BODY] [--sync]
reply TOPIC [BODY] [--sync]
topics | topic TOPIC | replies TOPIC
sync

post and reply read stdin when the body argument is absent:

printf 'First post\n' | deno task forum post 'Hello'
printf 'A reply\n' | deno task forum reply 'S.<topic>.H3'
deno task forum sync

Mutations store locally first. If optional --sync fails, the command reports the new hash and leaves the record local. Filesystem stores are single-writer; do not concurrently open one $FORUM_HOME/lace from separate commands.

Registration and authority

An applicant publishes a request; an authorized manager grants or denies that exact request:

deno task forum registration request --message 'I would like to participate.' --sync
deno task forum registration pending --format jsonl
deno task forum registration grant 'S.<request>.H3' --sync
# or: deno task forum registration deny 'S.<request>.H3' --sync
deno task forum registration status

Status is missing, requested, active, denied, or revoked. A denial resolves only its linked request, does not revoke active registration, and does not prevent a later request.

The root Forum Steward implicitly holds all administrative capability. It alone grants the fixed, non-recursive registration.manage and moderation.manage capabilities:

deno task forum capability grant \
  'V.<staff>.H3' registration.manage --sync
deno task forum capability grant \
  'V.<moderator>.H3' moderation.manage --sync

Delegated registration and moderation decisions exact-link the current grant. Revoking that grant invalidates every delegated decision under it; granting the capability again does not revive old decisions. Root decisions need no grant link. Current capability, registration, and moderation state use greatest TAI, then greatest record hash. Hiding is projection, not deletion.

Browser administrator keys

A root operator can provision a separate browser administrator without copying the root key or changing CLI task assignments:

deno task forum browser-key issue keys/gui-admin.json \
  --origin https://forum.example \
  --task registration.manage --task moderation.manage --sync

The printed import URL fragment contains a By-secret value. Keep it out of logs, shell history, tickets, and chat. The browser removes the fragment before fetching and may replace only its administrative task assignments; its personal request/post key remains separate. browser-key link reprints a link for an existing key. Links are reusable key copies, not one-use tokens. Root capability revocation is the authority transition. Root and waypoint-operational keys are rejected.

Registrar

The registrar selects the direct registration.manage key, uses $FORUM_HOME/registrar/lace, and holds a workspace registrar lock. It is not a host subtask.

deno task forum registrar once --auto-register
deno task forum registrar run --auto-register
deno task registrar once --register-with /opt/forum/bin/review-request
deno task registrar run --register-with /opt/forum/bin/review-request

--register-with requires an absolute executable path. The hook receives the request hash as argv[1] and exact canonical request bytes on stdin. Exit 0 grants and exit 1 denies; launch failures, signals, timeout, excessive output, or any other exit leave the request pending.

Hook execution is at least once if the worker crashes before storing its decision, so side effects must be idempotent by request hash. After local storage, publication retries do not rerun the hook. Every decision rechecks current registration.manage authority. run uses bounded reconnect backoff and handles SIGINT/SIGTERM.

Host

deno task forum --home .host key create keys/operator-bootstrap.json
deno task forum --home .host config init \
  --steward 'V.<forum-steward>.H3' \
  --waypoint 'wss:forum.example/interlace' \
  --key keys/operator-bootstrap.json
deno task forum --home .host host run
# deployment listener override:
deno task forum --home .host host run --listen ws:0.0.0.0:8798/interlace

The configured waypoint is the public connection address, not a listener bind. Without --listen, the host binds to ws:127.0.0.1:8798/interlace. Host identity and storage remain operational boundaries and grant no Forum capability. The base frontend entry is //u//forum//index.html; this HTTP-compatible host serves //u//forum/http//index.html.

Validation

From the Lace repository root:

(cd incubator/forum && deno task typecheck)
(cd incubator/forum && deno task test)
(cd incubator/forum && deno task test:e2e)
git diff --check -- incubator/forum