MCP Server
The SessionFS MCP server gives AI coding agents access to your session history and project knowledge base during conversations. Agents can search past sessions, read project context, and contribute knowledge back — building a shared memory that persists across tools and teammates.
Transports: stdio for local use (agent launches sfs mcp serve as a subprocess). Remote use over HTTP/SSE is not currently supported (see Remote MCP).
Installation
Section titled “Installation”Run sfs mcp install --for <tool> to register the MCP server with your AI tool. This registers the server in the tool’s MCP configuration and injects knowledge-contribution instructions into the tool’s project config file (e.g., CLAUDE.md, .cursorrules).
Supported tools:
sfs mcp install --for claude-code # ~/.claude.jsonsfs mcp install --for cursor # ~/.cursor/mcp.jsonsfs mcp install --for codex # via codex mcp addsfs mcp install --for gemini # via gemini mcp addsfs mcp install --for copilot # ~/.copilot/config.jsonsfs mcp install --for amp # ~/.amp/config.jsonsfs mcp install --for cline # VS Code globalStoragesfs mcp install --for roo-code # VS Code globalStoragesfs mcp install --for kilo-code # VS Code globalStoragesfs mcp install --for antigravity # ~/.gemini/config/mcp_config.json (+ legacy ~/.gemini/antigravity/mcp_config.json)To skip the instruction injection (server registration only):
sfs mcp install --for claude-code --skip-instructionsThe MCP server exposes 145 tools in twenty-one categories: Session, Knowledge Read, Knowledge Write, Rules, Personas, Tickets, AgentRun, Agent Feedback, Review Checklist, Handoffs (Pro+ for direct, Team+ for team handoffs), Work Queues, Review Loops, Workflow Templates, Skills Marketplace, Project Groups (Team+), Meetings and chat, Reminders, Approvals (Enterprise), External contacts, For You, and Evaluations and Lineage (Team+ for writes).
The git_remote parameter. Project-scoped tools take an optional git_remote that picks the project. Pass a remote URL such as github.com/org/repo, or a local folder: a value starting with /, ~, ./ or ../ (or . / ..) is resolved through that repository’s origin remote, git worktrees included. A folder that isn’t a git repository with an origin returns an error rather than acting on another project. Omit git_remote to use the current workspace.
Session Tools
Section titled “Session Tools”search_sessions
Section titled “search_sessions”Search past AI coding sessions by keyword, error message, or file path.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | yes | Keywords, error messages, or file paths to search for |
tool_filter |
string | no | Filter by source tool (claude-code, codex, gemini, cursor, copilot, amp, cline, roo-code, kilo-code, antigravity) |
max_results |
number | no | Maximum results to return (default: 5) |
get_session_context
Section titled “get_session_context”Retrieve the full conversation from a specific session. Use after search_sessions finds a relevant hit.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID in ses_... format |
max_messages |
number | no | Limit messages returned (default: 50) |
summary_only |
boolean | no | Return metadata only, no messages (default: false) |
audit_session_id |
string | no | Current session id to append this retrieval to its audit log |
list_recent_sessions
Section titled “list_recent_sessions”List recent sessions with optional filtering.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
number | no | Max sessions to return (default: 10) |
tool_filter |
string | no | Filter by source tool |
project_filter |
string | no | Filter by project/workspace path substring |
find_related_sessions
Section titled “find_related_sessions”Find sessions that touched a specific file or encountered a similar error. Provide file_path or error_text (at least one).
| Parameter | Type | Required | Description |
|---|---|---|---|
file_path |
string | no | Find sessions that modified this file |
error_text |
string | no | Find sessions with similar errors |
limit |
number | no | Max results (default: 5) |
audit_session_id |
string | no | Current session id to append this retrieval to its audit log |
get_session_summary
Section titled “get_session_summary”Get a structured summary — files modified, commands run, tests executed, errors encountered, packages installed.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID in ses_... format |
get_audit_report
Section titled “get_audit_report”Get the LLM Judge trust audit — verifiable claims, verdicts (verified/unverified/hallucination), confidence scores, CWE mappings.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID in ses_... format |
get_session_provenance
Section titled “get_session_provenance”Return the instruction provenance recorded for a session — what rules and artifacts shaped the agent at capture time. Returns rules_version, rules_hash, rules_source (sessionfs / manual / mixed / none), and the instruction_artifacts list.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID in ses_... format |
get_session_retrieval_log
Section titled “get_session_retrieval_log”Return the retrieval audit log for a session. When start_ticket creates a server-side retrieval_audit_id, MCP retrieval tools append durable events to the SessionFS API; offline clients fall back to local JSONL when callers pass audit_session_id or set SESSIONFS_SESSION_ID / SFS_SESSION_ID. Each row records the tool name, arguments, timestamp, and returned IDs/slugs.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID whose retrieval log should be returned |
ask_session_helper
Section titled “ask_session_helper”Ask the session helper a question over sessions and project knowledge you can already read (Enterprise plan + a configured LLM key). Returns a non-streaming answer plus a citations list — [{session_id, message_index, title}]. Use instead of shelling out to sfs helper ask.
| Parameter | Type | Required | Description |
|---|---|---|---|
question |
string | yes | The question to ask over your sessions and project knowledge |
project |
string | no | Project ID (proj_...) to scope the question to |
group_id |
string | no | Project group ID (pg_...) to scope the question to. The helper reads only the group’s member projects that you can already read. Use at most one of project, group_id and session_ids (v0.28.0) |
session_ids |
array | no | Session IDs (ses_...) to scope the question to |
conversation_id |
string | no | Conversation ID (hc_...) to continue an existing helper thread |
rename_session
Section titled “rename_session”Rename a captured session’s title and/or alias. Only the session’s owner can rename it. Pass at least one of new_title or new_alias; an empty new_alias clears the alias. Setting an alias needs Starter or above; title edits work on every plan.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session ID (ses_...) or alias |
new_title |
string | no | New title (up to 500 characters) |
new_alias |
string | no | New alias (3–100 characters: letters, digits, hyphens, underscores; starts with a letter or digit). Empty string clears it |
Knowledge Read
Section titled “Knowledge Read”get_project_context
Section titled “get_project_context”Get the shared project context document — architecture decisions, conventions, wiki pages, and recent knowledge entries. Call early in a session to understand the project. Use get_context_section or get_wiki_page instead when you only need one slice — they return less and cost less.
| Parameter | Type | Required | Description |
|---|---|---|---|
git_remote |
string | no | Git remote URL (auto-detected from working directory if omitted) |
get_context_section
Section titled “get_context_section”Return one section of the project context document by slug instead of the full document. If the slug is not found, the response lists the available slugs so you can retry.
| Parameter | Type | Required | Description |
|---|---|---|---|
slug |
string | yes | Section slug (lowercase, non-alphanumeric collapsed to _) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
audit_session_id |
string | no | Current session id to append this retrieval to its audit log |
get_wiki_page
Section titled “get_wiki_page”Read one wiki page’s full content plus backlinks. Cheaper than get_project_context when you already know the page slug.
| Parameter | Type | Required | Description |
|---|---|---|---|
slug |
string | yes | Wiki page slug (e.g., architecture) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
audit_session_id |
string | no | Current session id to append this retrieval to its audit log |
get_wiki_page_history
Section titled “get_wiki_page_history”Return the revision history for a wiki page. Each revision carries revision_number, revised_at, the editing user_id, optional persona_name and ticket_id, and a content snapshot. Cursor-paginated for long histories.
| Parameter | Type | Required | Description |
|---|---|---|---|
slug |
string | yes | Wiki page slug |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
cursor |
string | no | Opaque pagination cursor returned as next_cursor from the previous call |
limit |
number | no | Page size (default: 25) |
search_project_knowledge
Section titled “search_project_knowledge”Search across knowledge entries and wiki pages by keyword. Use this when you have a query string. Use list_knowledge_entries instead when you want a filtered list with no query.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | yes | What to search for |
entry_type |
string | no | Filter by type: decision, pattern, discovery, convention, bug, dependency |
limit |
number | no | Maximum results (default: 10) |
audit_session_id |
string | no | Current session id to append this retrieval to its audit log |
list_knowledge_entries
Section titled “list_knowledge_entries”Filtered list of knowledge entries with pagination. Useful when you want to browse by type, claim class, freshness, or origin session without a search query.
| Parameter | Type | Required | Description |
|---|---|---|---|
entry_type |
string | no | One of decision, pattern, discovery, convention, bug, dependency |
claim_class |
string | no | evidence, claim, or note |
freshness_class |
string | no | current, aging, stale, or superseded |
dismissed |
boolean | no | Include dismissed entries (default: false) |
session_id |
string | no | Only entries linked to this session |
sort |
string | no | created_at_desc (default), last_relevant_at_desc, confidence_desc |
page |
number | no | 1-based page number (default: 1) |
limit |
number | no | Page size, max 200 (default: 50) |
get_knowledge_entry
Section titled “get_knowledge_entry”Return one knowledge entry’s full record, including last_relevant_at for stale review.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
number | yes | Knowledge entry ID |
get_knowledge_health
Section titled “get_knowledge_health”One call for the dashboard banner data — counts and recommended next actions. Each count mirrors a precise compile-pipeline filter so MCP agents read the same contract the route enforces:
pending_entries— uncompiled claims the next compile will process. Filter:claim_class='claim'ANDcompiled_at IS NULLAND not dismissed ANDfreshness_class IN ('current', 'aging')ANDsuperseded_by IS NULL.auto_promotable_evidence(v0.10.17+) — evidence rows the compiler’s auto-promotion phase will promote AND that survive the post-promotion claim filter. Filter:claim_class='evidence'ANDconfidence >= 0.5ANDlength(content) >= 30AND not dismissed ANDcompiled_at IS NULLAND current/aging AND no superseder.uncompiled_notes(v0.10.17+) — notes that need abulk_promotecall before they can compile.compiled_entries,dismissed_entries,total_entries— straightforward counts.stale_entries,low_confidence_entries,potentially_stale— review surfaces.potentially_staleuses the same compile-eligible predicate aspending_entries(notes / superseded claims with novel terms can’t trigger a false-positive “Context may be stale” warning).word_count— current compiled context size.recommendations— strings driven bycompile_work_total = pending_entries + auto_promotable_evidence. Notes-only fresh projects get “No compile-eligible entries yet — add claims (or promote evidence) before running compile” instead of a “compile to build context” pointer.
No parameters required.
ask_project
Section titled “ask_project”Ask a question about the project. Gathers project context, searches the knowledge base, and finds related local sessions to assemble research material. Returns the assembled markdown plus a typed sources_cited list — [{type: "kb"|"session", id}] — resolved from a structured re-fetch of KB IDs and the local session search index, never regex-extracted from prose.
| Parameter | Type | Required | Description |
|---|---|---|---|
question |
string | yes | A question about the project |
Knowledge Write
Section titled “Knowledge Write”add_knowledge
Section titled “add_knowledge”Add a knowledge entry to the project knowledge base. Use when you discover patterns, decisions, conventions, bugs, or dependencies.
| Parameter | Type | Required | Description |
|---|---|---|---|
content |
string | yes | The knowledge entry text |
entry_type |
string | yes | One of: decision, pattern, discovery, convention, bug, dependency |
session_id |
string | no | Link this entry to a specific session |
confidence |
number | no | Confidence score 0.0–1.0 (default: 1.0) |
update_wiki_page
Section titled “update_wiki_page”Create or update a wiki page in the project knowledge base. Use for longer-form documentation of architecture, conventions, or concepts.
| Parameter | Type | Required | Description |
|---|---|---|---|
slug |
string | yes | URL-safe page identifier (e.g., architecture) |
content |
string | yes | Full page content in markdown |
title |
string | no | Page title (derived from slug if omitted) |
list_wiki_pages
Section titled “list_wiki_pages”List all wiki pages for the project. Returns page slugs, titles, word counts, and entry counts. No parameters required.
compile_knowledge_base
Section titled “compile_knowledge_base”Trigger a compile pass on the project’s knowledge base. Promotes pending entries, refreshes section pages and concept pages, and rebuilds the compiled context document. Returns a structured result: entries_compiled, context_words_before, context_words_after, section_pages_updated, concept_pages_updated, compiled_at.
No parameters required.
dismiss_knowledge_entry
Section titled “dismiss_knowledge_entry”Dismiss a knowledge entry that is stale, wrong, or no longer relevant. Idempotent — calling twice is a safe no-op. Writes a full audit triple (dismissed_at, dismissed_by, dismissed_reason) and the underlying PUT /entries/{id} is row-locked with SELECT FOR UPDATE so concurrent dismissals can’t tear the audit record.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
number | yes | Knowledge entry ID |
reason |
string | yes | Short justification (e.g., "superseded by entry 412" or "wrong file path") |
update_entry_confidence
Section titled “update_entry_confidence”Set a knowledge entry’s confidence (0.0–1.0). It doesn’t promote the entry: once confidence is above the 0.8 promotion gate, call promote_entry.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
number | yes | Knowledge entry ID |
confidence |
number | yes | New confidence, 0.0–1.0 |
promote_entry
Section titled “promote_entry”Promote a knowledge entry from note to claim when it passes the quality gates: confidence of at least 0.8, at least 50 characters, and no near-duplicate (more than 85% word overlap) of an active claim. A failure returns 422 naming the gates that didn’t pass. Only claims reach the compiled project context.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
number | yes | Knowledge entry ID |
promote_eligible_entries
Section titled “promote_eligible_entries”Promote every eligible note in the project in one call. Dry-run by default: the result lists what would be promoted and why the rest was skipped (too_short, low_confidence, duplicate, dismissed, superseded, wrong_type). Notes written by people who can view but not edit the project are only counted (reader_notes_excluded) unless include_reader_notes is true. Run compile_knowledge_base afterwards.
| Parameter | Type | Required | Description |
|---|---|---|---|
dry_run |
boolean | no | Default true; pass false to promote |
min_length |
number | no | Minimum content length (default 50) |
min_confidence |
number | no | Minimum confidence (default 0.8); ignored when set_confidence is given |
set_confidence |
number | no | Set each candidate’s confidence to this value before checking |
entry_type |
string | no | Only consider this entry type |
include_reader_notes |
boolean | no | Also consider notes from people who can only view the project |
Rules (Read-only)
Section titled “Rules (Read-only)”get_rules
Section titled “get_rules”Returns the canonical project rules record plus compilation config for the current repo (static preferences, enabled tools, knowledge / context injection settings, tool overrides). Agents cannot modify rules through MCP — changes must go through sfs rules edit or the dashboard.
| Parameter | Type | Required | Description |
|---|---|---|---|
git_remote |
string | no | Override auto-detected git remote |
get_compiled_rules
Section titled “get_compiled_rules”Returns the compiled rule text for a requested tool, or for the current tool if safely inferable. Useful when an agent needs to understand what behavior contract was materialized for its tool.
| Parameter | Type | Required | Description |
|---|---|---|---|
tool |
string | no | Tool slug: claude-code, codex, cursor, copilot, gemini |
git_remote |
string | no | Override auto-detected git remote |
audit_session_id |
string | no | Current session id to append this retrieval to its audit log |
Personas
Section titled “Personas”Tier-gated by the agent_personas feature flag. Personas are portable AI roles — each persona has a name (^[A-Za-z0-9_-]{1,50}$) and markdown content, and belongs to one project or to one organization. Org-level personas are usable from every project in the org. Inside a project, a name resolves to the project’s own persona first, then the org’s, so a project persona with the same name overrides the org one. get_persona, assign_persona, start_ticket, and agent runs all resolve this way. Names match case-insensitively. Org personas are visible only to current members of the project’s current org (and that org’s service keys); other callers with project access see project personas only.
list_personas
Section titled “list_personas”List the personas usable in the current project. Each row carries scope (project or org); an org persona overridden by a project persona of the same name is left out.
| Parameter | Type | Required | Description |
|---|---|---|---|
include_org |
boolean | no | Include the org’s personas (default true) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_persona
Section titled “get_persona”Return a single persona’s full content.
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Persona name |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
audit_session_id |
string | no | Current session id to append this retrieval to its audit log |
create_persona
Section titled “create_persona”Define a new persona for the project, or for an organization when org_id is passed. Names are case-insensitive-unique within the project (or within the org).
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | ASCII identifier, 1-50 chars |
role |
string | yes | Short role description (100 chars max) |
content |
string | no | Markdown body |
specializations |
string[] | no | Domain keywords |
org_id |
string | no | Create an org-level persona in this org (org admin or owner) |
represented_user |
string | no | With org_id: email or user id of the org member this persona represents. That member may then edit it |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
update_persona
Section titled “update_persona”Update a persona’s role, content, or specializations. Without org_id only the project’s own personas are matched; pass org_id to edit an org-level persona (org admin or owner). The member an org persona represents may also edit its role, content and specializations.
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Persona name (case-insensitive) |
role |
string | no | New role |
content |
string | no | New markdown body |
specializations |
string[] | no | Replacement list |
org_id |
string | no | Target an org-level persona |
represented_user |
string | no | With org_id, org admins (or org service keys) only: email or user id of the member the persona represents; an empty string clears it |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
delete_persona
Section titled “delete_persona”Soft-delete a persona. Refuses (409) while non-terminal tickets still need it unless force is true. For an org persona (org_id), the check covers every project in the org that has no same-named project persona.
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Persona name |
force |
boolean | no | Delete even if tickets reference it |
org_id |
string | no | Target an org-level persona |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
assume_persona
Section titled “assume_persona”Write a persona-only provenance bundle so the daemon tags subsequent captures with persona_name (and ticket_id=null).
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Persona name to assume |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
forget_persona
Section titled “forget_persona”Clear the active persona bundle. Refuses when a ticket-owned bundle is in effect — complete the ticket first.
No parameters required.
Tickets
Section titled “Tickets”Available on every plan (the agent_tickets feature). Tickets are self-contained units of work with a server-enforced FSM (suggested → open → in_progress → blocked → review → done | cancelled), dependency graph (BFS cycle detection), comments, and an active-ticket provenance bundle.
list_tickets
Section titled “list_tickets”Filter by status, assignee, or persona.
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
string | no | One of the FSM states |
assignee |
string | no | User ID |
persona |
string | no | Persona name |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_ticket
Section titled “get_ticket”Return a ticket’s full record, dependencies, dependents, and recent comments.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
create_ticket
Section titled “create_ticket”Open a new ticket. Agent-created tickets require ≥1 acceptance criterion + ≥20-char description; max 3 per session_id. Agent-source tickets land in suggested status — a human (or trusted agent) approves them with approve_ticket before they can be started.
| Parameter | Type | Required | Description |
|---|---|---|---|
title |
string | yes | Short summary |
description |
string | yes | Markdown body |
acceptance_criteria |
array | no | List of strings (required for agent source) |
depends_on |
array | no | List of ticket IDs |
persona |
string | no | Assign a persona |
assigned_user |
string | no | Assign directly to a teammate by email or user id; they get a “Your turn” notification. Can’t be combined with a persona (v0.27.0) |
due_date |
string | no | Due date as YYYY-MM-DD (v0.28.0) |
estimated_effort |
string | no | Estimate in Jira duration syntax, such as 3d, 2d 4h or 30m (v0.28.0) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
update_ticket
Section titled “update_ticket”Change a ticket’s title, description, acceptance criteria, context or file references, dependencies, priority, due date or estimate. Only the fields you pass change. Each update posts a diff comment on the ticket and records one audit row per changed field. Status changes go through the lifecycle tools and persona assignment through assign_persona; assigned_user assigns the ticket directly to a teammate. Only the ticket’s creator or a project admin can edit it; a project editor can change only the assignee (assigned_user, or null to unassign).
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
title |
string | no | New title |
description |
string | no | New Markdown body |
priority |
string | no | New priority |
acceptance_criteria |
array | no | Replacement list of criteria |
context_refs / file_refs |
array | no | Replacement reference lists |
depends_on |
array | no | Replacement list of ticket IDs |
assigned_user |
string or null | no | Teammate email or user id for direct-to-person assignment; null unassigns the person (v0.27.0) |
due_date |
string or null | no | Due date as YYYY-MM-DD; null clears it (v0.28.0) |
estimated_effort |
string or null | no | Jira-duration estimate such as 2d 4h; null clears it (v0.28.0) |
lease_epoch |
number | no | Optional fence from get_ticket; returns 409 if the ticket has moved on |
approve_ticket
Section titled “approve_ticket”Move a suggested ticket → open so it can be assigned and started. Returns 409 if the ticket is in any other state.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
start_ticket
Section titled “start_ticket”Atomic claim (UPDATE ... WHERE status='open' OR 'blocked' with rowcount guard). Increments and returns ticket.lease_epoch, creates a server-side retrieval_audit_id, writes both into the active-ticket bundle, and returns the compiled persona + ticket context (tool-aware token budget via tool).
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
tool |
string | no | claude-code (16k), codex/gemini/copilot/amp/antigravity/generic (8k), cursor/windsurf/cline/roo-code/kilo-code (4k) |
force |
boolean | no | Recover a blocked ticket; increments the lease epoch |
complete_ticket
Section titled “complete_ticket”Send a ticket from in_progress to review and clear the owned bundle. Pass lease_epoch to reject stale workers with 409.
Lease fencing is opt-in for backward compatibility. The CLI and MCP start_ticket path write the current epoch into the active-ticket bundle, so normal ticket workers are fenced automatically. Callers that omit lease_epoch are treated as legacy/single-worker clients; this is coordinated audit fencing, not a strict mutex unless callers pass the epoch.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
lease_epoch |
integer | no | Optional stale-worker fence from start_ticket |
resolve_ticket
Section titled “resolve_ticket”Move a ticket from review to done. Atomic with rowcount-1 guard. Pass lease_epoch to reject stale workers with 409.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
lease_epoch |
integer | no | Optional stale-worker fence from start_ticket |
assign_persona
Section titled “assign_persona”Set the persona on a ticket.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
persona |
string | yes | Persona name |
escalate_ticket
Section titled “escalate_ticket”Raise ticket priority and append a non-idempotent audit comment.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
reason |
string | yes | Why this is being escalated |
add_ticket_comment
Section titled “add_ticket_comment”Slack-like comment thread. Non-idempotent (each call creates a row). Passing lease_epoch atomically rejects stale-worker comments when another worker has restarted the ticket; omitting it is allowed for legacy callers and is unfenced.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
body |
string | yes | Markdown body |
as_persona |
string | no | Comment authored by this persona |
lease_epoch |
integer | no | Optional stale-worker fence from start_ticket |
watch_ticket
Section titled “watch_ticket”Follow or unfollow a ticket so you (and your agents) are notified when it changes hands or state. Creating a ticket, being assigned, commenting or posting a review verdict follows it automatically. Added in v0.24.0.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
unwatch |
boolean | no | Stop following (default false) |
muted |
boolean | no | Follow without receiving notifications (default false) |
git_remote |
string | no | Git remote URL like github.com/org/repo, or a local repo path. Omit to use the current workspace |
get_ticket_updates
Section titled “get_ticket_updates”Poll what changed on the tickets you follow since the last acknowledged cursor. Returns at most 100 updates and a next_cursor. Each persona keeps its own cursor, so several agents on one account each see every change once. Summaries are written by the server and never contain comment bodies. Added in v0.24.0.
| Parameter | Type | Required | Description |
|---|---|---|---|
persona_name |
string | no | Persona whose cursor to poll (defaults to the active ticket’s persona, else your own) |
ack |
boolean | no | Advance the cursor past the returned updates (default true); false peeks |
git_remote |
string | no | Git remote URL like github.com/org/repo, or a local repo path. Omit to use the current workspace |
Session checkpoint + fork
Section titled “Session checkpoint + fork”Local-only tools that operate on ~/.sessionfs. Use these to branch a session for “what-if” exploration or to mark a known-good state before risky changes. Neither tool uploads anything — call sfs push <new_id> afterwards if the fork should sync.
checkpoint_session
Section titled “checkpoint_session”Create a named snapshot of a session’s current manifest + messages under ~/.sessionfs/sessions/<id>.sfs/checkpoints/<name>/. Snapshot names must start with alphanumeric and use only [A-Za-z0-9._-] (1–100 chars). Re-using a name returns an error.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Full session id or unique prefix |
name |
string | yes | Checkpoint name |
list_checkpoints
Section titled “list_checkpoints”List checkpoints for a session, oldest first. Each entry returns name, created_at, message_count, and the on-disk path. Returns an empty list if there are no checkpoints.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Full session id or unique prefix |
fork_session
Section titled “fork_session”Fork a session (or one of its checkpoints) into a new independent session. The new manifest records parent_session_id and — when from_checkpoint is supplied — forked_from_checkpoint, so lineage is introspectable.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Source session id or unique prefix |
name |
string | yes | Title for the forked session |
from_checkpoint |
string | no | Fork from this snapshot instead of the live head |
Handoffs
Section titled “Handoffs”Handoffs are first-class coordination primitives. A handoff carries a session blob plus optional provenance (ticket_id + persona_name) and curated attachments (KB entries, wiki pages, ticket refs). On claim, the recipient’s CLI persists an active_ticket_payload so the next captured session is automatically tagged with the handed-off context.
Three recipient kinds, exactly one per handoff: recipient_email (any user by email), recipient_user_id (direct account match), or recipient_team_id (Team+ tier; any team member can claim with atomic race protection).
Non-parties get 404 (not 403) on all handoff routes — existence-hiding so recipients can’t distinguish pending vs claimed vs revoked. Pending handoffs past expires_at flip to expired on read; per-tier clamping is 720h (30d) on Free/Pro/Team, 2160h (90d) on Enterprise.
create_handoff
Section titled “create_handoff”Create a handoff for a session. Sender provides exactly one recipient field plus optional ticket/persona provenance, expiry, and attachments.
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | yes | Session being handed off |
recipient_email |
string | no | Recipient email (one-of) |
recipient_user_id |
string | no | Recipient user id (one-of) |
recipient_team_id |
string | no | Recipient team id (one-of, Team+ tier) |
message |
string | no | Optional sender note |
ticket_id |
string | no | Attach an active ticket for provenance carry-through |
persona_name |
string | no | Attach a persona for provenance carry-through |
expires_in_hours |
integer | no | Clamped per tier (720h Free/Pro/Team, 2160h Enterprise) |
attachments |
array | no | List of {kind: "kb_entry"|"wiki_page"|"ticket", ref_id} |
claim_handoff
Section titled “claim_handoff”Atomic claim. UPDATE Handoff WHERE id=X AND status='pending' runs first; race losers never write blobs. Returns the new session_id, active_ticket_payload (if attached), and dropped_attachments for refs the recipient can’t access.
| Parameter | Type | Required | Description |
|---|---|---|---|
handoff_id |
string | yes | Handoff ID |
get_handoff
Section titled “get_handoff”Fetch one handoff. Non-parties get 404. First non-sender read stamps viewed_at and emits a viewed event.
| Parameter | Type | Required | Description |
|---|---|---|---|
handoff_id |
string | yes | Handoff ID |
list_inbox_handoffs
Section titled “list_inbox_handoffs”List handoffs addressed to the caller (by email, user_id, or team membership). Optional status filter.
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
string | no | pending, claimed, revoked, declined, expired |
limit |
number | no | Page size |
list_sent_handoffs
Section titled “list_sent_handoffs”List handoffs created by the caller. Optional status filter.
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
string | no | Status filter |
limit |
number | no | Page size |
revoke_handoff
Section titled “revoke_handoff”Sender-only. Atomic revoke with a required reason. Emits revoked audit event and sends send_handoff_revoked email to the recipient.
| Parameter | Type | Required | Description |
|---|---|---|---|
handoff_id |
string | yes | Handoff ID |
reason |
string | yes | Required revoke reason |
decline_handoff
Section titled “decline_handoff”Recipient-only. Atomic decline with an optional reason. Emits declined audit event and sends send_handoff_declined email to the sender.
| Parameter | Type | Required | Description |
|---|---|---|---|
handoff_id |
string | yes | Handoff ID |
reason |
string | no | Optional decline reason |
add_handoff_comment
Section titled “add_handoff_comment”Append a comment to the handoff comment thread. Both parties (sender + valid recipients) can post; paged 200. Emits commented audit event and sends send_handoff_comment email to the other party.
| Parameter | Type | Required | Description |
|---|---|---|---|
handoff_id |
string | yes | Handoff ID |
body |
string | yes | Markdown body |
Ticket comments listing
Section titled “Ticket comments listing”list_ticket_comments
Section titled “list_ticket_comments”Paginated read of the existing GET /api/v1/projects/{id}/tickets/{id}/comments endpoint. Returns markdown body, author, persona, and timestamps so MCP clients don’t have to compose ticket-detail responses to inspect a comment thread.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
limit |
number | no | Page size (default: 50) |
cursor |
string | no | Opaque pagination cursor |
get_ticket_review_state
Section titled “get_ticket_review_state”A compact summary of a review ticket: open and closed findings, the last verdict, and open-finding counts by severity, derived from the comment thread. Cheaper than reading a long thread with list_ticket_comments. Returns review_state: null for tickets with no review comments. last_verdict_is_strict_verified_clean is true only when the last trusted verdict is a literal VERIFIED-CLEAN. “Last” means most recently posted: round numbers are labels, so a later changes-requested verdict reopens the review even if it carries a lower round number. Verdict headers take any reviewer name, in the form <Reviewer> R<n> review on <ticket>: <VERDICT>; see Worker Review Loop.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
check_merge_readiness
Section titled “check_merge_readiness”Whether a ticket’s work is safe to merge at a specific head commit. Returns {ready, reasons, verdict}. ready is true only when a trusted strict VERIFIED-CLEAN verdict exists, its reviewed_commit equals sha exactly, the reviewer’s identity differs from every implementer identity recorded for the ticket (with no implementer identity recorded, the answer is not ready), and no open finding is harmful. A finding tagged harm: none is harmless; an untagged finding of medium severity or higher counts as harmful. Pure read: a person still does the merge. CLI: sfs loop ready. See Worker Review Loop.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket ID |
sha |
string | yes | Head commit id (full 40- or 64-character lowercase hex) |
git_remote |
string | no | Project selector (see above) |
Work Queues
Section titled “Work Queues”Point an agent at a queue of tickets and wake it repeatedly — via /loop, cron, or CI — to service, review, and close them with SessionFS as the source of truth. The server holds all loop state, so the agent resumes correctly with no chat memory: each wake returns one bounded directive, and a crash between steps re-emits the same directive rather than losing or repeating work. Modes: review_until_clean (auto-finishes an item only on a server-verified, trusted, literal VERIFIED-CLEAN), implement_until_done, and triage. A built-in safety envelope (per-item attempt cap with 2m → 5m → 15m → 60m backoff that parks a stuck item for human reset, a per-wake ticket cap, a cadence floor, and a step rate limit) keeps an unattended loop bounded. These tools require the work_queues:read / work_queues:write scopes; acting on items also requires the relevant tickets / agent_runs write scopes. Available on all tiers. MCP / API only — there is no dashboard UI or CLI for work queues yet.
create_work_queue
Section titled “create_work_queue”Create a queue over a ticket filter or explicit ticket list, with a mode, a cadence, and per-run / per-item budgets.
get_work_queue
Section titled “get_work_queue”Return a queue’s configuration and progress.
list_work_queues
Section titled “list_work_queues”List the work queues for a project.
set_work_queue_status
Section titled “set_work_queue_status”Pause, resume, or archive a queue.
run_work_queue_step
Section titled “run_work_queue_step”Heartbeat: return one bounded directive (a single intent plus a small comment delta) for the agent to act on. Call this on each wake.
complete_work_queue_step
Section titled “complete_work_queue_step”Report the result of the directive returned by run_work_queue_step. This is the only call that durably advances the queue.
In review_until_clean mode the reviewer passes its verdict as verdict_content, and the server writes the trusted verdict comment itself. The first line must be a verdict header such as Claude R2 review on <ticket_id>: VERIFIED-CLEAN, with any reviewer name; a header that can’t be parsed is refused with 422 verdict_header_unparseable before anything is written (v0.27.0).
The reviewer can also pass reviewed_commit, the full commit id (40 or 64 lowercase hex characters) of the head it read, which is stored with the verdict so check_merge_readiness can require the clean verdict to be on the current head (v0.29.1). In implement_until_done mode the implementer reporting done no longer finishes an item on its own: the item finishes only once a trusted strict VERIFIED-CLEAN verdict comes from an identity other than the implementer’s.
AgentRun
Section titled “AgentRun”Tracked execution records for persona runs, manual or in CI. These tools record that a run happened and evaluate a fail_on policy at completion; they never start the model themselves. See CI Integration.
create_agent_run
Section titled “create_agent_run”Create a run for a persona. Pass start_now=true to create and start it in one call; the response then includes the compiled persona and ticket context.
| Parameter | Type | Required | Description |
|---|---|---|---|
persona_name |
string | yes | Persona that runs |
tool |
string | no | Tool label (default generic) |
trigger_source |
string | no | manual, ci, webhook, scheduled, mcp (default) or api |
ticket_id |
string | no | Ticket the run works on (same project) |
trigger_ref |
string | no | Commit, PR or other reference |
ci_provider / ci_run_url |
string | no | CI provenance |
fail_on |
string | no | none, low, medium, high or critical |
model |
string | no | Model the run reports it ran |
provider |
string | no | Provider of the reported model |
role |
string | no | implementer, ui-implementer, reviewer, design-reviewer, security-reviewer or release |
branch |
string | no | Working-tree branch for the run |
base_sha |
string | no | Base commit SHA (7–64 hex chars) |
parent_run_id |
string | no | Parent run (same project) |
continues_run_id |
string | no | Run this continues (same project) |
start_now |
boolean | no | Start the run immediately (default false) |
git_remote |
string | no | Project selector (see above) |
complete_agent_run
Section titled “complete_agent_run”Record the result of a queued or running run. The server evaluates fail_on and stores policy_result and exit_code. Usage fields are additive — if you reported usage while the run was in flight, the values here are added on top rather than overwriting them.
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run ID |
status |
string | no | passed (default), failed or errored |
severity |
string | no | Highest finding severity (none default) |
findings |
array | no | Structured findings (objects) |
result_summary |
string | no | Short summary |
session_id |
string | no | Session that did the work |
input_tokens / output_tokens |
integer | no | Token usage (≥0, additive) |
cache_read_tokens / cache_write_tokens |
integer | no | Cache token usage (≥0, additive) |
cost_usd |
number | no | Cost in USD (≥0, additive) |
cost_basis |
string | no | reported, estimated, plan or unknown |
head_sha |
string | no | Head commit SHA (7–64 hex chars) |
exit_reason |
string | no | finished, out_of_turns or crashed |
occurred_at |
string | no | When the run finished (ISO-8601) |
cost_basis says where a cost came from: reported (the tool or provider reported it), estimated (your own estimate), plan (covered by a subscription, no per-token cost) or unknown. A run that reports tokens without a cost counts as unknown. Spend rollups add dollars only for reported and estimated runs.
Each finding may carry review-loop keys, validated when present: round (integer ≥ 1), severity (none, low, medium, high or critical), class (a lowercase slug naming the kind of mistake, or new), harm (data-exposed, money-spent, wrong-actor, crash, other or none), stage (design or code), status (open, fixed, accepted or ticketed) and fixed_in_sha (7–64 hex characters). Findings without these keys are stored as before.
report_agent_run_usage
Section titled “report_agent_run_usage”Add token/cost usage to a queued or running run. Usage is additive while the run is active — long runs and continuations report more than once. After the run reaches a terminal state the totals are fixed and further reports are rejected with a conflict.
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run ID |
input_tokens / output_tokens |
integer | no | Token usage (≥0, additive) |
cache_read_tokens / cache_write_tokens |
integer | no | Cache token usage (≥0, additive) |
cost_usd |
number | no | Cost in USD (≥0, additive) |
git_remote |
string | no | Project selector (see above) |
replay_agent_run
Section titled “replay_agent_run”Create a queued copy of an existing run with an edited prompt, ticket, persona, context references, fail_on or trigger_ref. Fields you leave out are copied from the original, and the new run records which run it came from. Returns the new run plus the sfs agent run --run-id command and a CI snippet to run it.
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run to replay |
prompt |
string | no | Edited prompt |
context_refs |
array | no | Context references for the new run |
ticket_id |
string | no | Override the ticket (same project) |
persona_name |
string | no | Override the persona |
fail_on |
string | no | Override the fail-on level |
trigger_ref |
string | no | Override the trigger reference |
list_agent_runs
Section titled “list_agent_runs”List recent runs, newest first. Filter by persona_name, status, trigger_source or ticket_id; limit defaults to 50 (max 200).
Agent Feedback
Section titled “Agent Feedback”Structured, append-only outcome records on agent work. Each record points at least one target (agent_run_id, ticket_id, or comment_id) — all of which must belong to the same project — and classifies the signal with a feedback_type × verdict × optional label. Available on every plan (the agent_runs feature); service keys use the agent_feedback:read / agent_feedback:write scopes.
The fixed label vocabulary per type:
feedback_type |
Valid labels |
|---|---|
route |
correct_route, wrong_route |
summary |
summary_good, summary_bad |
actionability |
actionable, not_actionable |
duplicate |
duplicate, new_issue |
resolution |
false_positive, flaky, resolved_by_fix, resolved_by_test_update |
Reassigning an agent-created ticket to a different persona auto-records a route / negative / wrong_route record (source="auto", final_owner = the new persona), once per (ticket, new owner) — so the router learns from every correction.
record_agent_feedback
Section titled “record_agent_feedback”Create one feedback record. At least one of agent_run_id / ticket_id / comment_id is required, and each target is validated against the project (cross-project targets return 404).
| Parameter | Type | Required | Description |
|---|---|---|---|
feedback_type |
string | yes | One of route, summary, actionability, duplicate, resolution |
verdict |
string | yes | positive, negative, or neutral |
label |
string | no | Fixed vocabulary word valid for the chosen feedback_type |
final_owner |
string | no | Persona/owner the signal points at (≤100 chars) |
notes |
string | no | Free-form note (≤4000 chars) |
agent_run_id |
string | no | Target agent run |
ticket_id |
string | no | Target ticket |
comment_id |
string | no | Target ticket comment |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
list_agent_feedback
Section titled “list_agent_feedback”List feedback records oldest-first with a stable (created_at, id) cursor. Filter by target (agent_run_id, ticket_id), feedback_type, verdict, label, or persona (matched via the record’s run/ticket).
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_run_id |
string | no | Filter to a single run |
ticket_id |
string | no | Filter to a single ticket |
feedback_type |
string | no | Type filter |
verdict |
string | no | Verdict filter |
label |
string | no | Label filter |
persona |
string | no | Match records whose run or ticket belongs to this persona |
since |
string | no | ISO timestamp cursor |
since_id |
string | no | ID tiebreaker for the since cursor |
limit |
number | no | Page size (default 100) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_agent_feedback_summary
Section titled “get_agent_feedback_summary”Grouped counts by feedback_type × verdict × label — pure SQL aggregation, no LLM. Optionally filter by persona or since.
| Parameter | Type | Required | Description |
|---|---|---|---|
persona |
string | no | Only records whose run/ticket belongs to this persona |
since |
string | no | Only records after this ISO timestamp |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_spend_summary
Section titled “get_spend_summary”Summarize agent-run spend for the current project (grouped by persona, model, ticket, role, or day over a from/to window that defaults to the last 30 days) or for a single ticket (totals plus per-persona and per-model plus the review-round count). Token totals are always returned; dollar amounts are only returned when the caller has admin standing on the project (org owner/admin, or the owner of a personal project) and never for service keys. Runs with cost_basis plan or unknown count tokens but no dollars.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | no | Summarize a single ticket instead of the project |
group_by |
string | no | persona, model, ticket, role, or day (project mode only) |
from |
string | no | Start of the window (ISO datetime) |
to |
string | no | End of the window (ISO datetime) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_loop_report
Section titled “get_loop_report”Per-round review-loop rollup for one ticket: findings grouped by harm, how many findings were known checklist classes versus brand-new (class: "new"), how many were raised at the design stage, and the tokens (and dollars, for admin callers) attributed to that round. A run’s tokens/dollars go to its primary round — the first (round, stage) key in its findings. Dollar amounts follow the same visibility rule as get_spend_summary (org owner/admin or the owner of a personal project; never service keys).
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Ticket id (tk_...) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
Review Loops (Team+)
Section titled “Review Loops (Team+)”Start and watch a worker review loop, run its workers, record its review rounds and manage its budgets. Reports and the checklist tools are listed below and under Review Checklist. Added in v0.29.2; the worker and review-round tools were added in v0.29.3.
start_review_loop
Section titled “start_review_loop”Start a loop: adopt an existing issue (from_ticket_id) or create a new parent issue, file one child task per brief and create the review_until_clean queue for the reviewer persona. Returns the loop id, the child tickets with their briefs, the queue id and the environment each role needs. cost_budget_usd needs org owner or admin standing.
| Parameter | Type | Required | Description |
|---|---|---|---|
tickets |
array | yes | Child tasks: {title, description, acceptance_criteria} |
reviewer_persona |
string | yes | Persona that reviews the children |
title |
string | no | Parent issue title; required unless you adopt an issue (ignored with from_ticket_id) |
description |
string | no | Parent issue description |
from_ticket_id |
string | no | Existing issue (tk_...) to adopt as the loop parent |
ticket_id |
string | no | Same as from_ticket_id (the name start_workflow uses). Send one; two different values are refused |
token_budget |
integer | no | Token budget for the loop |
cost_budget_usd |
number | no | Dollar budget (org owner or admin only) |
max_review_rounds |
integer | no | Review-round cap; there is no default cap |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_loop_status
Section titled “get_loop_status”Read-only rollup of one loop: for each child its status, branch, head commit, review rounds, open harmful findings, findings by harm, tokens (and dollars for admins), budget use, whether it needs a person, and merge readiness.
| Parameter | Type | Required | Description |
|---|---|---|---|
loop_id |
string | yes | Loop (parent issue) id (tk_...) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
update_review_loop
Section titled “update_review_loop”Raise or clear a loop’s limits. Omitted fields stay as they are; an explicit null clears a limit. cost_budget_usd is for org owners and admins and is never visible to service keys. Closing an item the loop handed back for a person is not available here: only people can do that, from the dashboard, sfs loop close-item or the API.
| Parameter | Type | Required | Description |
|---|---|---|---|
loop_id |
string | yes | Loop (parent issue) id (tk_...) |
token_budget |
integer or null | no | New token budget |
max_review_rounds |
integer or null | no | New review-round cap |
cost_budget_usd |
number or null | no | New dollar budget (org owner or admin only) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
start_worker_run
Section titled “start_worker_run”Start a worker run on a loop ticket. Takes the ticket’s lease and opens an implementer run linked to the loop’s queue item. Refuses with loop_needs_human when the item is parked for a person or a budget is already used up. Returns the run_id, the lease_epoch, the ticket and loop ids and what is left of the budget (dollars only for org owners and admins). Added in v0.29.3.
| Parameter | Type | Required | Description |
|---|---|---|---|
ticket_id |
string | yes | Child ticket id (tk_...) |
model |
string | no | Model the worker uses |
provider |
string | no | Provider of the model |
branch |
string | no | Working branch |
head_sha |
string | no | Base commit (7-64 hex characters) |
tool |
string | no | Tool name for the run |
step_id |
string | no | Workflow step this report is for, from get_workflow_plan (workflow loops only; a mismatch is a 422) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
finish_worker_run
Section titled “finish_worker_run”Finish a worker run: record the head commit, how the worker exited and the tokens it used, then check the loop’s budgets. Hitting a token budget parks the item for a person. Repeating the call with the same head_sha returns the same result and never counts usage twice; a different head_sha after the run finished is a 409. Added in v0.29.3.
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id |
string | yes | Run id returned by start_worker_run |
head_sha |
string | yes | Head commit the run produced (7-64 hex characters) |
exit_reason |
string | yes | finished, out_of_turns or crashed |
branch |
string | no | Working branch |
input_tokens, output_tokens |
integer | no | Tokens the run used |
cache_read_tokens, cache_write_tokens |
integer | no | Cache tokens |
cost_usd |
number | no | Cost of the run |
cost_basis |
string | no | reported, estimated, plan or unknown |
summary |
string | no | Short result summary |
step_id |
string | no | Workflow step this report is for, from get_workflow_plan (workflow loops only; a mismatch is a 422) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
record_review_round
Section titled “record_review_round”Record one review round on a loop ticket, or a design round on the loop’s parent issue. Creates the reviewer’s run with its findings and posts the verdict for the exact commit. Whether the verdict is trusted comes only from the credential that sent it and the trusted-reviewers registry. Repeating a round is safe. A finding with class new proposes a checklist item. Going past the round cap or the token budget parks the ticket for a person. Added in v0.29.3.
| Parameter | Type | Required | Description |
|---|---|---|---|
loop_id |
string | yes | Loop (parent issue) id (tk_...) |
ticket_id |
string | yes | Child ticket id, or the loop id for a design round |
round |
integer | yes | Round number, 1 or more |
stage |
string | yes | design or code |
reviewed_commit |
string | yes | Full commit id (40 or 64 hex characters) that was reviewed |
verdict |
string | yes | VERIFIED-CLEAN or CHANGES-REQUESTED |
findings |
array | no | {severity, class, harm, title, file?, line?, status?} for each finding; severity is low, medium, high or critical, class is a checklist slug or new, harm is data-exposed, money-spent, wrong-actor, crash, other or none |
model, provider |
string | no | Reviewer model and provider |
input_tokens, output_tokens, cache_read_tokens, cache_write_tokens |
integer | no | Tokens the reviewer used |
cost_usd |
number | no | Cost of the round |
cost_basis |
string | no | reported, estimated, plan or unknown |
step_id |
string | no | Workflow step this report is for, from get_workflow_plan (workflow loops only; a mismatch is a 422) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
Workflow Templates
Section titled “Workflow Templates”Record-only workflow templates. A template is a small graph of steps; starting one creates a review loop with one child ticket per step slot. SessionFS never starts an agent: your orchestrator reads the plan, launches the agents and reports each step through start_worker_run, finish_worker_run and record_review_round with step_id. Reading templates works for project readers (org templates for org members); starting a workflow is a loop write (Team+). Added in v0.29.9.
list_workflow_templates
Section titled “list_workflow_templates”Active templates: the project’s own plus its org’s, newest first.
| Parameter | Type | Required | Description |
|---|---|---|---|
org_id |
string | no | List only this org’s templates |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_workflow_template
Section titled “get_workflow_template”One template version by id, with its definition.
| Parameter | Type | Required | Description |
|---|---|---|---|
template_id |
string | yes | Template id (wft_...) |
org_id |
string | no | Read through the org instead of the project |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
start_workflow
Section titled “start_workflow”Start a workflow: a loop pinned to the template version, one child ticket per step slot, briefs rendered from the template and the project checklist. Same rules and budgets as start_review_loop. Nothing is started.
| Parameter | Type | Required | Description |
|---|---|---|---|
template_id |
string | yes | Template id (wft_...) |
ticket_id |
string | one of | Existing issue (tk_...) to adopt as the loop parent |
title |
string | one of | Title for a new loop parent issue |
description |
string | no | Parent issue description |
reviewer_persona |
string | no | Reviewer persona for the loop queue |
token_budget |
integer | no | Token budget |
cost_budget_usd |
number | no | Dollar budget (org owner or admin only) |
max_review_rounds |
integer | no | Review-round cap |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
get_workflow_plan
Section titled “get_workflow_plan”Per step: state (blocked, ready, running, needs_human, done), gate_status, a reason when it is not ready, the tickets a reviewer step reviews, and ready_children with each ticket’s agent and brief. ready_steps lists the steps you can run now and done is true when every step is done. A step’s gate is its exit gate: nothing after it is ready until it passes. Read-only; computed on every call.
| Parameter | Type | Required | Description |
|---|---|---|---|
loop_id |
string | yes | Workflow loop (parent issue) id (tk_...) |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
Review Checklist
Section titled “Review Checklist”The project checklist that learns: a per-project list of review traps. Proposed items are the acceptance inbox; active items render into every brief via the markdown endpoint. Finding-sourced items are proposed automatically when an agent run completes with class: "new" findings.
get_loop_checklist
Section titled “get_loop_checklist”List the project’s checklist items, optionally filtered by status.
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
string | no | Filter by proposed, active or retired |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
propose_checklist_item
Section titled “propose_checklist_item”Propose a checklist item by hand. The item starts proposed and the project owner accepts or skips it; the slug is derived from the title when not given.
| Parameter | Type | Required | Description |
|---|---|---|---|
title |
string | yes | The trap, e.g. “Access rechecked after slow steps” |
check_text |
string | no | How to check for it (defaults to the title) |
slug |
string | no | Lowercase slug; derived from the title when omitted |
git_remote |
string | no | Git remote URL (auto-detected if omitted) |
Skills Marketplace
Section titled “Skills Marketplace”Marketplace tools separate discovery from authority. Search and preview return metadata or visibly untrusted text. load_marketplace_skill returns instruction text only after an exact-version project approval or organization assignment; it never installs files or activates scripts, hooks, executable extensions, or local MCP processes. Every preview and load response carries untrusted: true plus a fixed untrusted_preamble telling the model the content is third-party data, not instructions from the user.
Approval is never brokered over MCP. A project owner/admin approves from the dashboard or API, confirming each elevated capability (scripts, hooks, MCP, assets) explicitly. If the approver is the same principal that filed the request, the server additionally requires a single-use confirmation code emailed to that account (POST .../challenge); requested_via is recorded for display only. This closes the preview → request → approve → load self-approval loop.
| Tool | Purpose |
|---|---|
search_skill_marketplace |
Search public, personal, and authorized organization listings; optionally filter by target tool, category, publisher, verified publisher, trusted-publishing provenance, license, max scan severity, capability, works-in tool, updated within N days and deprecation, sorted by relevance or recent |
get_marketplace_package |
Inspect immutable hash, provenance, license, verification, risk, compatibility, and the install disclosure (files per tool, hooks, scripts, MCP servers, network endpoints, shell commands, hidden characters). Display only |
diff_marketplace_versions |
Compare two versions of one package: files, capability changes, and the update class (text, code, or widening). Read-only |
get_skill_policy |
The org skills policies that apply to you and, per tool, what the tool enforces, what only SessionFS checks, and what nothing checks. Use it to explain a refusal. Read-only (Enterprise) |
preview_marketplace_skill |
Read a bounded, untrusted instruction preview without granting consent |
load_marketplace_skill |
Load approved instruction-only context for one project/tool/device boundary |
request_skill_install |
Request an exact hash for project, user, or device scope |
get_skill_install_request |
Inspect one request |
list_skill_install_requests |
List project requests, optionally filtered by status |
cancel_skill_install_request |
Cancel a pending request as requester or project admin |
Use the Skills Marketplace guide for the four consumption modes and their security boundaries.
Project Groups (Team+)
Section titled “Project Groups (Team+)”Org-scoped groups of projects. Every tool addresses a group by its org-scoped slug and takes an optional org_id (default: your default org, sfs config default-org); list_group_access needs no org at all. Group-wide reads (search_group_knowledge, get_group_context, ask_group) only ever return content from member projects you can read yourself. See Project Groups.
| Tool | Purpose |
|---|---|
list_project_groups |
List an org’s groups with counts and your role |
get_project_group |
One group’s members, member projects, and compile setting |
create_project_group |
Create a group (org admin/owner) |
update_project_group |
Rename, re-slug or re-describe a group, or turn its knowledge compile on/off with compile_enabled (group admin or org admin/owner) |
delete_project_group |
Soft-delete a group (org admin/owner) |
add_project_to_group |
Add a project (group admin with edit standing on it) |
remove_project_from_group |
Remove a project (group admin) |
list_group_members |
A group’s member grants |
grant_group_access |
Grant or change a member’s role: reader, editor, admin (group admin) |
revoke_group_access |
Revoke a member’s grant (group admin) |
list_group_access |
Every group you have standing on, across your orgs |
search_group_knowledge |
Search active claims across the group’s readable member projects (q 3–200 chars, limit ≤ 100) |
get_group_context |
The group’s compiled overview (only if you can read every contributing project) |
compile_group_knowledge |
Compile the deterministic overview (group editor/admin or org admin; the group must have compile_enabled) |
ask_group |
Research a question across the group’s context and knowledge, with typed sources_cited including project ids |
Meetings and chat
Section titled “Meetings and chat”Stored meeting transcripts and chat threads for a project (git_remote or the workspace) or a project group (group_id, user keys only). Text is DLP-redacted by the server before storage and is returned as untrusted data. All access rules are enforced server-side. See Meetings. A chat thread is a kind=chat row of the meeting tools: list_meeting_transcripts and search_meetings take kind (meeting by default, chat or all), get_meeting_transcript and extract_meeting_action_items take an optional kind that must match the row, and promote_meeting_action_item takes conversation_kind (its kind stays the ticket kind).
| Tool | Purpose |
|---|---|
upload_meeting_transcript |
Store a transcript (title, content, optional meeting_at, source, extract). With extract=true it also runs one extraction call using your own LLM key (your key, else your org’s; never a SessionFS key); without a key the transcript is still stored |
list_meeting_transcripts |
Meetings, newest first (q, limit 1–200, before cursor); summaries only |
get_meeting_transcript |
One meeting by id: text, participants and extracted items. A pending item may carry suggested_ticket (an existing ticket it looks like, with suggestion_source model or text); a linked item carries linked_ticket |
extract_meeting_action_items |
Extract participants, action items and decisions with your own LLM key, and suggest existing tickets the items look like. Re-running keeps promoted, dismissed and linked items |
promote_meeting_action_item |
Preview only unless confirm=true. The preview returns the ticket draft; with confirm=true it creates the ticket, using any edited title, description, priority, kind, assigned_to, assigned_user_id, due_date, target_project_id you pass, and marks the item promoted. publish_to_jira=true also publishes it to Jira |
link_meeting_action_item |
Preview only unless confirm=true. Tie a pending item to an existing ticket (ticket_id, or the item’s suggestion when omitted on the preview; confirm=true requires ticket_id set to the ticket the preview returned, and a missing or different id links nothing): the item becomes linked and the ticket gets a “Raised again in meeting …” comment and a timeline event. unlink=true with confirm=true puts it back to pending (the comment stays). Takes conversation_kind like promote |
search_meetings |
Search meeting titles and transcript text (q, limit, kind) |
upload_chat_thread |
Store a chat thread: provider (slack, discord, paste, teams_paste), channel_name, content (the export as a string, or the paste; 2 MiB max, refused before the request), optional attestation (required for a paste: it is a channel, not a DM), users (Slack users.json), title, extract. Direct-message exports are refused |
Reminders
Section titled “Reminders”Personal reminders on every plan. A reminder is private to the person reminded and the person who set it; anyone else gets the same “not found” as for an id that does not exist. Due reminders reach the notification bell, the Inbox and (if your settings allow) the email digest. Titles and notes are DLP-redacted by the server before storage. Service keys act as their minter, need reminders:read / reminders:write, and only see reminders on a project inside the key’s org and allowlist.
| Tool | Purpose |
|---|---|
list_my_reminders |
Your reminders, earliest due first, each with is_due. Filters: status (open default, done, dismissed, all), due_before (ISO 8601), source (meeting, meeting_item, ticket, or kind:id), limit (1–200) |
create_reminder |
Remind yourself (never someone else): title, due_at (ISO 8601; without an offset it is read in timezone, an IANA name, else UTC; between 1 hour ago and 2 years ahead), optional source {kind, id, lines} on a meeting, meeting item, ticket, session or knowledge entry you can read |
update_reminder |
Exactly one change per call: note (append a note), snooze (1h, tomorrow, next_week at 09:00 in the reminder’s timezone, or custom with until), reschedule (a new due_at, optional timezone), or close (done or dismissed) |
Approvals
Section titled “Approvals”Read-only views of approval policies (Enterprise). Agents cannot approve or reject; a person decides in the dashboard or with sfs approval approve|reject. Service keys need approvals:read and only see their own org and project allowlist.
| Tool | Purpose |
|---|---|
list_my_approvals |
Pending requests you could decide now (merges at one commit, KB entries waiting to become claims), newest first, with approvals so far |
get_approval_request |
One request by id (ar_…): policy version and requirements, target and fingerprint (commit sha or content sha256), state and every decision |
list_approval_policies |
An org’s active policies (org_id, else your default org). Members see names and requirements; owners and admins also see filters |
External contacts
Section titled “External contacts”People your org works with who are not SessionFS users (External contacts). Org members read and create; owners and admins merge and delete (not over MCP). Emails are masked for members other than owners, admins and the creator, and never shown to service keys (contacts:read / contacts:write, own org only). Without org_id the default org is used.
| Tool | Purpose |
|---|---|
list_external_contacts |
The org’s contacts: q (name or alias), status (active, archived, all), tag, before, limit |
get_external_contact |
One contact (contact_id) and the meetings, chats, action items and tickets naming it that you can read. A merged id returns the contact it was merged into |
create_external_contact |
Create a contact when a person asks: display_name, optional email, role, tags, aliases. Never from names found in transcripts |
update_external_contact |
Edit display_name, role, tags, email, status (active or archived), add_aliases, remove_aliases; explicit null clears role or email |
create_ticket and update_ticket take assigned_contact (a contact of the project’s org; persona, person and contact are mutually exclusive).
For You
Section titled “For You”| Tool | Purpose |
|---|---|
get_my_attention |
What needs you: the ranked For You feed across reminders, approvals, assigned tickets, Review Loop items, meeting and chat action items, knowledge changes and the weekly proof card. Filters: band (now, your_turn, upcoming, lately), limit (1–100). Service keys need attention:read and see only their org and project allowlist; each section also needs its own read scope (approvals need approvals:read) |
Evaluations and Lineage
Section titled “Evaluations and Lineage”Record-only evaluations and lineage. Your grader runs in your own CI and posts results; SessionFS computes the verdict and whether the run is trusted. Agents grade and register artifacts but cannot define suites or promote: those are people-only (CLI or dashboard). Writes need Team or Enterprise. Service keys use evals:read/evals:write and artifacts:read/artifacts:write. Responses that carry case text or grader output include an untrusted_content_notice.
| Tool | Purpose |
|---|---|
list_eval_suites |
Active suites: slug, version, grader persona, acceptance, case storage, live case count (cursor pages) |
get_eval_suite |
One suite by evs_ id, evl_ lineage id or slug, with its versions; include_cases adds the first page of live cases (inputs only for inline storage) |
start_eval_run |
Start grading the active suite version against artifact_id, commit_sha (full hex) or subject_label; optional ticket_id, trigger_source, trigger_ref. Your credential becomes the grader; returns the cases and a trust_preview |
record_eval_results |
Post up to 500 results (case_key, verdict pass/fail/error/skip, score 0–1, notes, output, content_sha256 for reference storage); finish: true closes the run. Optional input_tokens, output_tokens, cost_usd go on the grader run |
get_eval_run |
A run’s state, verdict, trusted or unverified with the reason, and summary; include_results adds the first page of results |
compare_eval_runs |
a (reference) vs b (candidate) of one suite: regressions, fixes, cases added/removed, score deltas, pass rate per tag |
register_artifact |
Register a version as a pointer: kind, name, version, external_uri (never fetched; pre-signed URLs refused), optional digest, schema_summary, description, tags, produced_by_agent_run_id |
link_artifacts |
Add a lineage edge parent_id → child_id with a relation; cycles and self-edges are refused |
get_artifact_lineage |
Trace up, down or both (depth ≤ 25, ≤ 500 nodes) with the latest trusted run per suite and node |
list_artifacts |
Filter by kind, name, stage, tag (key or key=value); cursor pages |
Agent Knowledge Contribution
Section titled “Agent Knowledge Contribution”When sfs mcp install runs, it injects a MANDATORY instructions block into the tool’s project config file (e.g., CLAUDE.md, .cursorrules). These instructions tell the agent it must call add_knowledge() when discovering architecture decisions, code patterns, bugs, dependencies, or conventions — and must not end a session without contributing if it learned something new.
This creates a knowledge loop: each session reads project context at the start and writes back discoveries at the end. Tools that support project-level instructions: Claude Code (CLAUDE.md), Codex (codex.md), Gemini (GEMINI.md), Cursor (.cursorrules). For other tools, instructions are served at runtime via get_project_context.
Remote MCP (HTTP/SSE)
Section titled “Remote MCP (HTTP/SSE)”Remote MCP over HTTP/SSE, for agents that cannot launch local processes (e.g., claude.ai), is not currently supported — neither as a hosted endpoint nor self-hosted. Use the local server above.
Configuration
Section titled “Configuration”| Variable | Description |
|---|---|
SFS_API_URL |
SessionFS cloud API URL (for knowledge tools) |
SFS_API_KEY |
API key for cloud authentication |
sfs mcp serveRuns the MCP server on stdio transport. Connect from any MCP-compatible client.
Rebuild the search index:
sfs mcp indexRe-indexes all local sessions into the full-text search database.
Uninstall:
sfs mcp uninstall --for claude-codeRemoves the MCP server registration and cleans up injected knowledge instructions from the project config file. Supported tools are the same as for install.