Skip to content

Usage

This section covers day-to-day interaction patterns for users who need to read, write, pin, and synchronize state. It focuses on the Sync Web 1.5 general interface shape.

The general compose network exposes three primary web clients and one filesystem-oriented service: Explorer (/explorer/), Workbench (/workbench/), Gateway (/docs plus /api/v1/...), and File System (WebDAV at /webdav/). Together they cover the full operator/developer loop: inspect data, make changes, verify outcomes, mount journal state into ordinary file tools, and convert successful workflows into repeatable API calls.

The Explorer is the state-navigation and content-management interface. It has four explicit modes:

  • Ledger
    • the default landing mode
    • route-based browsing of committed state across bridges and snapshots
  • Stage
    • editable staged state at Self or the selected working journal
    • document and directory oriented editing actions using federated get/set! when routed
  • Access
    • Self-local path-scoped get, set!, and resolve grants
    • unavailable while a remote working route is selected
  • Admin
    • visible only to local interface admins and available only at Self
    • bridge registration and local bridge endpoint sharing
    • public window-size edits and interface admin-list management

Typical Explorer workflow:

  1. Start in Ledger and synchronize to the latest committed root.
  2. Use the working route to select Self or a terminal journal. Every breadcrumb is clickable: selecting Self, an intermediate journal, or the current terminal verifies that route prefix and resets both Stage and Ledger to its shared (*state*) namespace root while preserving prefix Ledger snapshots. Adding or removing a hop follows the same rule; owner-relative suffixes are not carried between journals. The permanent *state* row above the tree children returns to the exact current Stage route or Ledger route/snapshot root. The signed-in user’s existing folder is sorted first and emphasized without renaming it. Other user folders remain navigable when public or explicit sharing grants permit access. When grants begin deeper in a namespace, each ancestor exposes its ordinary immediate folder names for navigation, while opening a child still requires applicable public or principal-specific authority. Explicit deep links remain exact, and Ledger synchronization or snapshot changes preserve an accessible current path with namespace-root fallback. Use Ledger’s mirrored index controls for historical snapshots.
  3. Select a document to switch among Content, view-only Raw, and (in Ledger) proof/verification views. Raw preserves exact stored bytes: inert UTF-8/source where valid, allowlisted browser-native media previews selected by bounded magic-byte checks and safe document-name hints, and hex/download fallback otherwise.
  4. Use the Stage and Ledger tabs as Self-root navigation controls: every click, including the active tab, returns the working route and both selections to Self (*state*), then selects that mode. Use Stage when you want to edit staged documents and directories. Raw remains view-only in Stage and Ledger.
  5. Use stage actions to create documents/directories, upload documents, edit content, and download documents. A denied tree expansion shows an alert beneath that row without replacing the tree, so allowed siblings and upward navigation remain available.
  6. Return the working route to Self before using Access or Admin to manage local policy, bridges, retention settings, or administrators. In Access, a structurally remote principal automatically receives the fixed key-index (-32 -1) used for terminal-local bridge-state authentication; Explorer does not expose controls for this range. Exact local (*state* USER) and (*public*) principals omit the field. The independent Document history window, initially 0 … -1, applies only to resolve and governs committed document-history indexes. The complete stored rule is retained so deletion uses its exact identity. Owner-relative rule paths accept ordinary whitespace-separated segments or quoted human segments such as data "private documents"; backslash escapes literal separators, quotes, and backslashes. Each human segment is encoded exactly once (a%20b becomes stored a%2520b), decoded for display, and retained raw for exact deletion. Administrators explicitly load a username or exact *state* USER, and stale namespace responses cannot replace the selected target.

Admin mutations are serialized and failed values remain editable until a mutation and authoritative reload both succeed. Bridge deletion and incoming-preapproval removal require confirmation. Retention-window decreases show authoritative old/new values and warn that pruned unpinned history cannot be resurrected by widening; equal/increased windows proceed without confirmation, and an unknown current size refuses mutation.

The Explorer is best for operational tasks and data exploration because it separates committed Ledger inspection from staged editing while keeping both under one explicit working route.

Explorer desktop view

The Workbench is the API-oriented query environment. Use it when you want precise control over requests, fast iteration on payload shape, and direct inspection of results.

Typical Workbench workflow:

  1. Start from a known request pattern (for example get, set!, pin!, or bridge!).
  2. Run the request in Scheme form and inspect the returned value.
  3. Iterate on arguments/authentication until behavior matches intent.
  4. Use the final request as a template for automation or service integration.

The Workbench is best for debugging and integration development because it exposes the request/response layer directly.

Workbench desktop view

The Gateway is the web-facing API surface for journal operations. Use it when clients should call stable, versioned HTTP routes instead of direct function-shaped interface requests.

Typical Gateway workflow:

  1. Start with GET /docs to review request and response schemas.
  2. Use GET /api/v1/general/size or another stable route to validate connectivity.
  3. Use public GET routes for size and info; bridge protocol operations such as route, constrained trace, and synchronize! use public POST routes.
  4. Execute restricted application/local administration and optional root operations through authenticated POST routes.
  5. Move validated requests into application clients or automation scripts using the same gateway contracts.

The Gateway is best for service integration because it standardizes journal calls into HTTP endpoints with explicit request validation.

Gateway desktop view

The File System service projects journal state through WebDAV. Use it when existing tools should interact with Synchronic Web data through ordinary file and directory operations instead of direct API calls.

Typical File System workflow:

  1. Mount the share and work in /stage for ordinary mutable file operations.
  2. Browse /ledger/state for current committed content.
  3. Browse /ledger/<index>/state for a specific prior committed snapshot.
  4. Traverse /ledger/bridge/<name>/state for a bridged peer’s current committed state.
  5. Use /control/pin for explicit pin and unpin directives on discovered ledger paths.

The File System service is best for shell tools, editors, archives, source trees, and other workflows that already expect a hierarchical filesystem.

Filesystem projection overview:

/
├── stage/
│ └── ...
├── ledger/
│ ├── state/ (defaults to current head)
│ │ └── ...
│ ├── <index>/ (explicit historical snapshot)
│ │ ├── state/
│ │ │ └── ...
│ │ └── bridge/
│ │ └── <name>/
│ │ ├── state/
│ │ └── ...
│ └── bridge/
│ └── <name>/ (defaults to current head)
│ ├── state/
│ │ └── ...
│ └── bridge/
│ └── ...
└── control/
└── pin

Key semantics:

  • /stage is mutable.
  • /ledger/... is readable but content-immutable.
  • omitting an explicit <index> anywhere in a ledger path defaults to the current head (-1).
  • once you enter any state/ subtree, remaining path segments are ordinary file and directory names.
  • WebDAV Basic Auth uses a Sync Web API token as the password, not the account password.
  • file names that are unsafe as unescaped Scheme symbols are percent-escaped at the service boundary and decoded again for listings.
  • /control/pin is a synthetic UTF-8 file for pin and unpin directives against discovered /ledger/... paths.

Programmatic access is typically where teams standardize integrations across multiple services. The sections below focus on stable request patterns that are easy to lint, test, and automate.

Use this catalog as a quick orientation map. The /interface execution endpoint accepts Scheme or JSON runtime calls via content negotiation, while the conversion endpoints are for debugging and payload authoring.

EndpointDescription
POST /interfaceExecutes Scheme requests or JSON requests depending on Content-Type.
POST /interface/scheme-to-jsonConverts Scheme expressions into JSON payload representations.
POST /interface/json-to-schemeConverts JSON payloads back into Scheme forms for debugging and validation.

Public ledger/interface paths use flat token lists. In Scheme, write local paths as (*state* alice notes) or (-1 *state* alice notes). Bridge traversal is a concise prefix of directional bridge names with optional indexes: (-1 partner 12 archive *state* bob report) selects the current local head, partner index 12, the current archive head, and then Bob’s terminal-local report. In JSON, the same path is [-1, "partner", 12, "archive", "*state*", "bob", "report"].

An optional leading integer selects the local head; each optional integer after a bridge name selects that destination journal’s head. Every omitted index defaults to the current head (-1). A namespace marker such as *state* ends traversal, so remaining tokens are ordinary terminal-local path segments. Nested list paths are an internal ledger representation and are not accepted as public API input.

Restricted operations require an authentication field that identifies the caller and carries the interface secret.

Two caller identities are recognized:

  • Local user principal (e.g. (*state* alice)): a registered local user. The gateway injects this automatically when you are logged in via Kratos. When calling the interface directly, you supply the principal path and the interface secret.
  • Root journal caller: omit identity in the authentication block, which normalizes to (). This is used by journal automation and has no path restrictions.

When calling through the gateway (/api/v1/...), you do not construct the authentication block — the gateway handles it from your session or API token. When calling the interface directly (/interface), you supply it manually:

(authentication ((identity (*state* alice)) (credentials "interface-secret")))

Each local user’s owned namespace is (*state* <username> ...). Owners and local interface administrators can access that namespace. Other local or bridge-derived principals are denied unless the owner creates a recursive path-scoped rule.

A remote rule names the exact terminal-relative principal and the allowed application functions:

((principal (partner *state* alice))
(key-index (-1 -1))
(path (shared inbox))
(get #t)
(set! #t)
(resolve (0 -1)))

key-index is required for remote principals and constrains which terminal-local committed bridge state may authenticate the remote signing key. The separate resolve range constrains document-history indexes. Local and public rules omit key-index. Bridge creation alone grants no application access. Gateway authorize and deauthorize transport the complete exact rule and remain Self-local; $federation is rejected.

A (*public*) rule applies to every caller for the enabled operations. Grants do not need separate parent rules for navigation: a descendant grant permits reading the ordinary immediate listing of each ancestor directory. For example, a public grant at (data public) lets callers traverse admin → data and see the names of all folders beneath data; opening any non-public folder still requires its own principal-specific grant.

TierIdentityPrivileges
Rootomitted local identityAll local query-interface operations.
Local adminLocal principal path in the admin listAll local query-interface operations.
OwnerLocal (*state* <user>) principalOwn namespace and own authorization rules; cannot invoke call! unless separately configured as an Interface administrator.
Granted principalExact local or bridge-derived principalOnly explicitly granted get, set!, and/or resolve paths. Authorization rules do not grant call!.
Public(*public*)Only explicitly public data/proof and constrained bridge-control structure.

Interface administrators must be local principals. Bridge-derived principals cannot be administrators. Staged get-batch/set-batch! may use one signed working route, while resolve-batch groups canonical committed paths and routes compatible groups internally. Pin/unpin batches retain or cut proofs only at the origin. Bridge management, configuration, access management, retention mutation, and secret/window changes remain local-only.

Most JSON integrations can standardize on this envelope and only vary function and arguments. That keeps client implementations simple and makes troubleshooting easier across services.

FieldTypeRequiredNotes
functionsymbol/stringYesAPI function name
argumentsobject / association listUsuallyKeyword-style fields for ledger calls
authenticationalist / objectRestricted calls((identity (*state* alice)) (credentials "secret")) for local users, or ((credentials "secret")) for the root journal caller

Note:

In Scheme form, API queries are association lists. In JSON form, they are objects with equivalent fields.

These examples are intentionally minimal and map directly to frequently used workflows. You can copy them into Workbench first, then move them into automation once validated.

((function get)
(arguments ((path (*state* docs article hash))))
(authentication ((identity (*state* alice)) (credentials "password"))))

Info: get reads current Stage. Use resolve with pinned? and proof? for committed history and verifiable proof material.

((function set!)
(arguments ((path (*state* docs article hash))
(value "0xabc123")
(expression? #t)))
(authentication ((identity (*state* alice)) (credentials "password"))))

Gateway JSON callers add a reserved $federation context to the ordinary operation arguments. Only get, set, and resolve accept a non-empty route; only resolve accepts history, with one index for Self plus one for every route hop.

{
"path": [7, "*state*", "bob", "shared", "message"],
"pinned?": true,
"proof?": true,
"$federation": {
"route": ["carol", "bob"],
"history": [-1, 4, 7]
}
}

The Gateway removes $federation from arguments, the origin journal signs a direct terminal invocation, and the returned proof is checked against the exact selected terminal object.

((function pin!)
(arguments ((path (-1 *state* docs article hash))))
(authentication ((identity (*state* alice)) (credentials "password"))))

Pin and unpin are always local retention operations. For remote content, first perform a federated resolve with proof? enabled, then pin the returned proof at its full Self-relative bridge/history path. Explorer performs this two-step workflow automatically; it never asks the terminal journal to pin on the origin’s behalf.

((function bridge!)
(arguments ((name journal_b)
(interface "http://journal-b.example.org/api/v1/journal/interface")
(remote-name journal_a)))
(authentication ((credentials "password"))))

The converter treats JSON and Scheme as structurally equivalent where possible.

This mapping is the key mental model for moving between web client payloads and Scheme-native request forms. Once this is clear, advanced payloads become much easier to reason about.

SchemeJSON
symbolstring
listarray
association list ((k v) ...)object { "k": v, ... }
object-shaped assoc listobject

Special type wrappers are only needed where plain JSON cannot preserve Lisp/runtime semantics. If a payload seems unexpectedly interpreted, check whether a special type marker is required.

JSON markerScheme value
{"*type/string*": "text"}string
{"*type/quoted*": ...}(quote ...)
{"*type/byte-vector*": "deadbeef"}byte-vector
{"*type/vector*": [...]}vector
{"*type/pair*": [a, b]}dotted pair (a . b)
{"*type/rational*": "1/3"}rational
{"*type/complex*": "1+2i"}complex

Use /interface/scheme-to-json to generate exact JSON for complex expressions, and use /interface/json-to-scheme when debugging client payloads or validating round-trip conversions. For web clients, prefer object-shaped API queries (function, arguments, authentication) because they remain easier to read and diff than raw array forms, and reserve array-shaped JSON for raw root command calls. Prefer *type/string* for literal strings in JSON payloads whenever you need to avoid ambiguity in type conversion.

A common workflow is: prototype in Scheme, convert to JSON, integrate in client code, then round-trip with json-to-scheme during debugging. Teams that include conversion checks in their release process generally catch payload-shape regressions earlier.