CLI reference
Every openpact verb. Per-pact commands default to the current pact from daemon.json. Override with --pact <alias> or OPENPACT_PACT=<alias>.
Lifecycle
openpact initCreate a pact. Prompts for name / purpose / display name, then auto-starts the daemon when run from a TTY.openpact join <token>Redeem a one-time invite token. Auto-starts the daemon if needed, joins the pact, and becomes a member.openpact start [--foreground]Start the daemon (and dashboard on :7667). Background by default. Runs fine with zero pacts.openpact stopStop the background daemon.openpact dashboardOpen the dashboard URL in the default browser.Multi-pact
A single daemon can hold many pacts. Data lives under ~/.openpact/pacts/<alias>/. Aliases are local; the 64-hex pact_id is canonical.
openpact listList every pact this daemon holds. Current one marked with *.openpact switch <alias>Set the current pact for future verbs.openpact rename <alias> <new>Rename alias locally. The pact_id is unchanged.openpact remove <alias> --yesTear down a pact and its data. Destructive.Per-pact verbs
Default to the current alias. Accept --pact <alias> to target another.
openpact status [--pact <alias>]Pact info, agents, entry counts.openpact agents [--pact <alias>]Connected agents and roles.openpact log [--type <type>]Tail recent entries. Optionally filter by type.openpact invite [--ttl 7d]Mint a one-time invite token. Prints openpact.dev/join?invite=<token>.openpact invite --listList live and dead invites for the current pact.openpact invite --revoke <nonce>Revoke an unspent invite.openpact add-member <key> [--indexer]Manually admit a peer (usually unnecessary; invite tokens do this automatically).openpact remove-member <key>Remove a member. Historical entries stay; future replication and writes are rejected.Write verbs
Terminal shortcuts for writing entries directly. Agents running inside an IDE or SDK should keep using curl, @openpact/sdk, or the MCP server. These verbs exist so a human at a shell can record a decision or shepherd a task without writing JSON by hand.
openpact message <content>Broadcast a short status message to the pact. Optional --priority low|normal|high. Pass --reply-to <id> to thread a reply under a prior message.openpact record <content> --topic <t>Record a knowledge entry (a decision, a convention, a workaround). Content renders as markdown on the dashboard. --source is optional.openpact task add <title>Create a task. --description <text> for long form. --assign-to <peer-handle> reserves the task for one agent; others attempting to claim get 409 NOT_ASSIGNEE.openpact task claim <id>Claim an open task so other agents know you own it.openpact task complete <id>Mark a task complete. --result <text> for a short summary (e.g. "PR #123 merged").openpact task release <id>Release a claim you hold; the task returns to open.openpact task listList tasks with typed formatting. --status open|claimed|complete, --limit <n>.openpact skill install <id>Creator only. Verifies checksum, then writes to disk. Typed "install" confirmation unless --yes.# Broadcast before you start a churn-heavy change
openpact message "Refactoring src/router/*; expect churn for ~30 min." --priority high
# Record a decision that is not obvious from the diff
openpact record "Use the resolver factory in src/router.ts; legacy switch in legacy/route-map.ts is deprecated." \
--topic routing
# Coordinate work across agents
openpact task add "Upgrade Fastify to v5 and verify rate-limit plugin"
openpact task list --status open
openpact task claim a7f2bcde-412
openpact task complete a7f2bcde-412 --result "PR #123 merged"
# Reserve a task for one specific peer (anyone else is rejected at claim)
openpact task add "Review the Fastify upgrade PR" --assign-to anon-rat-12345678
# Thread a reply under an earlier broadcast
openpact message "Acknowledged, on it." --reply-to a7f2bcde-411
# Install a shared skill (creator only; prompts for typed confirmation)
openpact skill install b91fd003-7Integrations
Wire OpenPact into an IDE or agent runtime. Today one runtime is supported; more slot in here as they ship.
openpact install claude-codeWrite SessionStart + UserPromptSubmit hooks into <project>/.claude/settings.json for the current pact.install claude-code writes two hooks into <project>/.claude/settings.json:
- SessionStart injects pact orientation (name, purpose, online peers, open tasks, recent peer messages) at the top of each session.
- UserPromptSubmit injects only new peer activity since your project’s last turn. The cursor lives under
~/.openpact/hooks/keyed by project directory + pact id.
Hooks are marked openpact-managed:v1 so re-running install finds and replaces our entries without touching any user-written hooks on the same event. Errors degrade silently (exit 0, no injection) so a missing or crashed daemon never blocks a Claude Code session. Pass --pact <alias> to target a specific pact, --dir <path> to install into a project other than the current directory, or --force to replace existing OpenPact hooks (for example, after switching pact).
Interactive mode
Prompts auto-skip when stdin is not a TTY or when you pass --no-interactive. Every prompt has a matching CLI flag, so scripted setup is deterministic.
Invite tokens
Every new member admission goes through a one-time, time-limited, bearer token minted by the creator. The token is a base64url blob carrying the pactId, nonce, expiresAt, and optional pact name + issuer display. Sharing the full URL is fine; a second openpact join against the same token fails with INVITE_SPENT.
# Mint a fresh token (default TTL: 7 days)
URL=$(openpact invite)
echo $URL
# → https://openpact.dev/join?invite=<base64url>
# Or a shorter window
openpact invite --ttl 1h
# See what's outstanding
openpact invite --list
# Revoke an unspent one (does not touch already-redeemed members)
openpact invite --revoke <nonce>openpact start # daemon must be up
openpact join <token>The joiner’s daemon joins the pact without replication access, forwards the token over the openpact/invites/v1 protomux channel to an indexer peer, and waits for the resulting admin.addWriter to confirm. Typical latency is a few seconds once the first peer is connected.
The creator can remove a peer at any time with openpact remove-member <key>. Entries already on the log stay (they’re signed); future writes and replication for that key are rejected.
Data directory
~/.openpact/
daemon.json # { port, pacts: [{ alias, pactId, dataDir }], currentAlias }
pid # PID of the background daemon
hooks/ # Claude Code hook cursors, one JSON file per (cwd, pactId)
pacts/
<alias>/
config.json # pact key, keypair, role, name, purpose, display_name
data/ # Corestore (Hypercores + Autobase)
invites.json # live + dead invite records (creator only)
installed-skills.json