smriti/docs/API.md
Himanshu Dongre 3161c1a3c1 Close the skill-pack and API docs staleness before the website sprint
Skill pack (template.md -> AGENTS.md, .claude/skills/smriti/SKILL.md):
- §3.2 Repo reconciliation: lead with `## Repo state`'s automated drift
  signals; keep the manual git log checks as the documented fallback
  for checkpoints without recorded git state.
- §3.5 Backend reachability: lead with `smriti doctor` as the
  structured health check; keep `curl /health` as the raw fallback.
- Bump skill pack version 2.4 -> 2.5; re-render AGENTS.md (the
  .claude/skills/smriti/SKILL.md install is local-only and untracked).
- test_skill_pack: bump the expected version; add four single-line
  required phrases proving the new content shipped (`Repo state`,
  `smriti doctor`, "ahead of the last checkpoint", "checkpoint taken
  on a different branch").

docs/API.md:
- POST /api/v4/chat/commit: add `repo_state` to the request body
  example and a paragraph explaining its purpose (drift detection),
  persistence (`context_blob`), and read-back path (V4 state endpoint).
- DELETE /api/v2/repos/{repo_id}: add the missing section with the
  `force` query param, 204/404/409 responses, and the structured
  detail shape for the 409 refusal.

CLI suite: 253 passed. AGENTS.md and SKILL.md verified byte-identical
to fresh render(target) output.
2026-05-20 20:40:58 +05:30

23 KiB
Raw Permalink Blame History

Smriti API Reference

This document covers the V4 (chat) and V5 (checkpoint) APIs — the current primary interfaces. V1 and V2 endpoints are legacy and not documented here; see docs/legacy/ for historical context.

Base URL: http://localhost:8000

All request and response bodies are JSON. All IDs are UUIDs.


V4 — Chat API

Prefix: /api/v4/chat

The V4 API manages Sessions, Turns, and message sending. It is the primary runtime API for the Smriti workspace.


Sessions

Create a session

POST /api/v4/chat/sessions

Creates a new Session, optionally attached to a Space and seeded from a Checkpoint.

Request body:

{
  "repo_id": "<space-uuid>",
  "title": "Optional title",
  "provider": "openrouter",
  "model": "anthropic/claude-3.5-sonnet",
  "seed_from": "head"
}
Field Type Required Description
repo_id UUID string No Attach to a Space. Omit for a FRESH session.
title string No Defaults to "Session MMM DD HH:MM"
provider string No Defaults to chat.default_provider from config
model string No Model identifier for this provider
seed_from string No "head" (default) seeds from latest Checkpoint; "none" starts fresh; a Checkpoint UUID seeds from that specific Checkpoint

Response: Session object

{
  "id": "uuid",
  "repo_id": "uuid or null",
  "title": "Session Mar 21 14:30",
  "active_provider": "openrouter",
  "active_model": "anthropic/claude-3.5-sonnet",
  "seeded_commit_id": "uuid or null",
  "created_at": "2026-03-21T14:30:00Z",
  "updated_at": "2026-03-21T14:30:00Z"
}

List recent sessions

GET /api/v4/chat/sessions

Returns the 50 most recently updated Sessions, ordered by updated_at descending.

Response: Array of Session objects


Get a session

GET /api/v4/chat/sessions/{session_id}

Response: Session object


Generate a session title

POST /api/v4/chat/sessions/{session_id}/title

Uses the background intelligence model to generate a concise 35 word title from the first four Turns of the Session. Updates session.title in place.

Called automatically by the frontend after the first assistant reply (if a background provider is configured).

Response: Updated Session object


List session turns

GET /api/v4/chat/sessions/{session_id}/turns

Returns all Turns for a Session, ordered by sequence_number ascending.

Response: Array of Turn objects

[
  {
    "id": "uuid",
    "session_id": "uuid",
    "role": "user",
    "content": "What countries should I visit?",
    "provider": "openrouter",
    "model": "anthropic/claude-3.5-sonnet",
    "sequence_number": 0,
    "created_at": "2026-03-21T14:31:00Z"
  },
  {
    "id": "uuid",
    "session_id": "uuid",
    "role": "assistant",
    "content": "...",
    "provider": "openrouter",
    "model": "anthropic/claude-3.5-sonnet",
    "sequence_number": 1,
    "created_at": "2026-03-21T14:31:05Z"
  }
]

Attach a session to a space

PUT /api/v4/chat/sessions/{session_id}/attach

Attaches an existing Session to a Space. Updates session.repo_id and sets repo_id on all existing Turns in the Session.

Request body:

{
  "repo_id": "<space-uuid>"
}

Response: Updated Session object


Sending messages

Send a message

POST /api/v4/chat/send

The core endpoint. Sends a user message, resolves the context based on the active mode, calls the provider, and stores both the user Turn and assistant Turn.

Request body:

{
  "session_id": "<session-uuid>",
  "repo_id": "<space-uuid>",
  "provider": "openai",
  "model": "gpt-4o",
  "message": "What should I do first?",
  "use_mock": false,
  "memory_scope": "latest_1",
  "mounted_checkpoint_id": null,
  "history_base_seq": null
}
Field Type Required Description
session_id UUID string Yes The active Session
repo_id UUID string No The attached Space. Must match session.repo_id.
provider string Yes Provider to use for this Turn
model string Yes Model identifier
message string Yes The user's message
use_mock boolean No Use the deterministic mock adapter (no API key required)
memory_scope string No "latest_1" (default) or "latest_3"
mounted_checkpoint_id UUID string No If set, anchors context to this specific Checkpoint
history_base_seq integer No Required when mounted_checkpoint_id is set. The sequence number of the last Turn before mounting. Only Turns with sequence_number > history_base_seq are included in context.

Context resolution logic:

  1. If mounted_checkpoint_id is set: use that Checkpoint (plus ancestors if memory_scope is "latest_3"). Turn history: sequence_number > history_base_seq.
  2. If repo_id is set (HEAD mode): use the N most recent Checkpoints from the Space. Turn history: created_at >= latest_checkpoint.created_at.
  3. Otherwise (FRESH): no Checkpoint context. No Turn history filter.

Response:

{
  "reply": "Here is what I recommend...",
  "session_id": "uuid",
  "turn_count": 4,
  "provider": "openai",
  "model": "gpt-4o"
}

Spaces

List spaces

GET /api/v2/repos

Note: Spaces use the V2 prefix. The user-facing name is "Space"; the internal model is RepoModel.

Response: Array of Space objects

[
  {
    "id": "uuid",
    "name": "Australia Trip",
    "description": "Planning for the 2026 trip",
    "created_at": "2026-03-01T10:00:00Z",
    "updated_at": "2026-03-21T14:30:00Z"
  }
]

Create a space

POST /api/v2/repos

Request body:

{
  "name": "Australia Trip",
  "description": "Planning for the 2026 trip"
}

Response: Space object

Get a space

GET /api/v2/repos/{repo_id}

Response: Space object

Delete a space

DELETE /api/v2/repos/{repo_id}

Deletes a Space and cascades to every Checkpoint, Session, and Turn under it. Irreversible.

Query parameters:

  • force (boolean, default false) — required to delete a Space that still holds checkpoints.

Responses:

  • 204 No Content — Space deleted (empty Space, or force=true on a populated Space).

  • 404 Not Found — Space does not exist (or belongs to a different user).

  • 409 Conflict — Space holds checkpoints and force=true was not passed. The response body carries a structured detail explaining the refusal:

    {
      "detail": {
        "message": "Cannot delete space 'Australia Trip': it still holds 12 checkpoint(s). Deletion cascades to every checkpoint, session, and turn under it and cannot be undone. Re-send with ?force=true to delete the space and all its contents.",
        "checkpoint_count": 12,
        "requires_force": true
      }
    }
    

The 409 guard is one of three deletion-safety layers — the CLI's --force flag and the MCP smriti_delete_space tool's confirm_space argument are the other two. Every client (direct curl, the web UI, a future client) goes through this server-side rule.

Get space head state (main-only)

GET /api/v4/chat/spaces/{repo_id}/head

Returns the latest main-branch Checkpoint and latest Session for a Space. This is the legacy single-HEAD endpoint — for multi-agent workflows, prefer /state below.

Response:

{
  "repo_id": "uuid",
  "commit_hash": "abc1234...",
  "commit_id": "uuid",
  "summary": "Decided to focus on east coast cities",
  "objective": "Plan a 3-week Australia itinerary",
  "latest_session_id": "uuid",
  "latest_session_title": "Australia Trip Planning"
}

Get space state (multi-branch, default)

GET /api/v4/chat/spaces/{repo_id}/state

The agent-facing default. Returns the main-branch continuation brief plus active non-main branches, active work claims, and a divergence signal when any branch disagrees with main on decisions. One round trip, atomic snapshot.

Response:

{
  "space": {
    "id": "uuid",
    "name": "my-project",
    "description": "..."
  },
  "head": { "...same shape as /head..." },
  "commit": { "...full main-branch HEAD checkpoint..." },
  "active_branches": [
    {
      "branch_name": "experiment-a",
      "commit_id": "uuid",
      "commit_hash": "abc1234...",
      "message": "Trying alternative approach",
      "author_agent": "codex-local",
      "created_at": "...",
      "summary": "..."
    }
  ],
  "active_claims": [
    {
      "id": "uuid",
      "agent": "claude-code",
      "branch_name": "main",
      "scope": "Adding lineage test",
      "intent_type": "implement",
      "claimed_at": "...",
      "expires_at": "...",
      "base_commit_hash": "abc1234"
    }
  ],
  "divergence": {
    "pairs": [
      {
        "branch_name": "experiment-a",
        "branch_commit_hash": "def5678",
        "main_only_decisions": ["Use Pydantic"],
        "branch_only_decisions": ["Use dataclasses"]
      }
    ]
  }
}

active_branches is capped at 5 (most recent by created_at). divergence.pairs is capped at 2. Per-branch divergence is capped at 3 decisions per side. active_claims shows only active, non-expired claims. All three sections are omitted from the response when empty.


Provider status

List provider status

GET /api/v4/chat/providers

Returns the configuration status of all providers. Never returns API keys.

Response:

{
  "openai": {
    "enabled": true,
    "has_key": true,
    "missing_package": false,
    "configured": true,
    "status_label": "Ready",
    "default_model": "gpt-4o"
  },
  "anthropic": {
    "enabled": false,
    "has_key": false,
    "missing_package": false,
    "configured": false,
    "status_label": "Disabled",
    "default_model": ""
  },
  "openrouter": {
    "enabled": true,
    "has_key": true,
    "missing_package": false,
    "configured": true,
    "status_label": "Ready",
    "default_model": ""
  },
  "background_intelligence": {
    "provider": "openai",
    "model": "gpt-4o-mini",
    "enabled": true,
    "has_key": true,
    "configured": true,
    "status_label": "Ready"
  }
}

V5 — Checkpoint API

Prefix: /api/v5/checkpoint

The V5 API handles checkpoint drafting — the AI-assisted extraction of structured state from a conversation.


Draft a checkpoint

POST /api/v5/checkpoint/draft

Uses the background intelligence model to extract structured metadata from the active conversation. Returns a draft that the user can review, edit, and save.

Important: This endpoint respects the same context isolation as send_message. If mounted_checkpoint_id and history_base_seq are provided, the draft is extracted only from Turns after the isolation boundary — the same Turns the model saw during the session.

Request body:

{
  "session_id": "<session-uuid>",
  "num_turns": 15,
  "mounted_checkpoint_id": null,
  "history_base_seq": null
}
Field Type Required Description
session_id UUID string Yes The Session to draft from
num_turns integer No Maximum number of recent Turns to include (default 15, max 100)
mounted_checkpoint_id UUID string No If set, applies isolation boundary
history_base_seq integer No Required when mounted_checkpoint_id is set

Turn selection:

  • If mounted_checkpoint_id and history_base_seq are both provided: sequence_number > history_base_seq, limited to num_turns most recent
  • Otherwise: all Turns in the Session, limited to num_turns most recent

No previous Checkpoint context is injected into the extraction prompt. The draft reflects only what is present in the selected Turns.

Response:

{
  "title": "Australia East Coast Plan",
  "objective": "Decide on a 3-week itinerary for Australia focusing on the east coast",
  "summary": "The user is planning a trip to Australia and has narrowed focus to Sydney, Melbourne, and the Great Barrier Reef. Budget and timing constraints have been discussed.",
  "decisions": [
    "Focus on east coast cities only",
    "Avoid peak season (DecemberJanuary)"
  ],
  "tasks": [
    "Research visa requirements",
    "Compare flight options from London"
  ],
  "open_questions": [
    "Whether to include Tasmania",
    "How many nights to allocate to each city"
  ],
  "entities": [
    "Sydney",
    "Melbourne",
    "Great Barrier Reef",
    "Qantas"
  ],
  "assumptions": [
    "Budget is flexible",
    "Traveling from London"
  ]
}

All array fields may be empty if nothing relevant was found in the conversation. objective may be an empty string if the goal is not stated clearly enough to extract. assumptions captures things the conversation takes for granted that were not explicitly debated or decided.


Review a checkpoint

POST /api/v5/checkpoint/{checkpoint_id}/review

Uses the background intelligence model to review a checkpoint for reasoning consistency. Returns a list of issues and suggestions.

Issue types (V1):

Type Description
contradiction Two decisions or an assumption and a decision that appear to conflict
hidden_assumption Something the reasoning relies on that is not listed as an assumption or decision
resolved_question An open question that appears already answered by a decision or the summary
unused_entity An entity not referenced in the summary, decisions, tasks, or objective

Response:

{
  "checkpoint_id": "uuid",
  "issues": [
    {
      "type": "hidden_assumption",
      "description": "The itinerary assumes travel logistics between cities can be easily managed within the 10-day timeframe"
    }
  ],
  "suggestions": [
    "Consider adding travel logistics as an explicit assumption"
  ]
}

Issues are capped at 5 per review. The review is conservative and prefers precision over recall.


Saving a checkpoint

Checkpoints are saved via the V4 commit endpoint, not V5.

POST /api/v4/chat/commit

Request body:

{
  "repo_id": "<space-uuid>",
  "session_id": "<session-uuid>",
  "message": "Australia East Coast Plan",
  "summary": "Decided to focus on east coast...",
  "objective": "Plan a 3-week itinerary...",
  "decisions": ["Focus on east coast cities only"],
  "assumptions": ["Budget is flexible"],
  "tasks": ["Research visa requirements"],
  "open_questions": ["Whether to include Tasmania"],
  "entities": ["Sydney", "Melbourne"],
  "artifacts": [
    {
      "id": "a1b2c3d4",
      "type": "text",
      "label": "Draft itinerary",
      "content": "Day 1: Arrive in Sydney..."
    }
  ],
  "repo_state": {
    "head": "abc123def456...",
    "head_short": "abc123d",
    "branch": "main"
  }
}

Response:

{
  "id": "uuid",
  "commit_hash": "abc1234def5678...",
  "message": "Australia East Coast Plan",
  "created_at": "2026-03-21T15:00:00Z"
}

Repo-state drift detection (repo_state). The optional repo_state field records the git HEAD and branch of the repo the checkpoint was created from. It is persisted under the commit's context_blob and returned by GET /api/v4/chat/spaces/{repo_id}/state as commit.context_blob.repo_state. The CLI uses it on subsequent smriti state calls to detect drift — N commits ahead of the recorded checkpoint, a different branch, or diverged history — and surfaces those signals in the rendered state brief's ## Repo state section. The field is optional: clients that cannot inspect a repo (e.g. the MCP server, which runs in the host's arbitrary working directory) may omit it, and the backend stores an empty context_blob.


Checkpoint history

List checkpoints for a space

GET /api/v2/repos/{repo_id}/commits

Returns all Checkpoints for a Space, ordered by creation time.

Response: Array of Checkpoint objects

[
  {
    "id": "uuid",
    "commit_hash": "abc1234...",
    "parent_commit_id": "uuid or null",
    "message": "Australia East Coast Plan",
    "objective": "Plan a 3-week itinerary...",
    "summary": "Decided to focus on east coast...",
    "decisions": ["Focus on east coast cities only"],
    "assumptions": ["Budget is flexible"],
    "tasks": ["Research visa requirements"],
    "open_questions": ["Whether to include Tasmania"],
    "entities": ["Sydney", "Melbourne"],
    "artifacts": [],
    "created_at": "2026-03-21T15:00:00Z"
  }
]

Get a specific checkpoint

GET /api/v2/commits/{commit_id}

Response: Checkpoint object (full fields as above)



V5 — Lineage API

Prefix: /api/v5/lineage

The Lineage API handles session forking, branch tree visualization, and checkpoint comparison across branches.


Fork a session

POST /api/v5/lineage/sessions/fork

Creates a new Session branching from a specific Checkpoint. The forked session starts with a clean Turn history; its context comes from the checkpoint state snapshot.

Request body:

{
  "space_id": "<space-uuid>",
  "checkpoint_id": "<checkpoint-uuid>",
  "branch_name": "my-branch",
  "provider": "openai",
  "model": "gpt-4o"
}
Field Type Required Description
space_id UUID string Yes The Space to fork within
checkpoint_id UUID string Yes The Checkpoint to fork from
branch_name string No Branch name. Defaults to "branch-YYYY-MM-DD"
provider string No Defaults to config default
model string No Model for the new session

Response:

{
  "session_id": "uuid",
  "branch_name": "my-branch",
  "forked_from_checkpoint_id": "uuid",
  "history_base_seq": 0
}

Get branch tree

GET /api/v5/lineage/spaces/{space_id}

Returns all Checkpoints and Sessions for a Space, structured for branch tree rendering. Checkpoints carry parent_checkpoint_id for the commit ancestry chain; Sessions carry forked_from_checkpoint_id to locate where each branch began.

Response:

{
  "space_id": "uuid",
  "checkpoints": [
    {
      "id": "uuid",
      "commit_hash": "abc1234...",
      "message": "Australia East Coast Plan",
      "branch_name": "main",
      "parent_checkpoint_id": "uuid or null",
      "created_at": "...",
      "summary": "...",
      "objective": "..."
    }
  ],
  "sessions": [
    {
      "id": "uuid",
      "title": "Session Mar 21",
      "branch_name": "main",
      "forked_from_checkpoint_id": "uuid or null",
      "seeded_commit_id": "uuid or null",
      "created_at": "..."
    }
  ]
}

Compare two checkpoints

GET /api/v5/lineage/checkpoints/{a_id}/compare/{b_id}

Returns a structured diff of two Checkpoint state snapshots. Works across any two Checkpoints regardless of branch origin.

Response:

{
  "checkpoint_a": {
    "id": "uuid",
    "commit_hash": "abc1234...",
    "message": "...",
    "branch_name": "main",
    "summary": "...",
    "objective": "...",
    "decisions": ["..."],
    "tasks": ["..."],
    "open_questions": ["..."]
  },
  "checkpoint_b": { ... },
  "diff": {
    "summary_a": "...",
    "summary_b": "...",
    "objective_a": "...",
    "objective_b": "...",
    "decisions_only_a": ["..."],
    "decisions_only_b": ["..."],
    "decisions_shared": ["..."],
    "tasks_only_a": ["..."],
    "tasks_only_b": ["..."],
    "tasks_shared": ["..."]
  }
}

Get reachable checkpoints for a session

GET /api/v5/lineage/sessions/{session_id}/checkpoints

Returns the Checkpoint set reachable from a given Session. This is the authoritative query for populating the checkpoint history panel and mount-candidate list.

Reachability rules:

  • Main-branch session — all Checkpoints where branch_name == "main", newest first.
  • Forked session — fork-local Checkpoints (same branch) plus the fork-source Checkpoint and all its ancestors. Downstream main Checkpoints created after the fork point are explicitly excluded.

Response: Array of full Checkpoint objects (same schema as GET /api/v2/commits/{id})


V5 — Work Claims API

Prefix: /api/v5/claims

Work claims are lightweight, time-bounded declarations that an agent is actively working on something in a space. They make pre-work intent visible to other agents before work produces a checkpoint. Claims are advisory — not locks.


Create a work claim

POST /api/v5/claims

Request body:

{
  "space_id": "<space-uuid>",
  "agent": "claude-code",
  "scope": "Adding lineage test for author_agent",
  "branch_name": "main",
  "base_commit_id": "<checkpoint-uuid>",
  "intent_type": "implement",
  "ttl_hours": 4.0
}
Field Type Required Description
space_id UUID string Yes The Space to claim work in
agent string Yes Agent identifier (e.g. claude-code, codex-local)
scope string Yes One sentence describing the work
branch_name string No Branch the work targets. Default "main"
base_commit_id UUID string No The Checkpoint the agent read as HEAD
intent_type string No One of: implement, review, investigate, docs, test. Default "implement"
ttl_hours float No Hours until the claim expires. Default 4.0

Response: Claim object (status "active", claimed_at and expires_at set)


Update a claim

PATCH /api/v5/claims/{claim_id}

Marks a claim as done or abandoned. Only active claims can be updated.

Request body:

{
  "status": "done"
}
Value Meaning
done Work completed successfully
abandoned Work intentionally stopped

Response: Updated Claim object

Returns 409 if the claim is already done or abandoned.


List claims

GET /api/v5/claims?space_id=<uuid>

Returns active, non-expired claims for a space. Pass include_expired=true to include done, abandoned, and expired claims.

Response: Array of Claim objects


Error responses

All endpoints return errors in this format:

{
  "detail": "Session not found"
}
Status Meaning
400 Bad request — missing required field or invalid input
404 Resource not found
422 Validation error — request body did not match schema
500 Server error — typically a misconfigured or missing background provider
502 Provider error — the upstream LLM returned an error or invalid response

Notes on V1, V2, V4, V5

/api/v1 — Transcript paste ingestion. Accepts raw text, extracts memories, generates context packs. Not used by the current UI or CLI. Retained for compatibility but no new development happens here. Do not build new integrations against V1.

/api/v2 — Space CRUD and Checkpoint read endpoints. The CLI reads full checkpoints via GET /api/v2/commits/{commit_id} and lists per-space checkpoints via GET /api/v2/repos/{repo_id}/commits. The CommitResponse schema returns the complete checkpoint shape including assumptions and artifacts. New programmatic clients are welcome to use V2 read endpoints; for writes, use V4 (POST /api/v4/chat/commit) which accepts the full schema.

/api/v4 — Chat sessions, message sending, and the canonical checkpoint write path. The chat UI's primary interaction surface and the CLI's write surface.

/api/v5 — Checkpoint drafting, review, fork, compare, lineage, and work claims. Used by both the chat UI and the CLI/MCP server.