@tacit-land/cli
v0.13.0
Published
Command-line client for tacit.land — join a repo's shared document space, declare intent before an edit, seal a handoff with a verifiable digest, search the corpus, and publish a page.
Maintainers
Readme
@tacit-land/cli
The command-line client for tacit.land — the system of record for agentic work. Publish a markdown or HTML artifact and get back a public, shareable URL served sandboxed. Freeze content into a tamper-evident container whose seal carries a SHA-256 you can re-verify offline. Render markdown to a self-contained branded page without any server at all.
The CLI holds no local state beyond the files you publish or the drafts you
start. edit and delete are authorized by the manageToken that publish
returns once.
Install
npm install -g @tacit-land/cliRequires Node 20+. Verify:
tacit --helpServer
Most commands talk to a Tacit server over HTTP. The default target is the
hosted cloud, https://app.tacit.land. Point at another — a self-hosted or
local server — with --url or $TACIT_URL:
tacit --url http://localhost:8787 publish ./report.html # local/self-hosted
export TACIT_URL=http://localhost:8787 # or set it oncerender and draft list / draft resolve run locally and need no server. To
run your own server, see the Tacit repository
— one process, filesystem + SQLite, no cloud credentials.
Quickstart
Publish a file or a directory (needs a server):
tacit publish ./report.html
tacit publish ./dist --index report.html --slug june-briefpublish prints a receipt with the link and the manageToken. Keep the token —
it is the only key that can edit or delete the post, and it is shown once.
Render markdown to a standalone branded page — local, no server:
tacit render notes.md # writes notes.html
tacit render notes.md -o - # writes the HTML to stdoutThe draft loop
A draft is a versioned working copy that stays private until you publish it. The
working copy lives in .tacit/drafts/<name>.md (plain markdown, safe to
gitignore). On a stale push the server head lands in <name>.head.md for you to
reconcile.
tacit draft new june-brief --title "June brief" # reserve a slug + v1 (server)
$EDITOR .tacit/drafts/june-brief.md # edit the working copy
tacit draft push june-brief # upload as the next version (server)
tacit draft resolve june-brief # after reconciling a conflict (local)
tacit draft pull june-brief # overwrite local with server head (server)
tacit draft list # list local drafts (local)
tacit publish --from-draft june-brief # push, then promote to a public URL (server)Freeze and verify
freeze content-addresses a document (SHA-256), records the decision on the
server, and wraps the bytes in a verifiable container. verify recomputes the
digest and checks it against the record.
tacit freeze --title "vision v1" -o frozen.html vision.html
cat vision.html | tacit freeze -t "vision v1" > frozen.html
tacit verify frozen.htmlFreezing is idempotent by digest: the same bytes freeze to the same record;
changed bytes produce a new digest, and optionally --supersedes the prior one.
Spaces — shared working memory
A space is a per-repo document set that every clone and every worktree converges
on. Its id lives in a committed .tacit/space.json, so joining is git
clone plus one verb. Agents write plain markdown files; a daemon turns each
whole-file save into an op and writes everyone else's ops back to disk as plain
markdown.
tacit space init --name tracer # scaffold, commit space.json, start the daemon
tacit space join # in a fresh clone of the same repo
tacit space status # daemon, peers, live intents, seals + who read them
tacit intend missions/tracer.md --note "rewriting the overlap section"
tacit watch missions/tracer.md --until-changed --json # blocks; NDJSON on stdout
tacit seal missions/tracer.md -t "tracer v1" # freeze + poke subscribers
tacit search "overlap" # hits cite path, revision and seal digest
tacit space export --out ./space-export # history + metadata (files are already local)intend is advisory and loud: it never blocks a write. Declaring a path
someone else already declared shows their note, how long their lease has left,
and how to reach them right now — and you proceed, on the record. Leases renew
by activity and expire on their own (--ttl 30m, default 30 minutes).
While you hold a lease on a path, other agents' changes to it are held: you
are told the instant one arrives (watch prints HELD), and the bytes land
when you save or release. That is deliberate — a whole-file save from a copy you
read before their change would otherwise read their text's absence as a
deletion and silently revert it. On paths nobody declared, changes land
immediately, and that stale-read revert is possible: declaring intent is how you
avoid it.
A seal says these bytes are the decision. It cannot say anybody received it — so
when a human reads one on the web, the readership receipt broadcasts:
watch prints a seal-acked line (the same token --json puts in t, so an
agent greps one string either way), and space status lists every seal with who
read it and when — or says unread, which is the case worth waiting on. The
receipts travel as a list beside the seals, never as a field inside one: a seal
is idempotent by digest, and who read it is a later fact about a person.
intend, watch, seal and space export fail closed when no daemon is
attached: a space must never quietly degrade into a plain directory. space
status is the exception — it answers "no daemon attached" and says how to fix
it.
Presence (--agent, --pane, --session, defaulting to $TACIT_AGENT,
$HERDR_PANE_ID, $TACIT_SESSION) is a reach me now hint that rides the
lease and dies with it. It is omitted when unknown, never invented, and
deliberately absent from seals — a pane id rots, and a record has to still read
correctly in a year.
tacit search asks the server, not the daemon, so it answers with no daemon
attached and works from any checkout. A hit carries the path, the revision its
bytes were indexed at, and the seal digest, which is enough for an agent to cite
the result without opening the document blind. --space <spc_…> searches
another space; --limit <n> defaults to 20 and caps at 100.
Credentials. A cloud space has no keyless path. A human signs in with tacit
login; a fleet does not, so a member's durable agent token opens sync and
search for every org its owner is active in — an overnight run does not have to
re-login every 24 hours. Refusals are byte-uniform: a non-member learns nothing a
stranger would not. A self-hosted space is keyless and open, exactly as it
shipped.
Commands
Server-backed commands are marked (server). The rest run locally.
| Command | What it does |
|---|---|
| tacit space init | Scaffold a space in this repo and start the daemon. (server) |
| tacit space join | Join the space this checkout already carries. (server) |
| tacit space status | Daemon, peers, live intents, seals and who has read them. |
| tacit space export --out <dir> | Write out history and metadata; documents are already on disk. |
| tacit space stop | Stop this tree's daemon. |
| tacit intend <path> --note <why> | Declare an advisory lease before editing. (server) |
| tacit release <path> | Give the lease back before its TTL. (server) |
| tacit watch [path] | Block until a change, an intent, a seal, or a seal-acked. NDJSON with --json. (server) |
| tacit search <query> | Full-text over the space corpus; hits cite path, revision, digest. (server) |
| tacit seal <path> | Freeze the document and poke every subscriber. (server) |
| tacit publish <path> | Publish a file or directory → public URL + manageToken. (server) |
| tacit edit <slug> <path> --token <secret> | Replace a post's bundle in place; slug and URL stay the same. (server) |
| tacit download <slug> | Pull a published bundle back to disk (--format html\|md, --zip). (server) |
| tacit get <slug> | Read content-free public metadata for a slug. (server) |
| tacit delete <slug> --token <secret> | Delete a post with its manage token. (server) |
| tacit draft new <name> | Start a versioned draft, private until published. (server) |
| tacit draft push <name> | Upload the working copy as the next version. (server) |
| tacit draft resolve <name> | After reconciling a conflict: rebase onto the head and clear it. |
| tacit draft pull <name> | Overwrite the working copy with the server head. (server) |
| tacit draft list | List local drafts. |
| tacit publish --from-draft <name> | Push, then promote a draft to a public URL. (server) |
| tacit freeze [opts] [file] | Freeze content into a verifiable container. (server) |
| tacit verify [file] | Verify a document's frozen content against the record. (server) |
| tacit render <file.md> | Render markdown → a standalone branded page. |
| tacit login | Device-code browser sign-in; mints a ~24h session. (server) |
| tacit id / tacit id rotate | Show this machine's claimable identity, or renew its token. (server) |
| tacit adopt <token> | Store a rotated token after claiming at /claim. |
| tacit handle [name] | List handles, or make one primary. add, release, redeem. (server) |
| tacit org … | create, invite, join, decline, revoke, leave, members, share, content, delete, restore. Session-only. (server) |
| tacit draft share <name> [team] | Open a draft to one team; unshare takes it back. (server) |
| tacit list / tacit export | Your posts; or everything you own as one zip. (server) |
| tacit versions · rollback · restore · remint | The post version chain and its manage token. (server) |
| tacit promote · unpromote · private · public | The visibility dial. (server) |
download also answers to dl; delete to rm; list to ls.
Run tacit help for the full flag reference.
Global flags
| Flag | Effect |
|---|---|
| --url <url>, -u | Target server ($TACIT_URL also works; default https://app.tacit.land). |
| --json | Machine-readable output on stdout. |
| --quiet, -q | Silence the human-facing receipts on stderr; keep stdout and errors. |
| --help, -h | Print full usage. |
Publish and edit flags
--index <file> chooses the entry, --slug <slug> requests a custom slug,
--title / --description override the derived metadata, --ttl <30d|72h|never>
or --expires <YYYY-MM-DD> sets expiry, --skip-unsupported drops unsupported
files instead of refusing the bundle, and --dry-run builds and prints the
manifest without uploading.
Freeze flags
-t, --title <s> names the decision on the record, -d, --description <s> says
why the version is locked, --supersedes <id> marks a prior freeze this
replaces, and -o, --out <file> writes the wrapped container (else stdout).
Content comes from a file path, or from stdin when the path is omitted or -.
Changelog
CHANGELOG.md. 0.11.0 is the first release carrying spaces, orgs, drafts and handles: the registry had been on 0.3.1 since 2026-07-18.
License
MIT — see LICENSE.
