smriti/cli
Himanshu Dongre 64caf0c801 Add space metrics endpoint and sync docs with current product surface
Metrics: GET /api/v5/metrics/spaces/{id} returns coordination (checkpoints,
agents, cross-agent continuations, claim completion rate), state quality
(decisions/tasks per checkpoint, structured task adoption, milestones),
and branch lifecycle KPIs. All computed on demand from existing data —
no new schema, no events, no background jobs. CLI: smriti metrics <space>.

Doc sync: fix stale tool counts (CONTRIBUTING 15→17, cli/README 16→17),
update REPO_STRUCTURE (skill pack v1.5→v1.9, test files/counts), remove
shipped branch-lifecycle from ARCHITECTURE "not yet" section, add task
IDs + task-referenced claims + capabilities manifest + recheck pattern
to ARCHITECTURE structured tasks section, add coordination primitives
summary to README.
2026-04-14 01:11:56 +05:30
..
smriti_cli Add space metrics endpoint and sync docs with current product surface 2026-04-14 01:11:56 +05:30
tests Add stable task IDs and task-referenced claims for collision detection 2026-04-14 00:16:46 +05:30
pyproject.toml Add Smriti agent skill pack source and renderer 2026-04-12 02:07:47 +05:30
README.md Add space metrics endpoint and sync docs with current product surface 2026-04-14 01:11:56 +05:30

smriti-cli

Command-line access to Smriti's reasoning-state backend. Built for coding agents and scripts — pipe JSON in, get readable markdown out.

Install

From the repo root:

cd cli
pip install -e .

This installs a smriti command on your PATH.

Configuration

Set the backend URL via env var (defaults to http://localhost:8000):

export SMRITI_API_URL=http://localhost:8000

Or pass --api-url on any command.

MCP server

Run Smriti as a local MCP server so agents inside Claude Code, Cursor, or Windsurf can read and write reasoning state natively — no subprocess-shelling to the smriti binary.

Installation. Bundled with the CLI. pip install -e ./cli installs both smriti and smriti-mcp on your PATH.

Claude Code config (typically ~/.config/claude-code/mcp.json or ~/Library/Application Support/Claude/claude_desktop_config.json — check your host's docs for the exact path):

{
  "mcpServers": {
    "smriti": {
      "command": "smriti-mcp",
      "env": { "SMRITI_API_URL": "http://localhost:8000" }
    }
  }
}

Restart the host and the smriti_* tools appear in the tool picker.

Available tools (17):

Tool Purpose
smriti_list_spaces List all spaces
smriti_create_space Create a new space
smriti_delete_space Delete a space and all its checkpoints
smriti_state Multi-branch continuation brief (includes active work claims + divergence signal)
smriti_list_checkpoints List checkpoints in a space (optional branch filter)
smriti_show_checkpoint Print a specific checkpoint as markdown
smriti_create_checkpoint Create a checkpoint from freeform markdown (via extractor)
smriti_review_checkpoint Run consistency review on a checkpoint
smriti_delete_checkpoint Delete a checkpoint (refuses with dependents unless cascade=true)
smriti_checkpoint_note Add a note to a checkpoint (kinds: note, milestone, noise)
smriti_restore Print a specific checkpoint as a continuation brief
smriti_fork Fork a new session from an existing checkpoint
smriti_compare Structured diff between two checkpoints
smriti_close_branch Mark a branch as integrated, abandoned, or active
smriti_claim Declare a work claim before starting work (pre-work intent visibility)
smriti_claim_done Mark a work claim as done or abandoned
smriti_install_skill Return the Smriti agent skill pack for a host (claude-code / codex)

Example. In a Claude Code session with Smriti MCP connected, ask "show me the current state of my-project". The agent calls smriti_state(space="my-project"), the MCP server hits the backend, pipes the result through the same format_state_brief formatter the CLI uses, and returns the continuation brief you'd otherwise get from smriti state my-project at the terminal — directly inside the chat context.

Notes:

  • The MCP server talks to the same backend as the CLI. Keep the backend running.
  • Destructive tools (smriti_delete_space, smriti_delete_checkpoint) have no per-tool confirmation prompt — the MCP host's tool-approval UI is the gate.
  • smriti_create_checkpoint always uses the extract path. Agents pass freeform markdown and Smriti's background LLM extracts the structured fields. Pass dry_run=True to preview the extracted payload before committing.
  • smriti_create_checkpoint does NOT auto-capture project_root (unlike the CLI, which uses cwd). MCP servers run in the host's arbitrary working directory, so cwd would plant garbage paths on every checkpoint. Pass project_root="/absolute/path" explicitly if you want that field populated.
  • Protocol version. The mcp SDK negotiates the protocol version on its own during the initialize handshake — you get whatever the installed mcp package and your host agree on, and that's fine. No Smriti code pins a version.
  • Logging. The SDK logs Processing request of type … at INFO on every tool call. smriti-mcp defaults the mcp logger to WARNING so host log panels stay readable. Set SMRITI_MCP_LOG_LEVEL=INFO (or DEBUG) in the host's MCP env block when you need to debug a transport issue.

Smoke-test the server without a host. The mcp SDK ships with an Inspector UI:

mcp dev smriti_cli.mcp_server:mcp

Opens a browser-based tool explorer connected over stdio. Click through tools/list (expect 17 entries, all prefixed smriti_) and try each tool interactively.

Installing the Smriti skill pack

The MCP server and CLI give an agent the ability to read and write reasoning state. They don't teach it when or why. Without explicit guidance, an agent dropped into a Smriti-enabled project will call a few tools, fail to reach for them at session start, and quietly fall back to writing HANDOFF.md — the exact pattern Smriti exists to replace. The skill pack closes that gap.

A skill pack is a single versioned markdown file installed into the agent host's project directory. It lives in the agent's system context, so the heuristics are always in scope during a session instead of behind a docs link nobody opens. Two targets ship today:

Target Default destination Primary tool mode
claude-code ./.claude/skills/smriti/SKILL.md MCP (smriti_state(...))
codex ./AGENTS.md CLI (smriti state ...)

Both targets render from the same source-of-truth template, so the workflow heuristics (when to checkpoint, when NOT to checkpoint, when to fork, how to detect drift) are identical across hosts — only the primary tool notation varies.

Install via the CLI:

smriti skills list                              # show targets + template version
smriti skills show claude-code                  # print the rendered content to stdout
smriti skills install claude-code               # write to default destination
smriti skills install claude-code --dry-run     # preview without writing
smriti skills install codex --destination my-AGENTS.md   # override destination
smriti skills install claude-code --force       # overwrite an existing same-version file

The installer is version-aware: it refuses to overwrite a destination whose installed version is at least as new as the template's version unless you pass --force. Older versions are upgraded in place with no flag needed.

Install from an MCP host. Ask the agent directly: "Install the Smriti skill pack for this project." The agent calls smriti_install_skill(target="claude-code"), which returns the rendered markdown plus the suggested destination path. Unlike the CLI, the MCP tool does not write files — the MCP server lives in the host's arbitrary working directory and has no business planting files. The agent is expected to read the suggested destination from the tool output and write the file using its host's own file tools (Edit, Write, Bash).

What the skill pack teaches. In order of weight:

  1. Read state first. Unconditional reflex at session start. Call smriti_state before reading any file or writing any code.
  2. When to checkpoint. At inflection points — decisions made, hypotheses rejected, sub-problems solved, handoffs imminent.
  3. When NOT to checkpoint. This is the load-bearing section and it gets equal weight to the previous one. Agents are told explicitly not to checkpoint after every small step, not to produce end-of-session blobs, not to treat commits as a save button, not to stack commits on inconsistent state, and not to re-checkpoint existing state. A three-question signal test and a concrete frequency target (24 checkpoints per 4-hour session) give the agent deterministic criteria for each call.
  4. Drift detection. Specific heuristics for noticing when the state brief disagrees with the agent's own work, and three correct responses (review, compare, surface to the human) — with an explicit prohibition on "quietly picking a side."
  5. Anti-patterns. A concise list of things to reject: HANDOFF.md, silent state reads, inconsistent author_agent tags, /chat/send from inside a tool loop.

Verifying it worked. After smriti skills install claude-code, open Claude Code on the project and ask it to do work. A correctly-installed skill pack means the agent calls smriti_state unprompted at session start, says "Reading current state from Smriti." out loud, and never writes a HANDOFF.md no matter how long the session runs.

Commands

smriti init <space> [--description "..."]             # one-step agent onboarding

smriti space list
smriti space create <name> [--description "..."]
smriti space delete <space> [-y]

smriti state <space>                                     # multi-branch continuation brief (full artifacts by default)
smriti state <space> --preview                           # truncate artifacts to a short preview
smriti state <space> --main-only                         # legacy single-HEAD path (pre-V4 behaviour)
smriti state <space> --json                              # structured output

smriti claim create <space> --agent <name> --scope "..." # declare work intent before starting
smriti claim create <space> --agent <name> --scope "..." --intent-type review
smriti claim create <space> --agent <name> --scope "..." --task-id impl-1  # reference a specific task ID
smriti claim done <claim-id>                             # mark a claim as done
smriti claim abandon <claim-id>                          # mark a claim as abandoned
smriti claim list <space>                                # list active claims

smriti metrics <space>                                   # project-level KPIs

smriti skills list                                       # list skill pack targets and template version
smriti skills show <target>                              # print rendered skill pack to stdout
smriti skills install <target>                           # write skill pack to target's default path
smriti skills install <target> [--destination <path>] [--dry-run] [--force]

smriti fork <checkpoint-id> [--branch <name>]            # new session from checkpoint
smriti restore <checkpoint-id>                           # brief of a specific checkpoint
smriti compare <checkpoint-a> <checkpoint-b>             # structured diff

smriti checkpoint create <space>                         # reads JSON from stdin
smriti checkpoint create <space> --from-json <path>      # from JSON file
smriti checkpoint create <space> --extract               # reads markdown, LLM extracts schema fields
smriti checkpoint create <space> --extract --dry-run     # preview the extracted payload without committing
smriti checkpoint create <space> --session <session-id>  # attach to existing session
smriti checkpoint create <space> --author-agent claude-code
smriti checkpoint create <space> --project-root /path    # override cwd auto-capture
smriti checkpoint show <checkpoint-id>
smriti checkpoint list <space>
smriti checkpoint review <checkpoint-id>
smriti checkpoint delete <checkpoint-id> [--cascade] [-y]

smriti state shows full artifact content by default — flip to --preview for the truncated brief.

smriti checkpoint create auto-captures the current working directory as the checkpoint's project_root so cross-agent handoffs know where the project actually lives on disk. Pass --project-root /absolute/path to override or --no-project-root to skip. Tag the checkpoint with an explicit --author-agent <name> (like claude-code or codex-local); without it, the backend falls back to the session's active provider.

Extracting checkpoints from freeform agent output: instead of hand-writing the JSON payload, pipe an agent's markdown output to --extract and let Smriti's background LLM extract the structured fields (decisions, assumptions, tasks, open questions, entities, artifacts) for you:

# Extract and commit in one step
cat /tmp/r3_agent_a_output.md | smriti checkpoint create my-project --extract --author-agent codex-A

# Preview what would be extracted, without committing
cat /tmp/r3_agent_a_output.md | smriti checkpoint create my-project --extract --dry-run

--extract reads stdin as freeform markdown, sends it to POST /api/v5/checkpoint/extract, and uses the returned fields to build the commit payload. --dry-run prints the extracted payload as JSON and exits without creating a checkpoint. --extract and --from-json are mutually exclusive.

Every command supports --json for structured output.

Using Smriti from a coding agent

Smriti is designed to be driven by a coding agent inside its tool loop — either by shelling out to smriti from any host, or by calling the smriti_* MCP tools directly (Claude Code, Cursor, Windsurf). The workflow is the same in both modes, and the rest of this section is transport-agnostic — CLI commands and their MCP equivalents are shown side by side. The shape was validated across five rounds of dogfood testing with real cross-agent handoffs.

The pattern is always:

  1. Orient. Read the current state of the space before doing anything.
  2. Work. Do whatever the task requires. Smriti has no opinion about what happens between checkpoints.
  3. Checkpoint. Write a structured snapshot at each inflection point.
  4. Hand off. The next agent reads the new state and continues.

1. Orient

smriti state my-project

From an MCP host, the agent calls smriti_state(space="my-project"). Either way you get the same markdown brief — objective, summary, decisions, assumptions, tasks, open questions, and full artifact content — rendered into the agent's context. This is the minimum set of facts the next agent needs to continue work.

Multi-branch by default. If other agents are working on the same project on different branches, smriti state appends a concise ## Active branches section listing up to 5 recent non-main branches (one line per branch, with author attribution), and a ## Divergence signal section when any active branch disagrees with main on decisions. Both sections are elided cleanly when the project has no fork activity, so single-agent projects see output identical to the pre-V4 format. The divergence signal caps at the top 3 conflicting decisions per side per branch and points at smriti compare for the full diff — it stays digestible even on busy projects. Pass --main-only (CLI) or main_only=True (MCP) to fall back to the legacy single-HEAD view when a script needs the old shape.

For a list of past checkpoints (with full UUIDs so you can feed them back into fork / compare / restore):

smriti checkpoint list my-project

MCP equivalent: smriti_list_checkpoints(space="my-project").

2. Checkpoint at each inflection point

In early rounds of dogfood, agents had to hand-write JSON payloads. From V3 onward, the preferred path is freeform markdown through the LLM extractor — pass the same kind of note you'd leave a teammate and Smriti pulls out the structured fields:

cat <<'MD' | smriti checkpoint create my-project --extract --author-agent claude-code
# Decided on Pydantic for the state validation layer

After trying dataclass-based validation and hitting the injection-attack
surface from unbounded extra fields, going with Pydantic BaseModel and
`extra="forbid"`. Latency overhead is ~0.3 ms per call, well under budget.

## Open questions
- How do we share state across parallel agent runs?
- Cleaner schema-versioning story for migrations?

## Artifacts
- Draft implementation: see `state_layer.py`
MD

--extract posts the markdown to /api/v5/checkpoint/extract, gets back the structured fields, and commits. Add --dry-run to preview the extraction without writing anything:

cat /tmp/handoff.md | smriti checkpoint create my-project --extract --dry-run

The CLI auto-captures $(pwd) as the checkpoint's project_root so the next agent knows where the project lives on disk. Override with --project-root /absolute/path or skip with --no-project-root. Tag the author with --author-agent claude-code / --author-agent codex-local so space history attributes each checkpoint to the agent that wrote it.

MCP equivalent — agent calls smriti_create_checkpoint(space="my-project", content="# Decided on Pydantic ...", author_agent="claude-code"). The MCP server runs the same extract → commit pipeline. Note that MCP does not auto-capture project_root (the MCP server lives in the host's arbitrary cwd); pass project_root="/absolute/path" explicitly when you want the field populated.

Review a checkpoint for consistency before handing it off:

smriti checkpoint review <checkpoint-id>

Surfaces possible contradictions, hidden assumptions, already-resolved open questions, and unused entities. MCP equivalent: smriti_review_checkpoint(checkpoint_id="<id>").

3. Hand off to the next agent

A second agent (different process, different model family, different session) starts fresh. It runs smriti state my-project — or calls smriti_state from inside its MCP host — and receives the same brief the first agent just wrote. There is no prose handoff, no pasting markdown between windows, no re-explaining. The agent picks up where the previous one left off and continues working.

This is the core loop. Rounds 3 through 5 of dogfood testing exercised exactly this pattern across Claude Code ↔ Codex handoffs, same-family Codex ↔ Codex handoffs, and a round 5 end-to-end test that drove all 17 MCP tools from a host-less Python client. The shape holds.

Branching when you want to explore an alternative

Sometimes an agent wants to try a different direction without losing the main line. Fork from any checkpoint into a new session on its own branch:

# Fork a new session off checkpoint C1
smriti fork <C1-checkpoint-id> --branch alternative-design

# Output gives you a new session UUID. Write a checkpoint into it:
cat alternative.md | smriti checkpoint create my-project \
    --extract --session <fork-session-id> --author-agent codex-local

# Compare the two branches
smriti compare <C1-checkpoint-id> <fork-checkpoint-id>

# Pull any checkpoint back into context as a continuation brief
smriti restore <fork-checkpoint-id>

smriti compare shows the common ancestor, per-side objectives / summaries, and Shared / Only in A / Only in B splits for decisions, assumptions, and tasks. The shared-set matching is case- and punctuation-insensitive, so two agents phrasing the same commitment differently still show up as shared.

smriti restore renders a specific checkpoint in the same shape as smriti state, so the agent reads it and continues as if that checkpoint were current HEAD.

MCP equivalents: smriti_fork(checkpoint_id="<C1>", branch="alternative-design"), smriti_create_checkpoint(..., session="<fork-session-id>"), smriti_compare(checkpoint_a="<A>", checkpoint_b="<B>"), smriti_restore(checkpoint_id="<id>"). The same four tools, the same four operations, no host-specific glue.

Checking freshness before checkpointing

If you have been working for more than a few minutes, check whether the project state has moved since you started — before you checkpoint:

smriti state my-project --since <your-base-checkpoint-id> --compact

Your base checkpoint ID is the HEAD you read at session start. If state is unchanged, proceed. If state has changed, the output lists the new checkpoints so you can decide whether to reconcile, fork, or continue.

MCP equivalent: smriti_state(space="my-project", since="<base-id>", compact=True).

Checkpoint payload schema

Only message is required. Every other field defaults to empty.

Field Type Notes
message string Short title (required)
objective string What you are working toward
summary string Narrative of what was figured out
decisions string[] Explicit choices made
assumptions string[] Things taken for granted
tasks string[] Concrete action items
open_questions string[] Unresolved issues
entities string[] Key concepts, tools, names
artifacts object[] {id, type, label, content} entries
project_root string Absolute path to the project's working directory. Auto-captured by the CLI at commit time; can be overridden via the payload or --project-root.
author_agent string Agent identifier. The CLI flag --author-agent overrides any payload value; when unset the backend tags the checkpoint with the session's active provider.

Space resolution

<space> arguments accept either the space name or the UUID. Names are matched exactly first, then case-insensitively. If multiple spaces match, the CLI asks you to use a UUID.

Exit codes

  • 0 success
  • 1 API error, invalid input, or backend unreachable
  • 130 interrupted (Ctrl+C)