The deletion-safety thread guarded the CLI (`--force`) and the MCP tool
(`confirm_space`), but `DELETE /api/v2/repos/{id}` itself still cascade-
deleted a fully populated space — every checkpoint, session, and turn —
with no server-side check. Any client that bypassed the CLI/MCP guards
(a direct API call, the web UI, a future client) reopened the incident
path.
Gate the route: `delete_repo` now counts the space's checkpoints and
refuses with 409 plus a structured detail (`message`, `checkpoint_count`,
`requires_force`) unless `?force=true` is passed — the same shape as the
`checkpoint delete` dependent-guard. An empty space still deletes with no
force.
Wire the existing clients through the new signal so their behavior is
unchanged: the CLI passes `force=args.force` (its own `--force` gate),
the MCP tool passes `force=true` after its `confirm_space` gate, and
quickstart passes `force=true` to tear down its own demo space.
CLI:
smriti skills list — enumerate targets + version
smriti skills show <target> — print rendered content to stdout
smriti skills install <target> — write to target's default destination
smriti skills install <target> --dry-run — preview without writing
smriti skills install <target> --force — overwrite same-or-newer version
smriti skills install <target> --destination PATH — override default path
The skills group does not hit the backend; rendering is a local
package-data lookup. Version-aware refusal is already implemented in
the renderer — install prints a clear "Skipped: already has version X"
message and exits non-zero without --force.
MCP:
smriti_install_skill(target: str) -> str
Returns the rendered skill pack wrapped in a fenced markdown block with
the suggested destination path at the top. Unlike the CLI, the MCP
tool does NOT write any files — the MCP server runs in the host's
arbitrary working directory, so the agent is expected to read the
suggested destination and write the file using its host's own file
tools (Edit/Write/Bash). This keeps the MCP server read-only from the
host filesystem's perspective.
Thirteen tools total now registered on the FastMCP instance.
smriti state and smriti_state now default to the /state endpoint from
the previous commit, which returns main HEAD plus active non-main
branches plus a lightweight divergence signal. The main continuation
brief still renders first and is unchanged; the two new sections are
appended after it and elided cleanly when there is no fork activity.
Output shape for a single-agent project is byte-identical to before,
so existing users see no change. Projects with multiple agents on
different branches now see one line per active branch in an Active
branches section, and if any branch disagrees with main on decisions
a Divergence signal section names the specific conflicting decisions
and points at smriti compare for the full diff.
Hard caps from the endpoint (5 branches, 2 divergent pairs, 3
decisions per side) keep the aggregate output digestible no matter
how busy the project is.
--main-only (CLI) / main_only=True (MCP) falls back to the legacy
two-call get_head + get_commit path for scripts that parsed the old
shape.
format_state_brief gains an optional space_state kwarg; existing
callers passing only positional args are unaffected.
Round 5 dogfood surfaced three small friction items:
- smriti_list_checkpoints only rendered short hashes, forcing agents to
make a second round trip to get the UUID they needed for fork/compare/
restore. format_commit_list now appends the full UUID in parentheses
when c["id"] is populated; legacy callers without ids still render a
clean line. CLI output benefits equally since formatters are shared.
- The mcp SDK logs "Processing request of type ..." at INFO on every
tool call, cluttering host log panels. smriti-mcp main() now defaults
the mcp logger to WARNING. Set SMRITI_MCP_LOG_LEVEL=INFO (or DEBUG)
in the host's env block to re-enable verbose logging when debugging.
- Add README notes acknowledging that the mcp SDK negotiates the
protocol version on its own during initialize, and documenting the
new log-level env var.
Round 4 validated that the Smriti CLI surface is complete. This is the
next transport: an MCP stdio server that exposes the same operations as
tools inside MCP-aware hosts (Claude Code, Cursor, Windsurf) so agents
can read and write reasoning state natively in their session instead of
shelling out to the `smriti` binary.
The server lives inside the existing CLI package as a sibling to
client.py and main.py. One `pip install -e ./cli` installs both the
`smriti` and `smriti-mcp` console scripts. Architecture is a thin shim:
each tool builds a SmritiClient, calls 1-2 client methods, pipes the
result through an existing formatter, and returns a string. FastMCP
auto-wraps the string into TextContent. Errors raise SmritiToolError
(wrapping SmritiError with HTTP status + structured detail); FastMCP
converts raised exceptions into MCP error responses.
Zero reimplementation of API logic, zero duplicated formatting, zero
changes to client.py, formatters.py, main.py, or the backend.
Twelve tools, 1:1 with the CLI verbs:
smriti_list_spaces smriti_state
smriti_create_space smriti_list_checkpoints
smriti_delete_space smriti_show_checkpoint
smriti_create_checkpoint smriti_review_checkpoint
smriti_delete_checkpoint smriti_restore
smriti_fork smriti_compare
Two deliberate differences from the CLI:
- No `-y` confirmation flag on destructive tools. The MCP host's
tool-approval UI is the gate.
- smriti_create_checkpoint uses the extract path only (no
--from-json mode) and does NOT auto-capture cwd as project_root.
MCP servers run in the host's arbitrary working directory, so
cwd would plant garbage paths. Callers pass project_root
explicitly when they want it populated.
Testing: 33 unit tests across all 12 tools using a
MagicMock(spec=SmritiClient) fixture in tests/conftest.py. Each tool
has at least one happy path and one error path; the complex ones
(smriti_state, smriti_create_checkpoint, smriti_delete_checkpoint)
have extra tests for their branches (no-checkpoints short-circuit,
dry-run, existing-session, 409-with-dependents formatting,
409-with-non-dict-fallback, empty-content pre-check).
End-to-end stdio protocol smoke verified independently: the
`smriti-mcp` binary responds to `initialize` with protocol version
2025-03-26 and returns all 12 tools on `tools/list`. Ready for
`mcp dev smriti_cli.mcp_server:mcp` Inspector UI exploration or
direct Claude Code connection.
cli/README.md gets a new MCP server section with installation,
example Claude Code config, tool list, and notes on the project_root
and confirmation-gate differences from the CLI.