Skip to content

MCP Verbs

softfig-mcp is the bridge that lets a Claude session propose garden writes. It is a stateless stdio server, spawned per session, that forwards each verb to the running softfig-keeperd daemon over its IPC socket. Reads of the garden are plain filesystem operations — Claude just reads the mounted tree — so the verbs below are the write surface plus a few coordination reads. The server lists 43 tools. Registering the server is covered in Register softfig-mcp; the practice of working through it is Working with Claude.

Every write verb is convention-stamping: the daemon owns all the mechanical fields — dates, sequence numbers, # title and > Last reviewed: headers, filenames, index tables, [[…]] backlinks — and the commit. The caller emits only the irreducible new content. Each successful write is one typed commit whose intent classifies it (decision_logged, note_added, …), which is what makes history queryable by what changed.

Verb Key params Purpose
log_decision slug, body, summary? Write journal/decisions/decision-<slug>.md with a stamped # decision: <title> header and date.
log_incident slug, summary, body, date? Write journal/incidents/incident-<date>-<slug>.md with a stamped header.
add_note dir, slug, body, title? Append a numbered note NNN-slug.md to a notes/ or troubleshooting/ folder (.seq, title, > Last reviewed: stamped).
revise_note dir, id, body Replace the body of a numbered note; number, slug, and title stay fixed; reviewed date re-stamped.
add_code_review dir, slug, body, title? Append a numbered record to a code-reviews/ folder (same machinery as add_note).
add_project name, repo_path?, summary? Scaffold projects/<name>/ with its reserved-name stubs in one commit.
refresh_snapshot path, content Write caller-supplied content under snapshots/. The daemon never runs your data-gathering command.
archive src, archive_name? Move a tracked path under journal/archive/<name>/ and rewrite references to it.

Sections are addressed by heading text (case-sensitive, level-agnostic, # prefix optional; the heading must match exactly one). expected_version is an optional compare-and-swap guard (whole-file for file verbs, per-section for section verbs); seed it with read_versions. editor is an optional per-agent identity for the contention detector in multi-agent fleets.

Verb Key params Purpose
add_section path, heading, body Append a new section (leading #s set the level, default ##). The heading must not already exist.
edit_section path, heading, body, expected_version?, editor? Replace a section’s body, keeping its heading.
append_to_section path, heading, text, expected_version?, editor? Add a row, bullet, or line to the end of a section.
remove_section path, heading, expected_version?, editor? Delete a section (heading, body, and subsections). Refused for the file’s last heading or a daemon-managed region.
patch_file path, old, new, anchor?, expected_version?, editor? Exact old→new replacement; old must occur exactly once in the search window (the file, or the line range of anchor). Refused if it would change a daemon-managed softfig: region.
set_reviewed path Bump the doc’s Last reviewed: line to today.
unlink path, expected_version?, editor? Delete one file. Refused if it appears in an index region or has inbound [[…]] links; use archive for those. Files only.
batch ops, editor? Apply several sub-ops as one atomic commit. Allowed ops: patch_file, edit_section, append_to_section, add_section, remove_section, set_reviewed, add_note, revise_note. Every op is validated before anything is written; any failure aborts with nothing changed.
replace_file path, content, expected_version? Break-glass. Overwrite a file with verbatim bytes and no stamping. Discouraged; use it only when no structural verb fits (e.g. rewriting a monolithic CLAUDE.md).

These return data or arbitrate coordination; they don’t stamp garden content.

Verb Key params Purpose
read_versions path A file’s current CAS version tokens (whole-file and per-section) without its content. Also flags vault-sealed paths.
file_provenance path, limit? Who last edited a path and its recent edit history (default 20), from the commit chain.
read_inbox agent Read the agent’s unread coordination-bus messages (direct and @all) and advance its cursor.
list_reports tags? List filed reports carrying all given tags (ns:* matches any value). Read-only.
request_lease agent, key Request a supervisor-arbitrated lease over a shared resource. Returns granted, waiting, or denied. Needs growlightd; no commit.
release_lease agent, key Release a held lease and promote the head waiter. No commit.
Verb Key params Purpose
post_message from, to, kind, body Post to the coordination bus. to is an agent slug, @all, or @human; kind is info, coord-request, lease-request, question, alert, or restart-request.
file_report title, body, tags, item?, from?, slug? File a numbered report under growlight/reports/. Tags need exactly one type: (bug, regression, flake, security, doc-drift, finding, question, blocker, idea) and may carry severity: (critical/high/medium/low) plus free tags. Blockers, security reports, and critical severity also alert @human.
update_report number, status?, add_tags?, remove_tags?, note?, from? Move a report along: status open, triaged, resolved, wontfix, duplicate. Closing requires a note.

The queue is the ordered work list. The first group is the current queue; every mutating verb there takes dry_run (validate and render, write nothing). Human CLI equivalents are under CLI → Queue and slices.

Verb Key params Purpose
queue_add_project name, repo, main?, dry_run? Register a project: a name bound to a repo and its merge branch. Human-only.
queue_add_entry kind (milestone/task/restack), project, slug?, title?, mission?, finish_criteria?, lane?, after?, position?, ref?, slices?, dry_run? Create a backlog entry, its docs, and its queue row in one commit. A fleet member may add only normal-lane milestones and tasks (found work), at the back.
queue_update_entry id, lane?, move?, after?, status?, dry_run? One atomic patch-style edit of a live entry, applied lane, then move, then links, then status (queued/blocked/deferred/done). Human-only.
queue_drop id, reason, dry_run? Archive a live entry as dropped. Human-only.
slice_insert milestone, slug, body, title?, position?, ref?, dry_run? Append a numbered slice to a milestone. A fleet member may insert only within its own current entry.
slice_update milestone, id, move?, status?, dry_run? Move a slice or set its status. A fleet member may only move, within its own entry.

Older table-based backlog verbs, still shipped for gardens using the original backlog table:

Verb Key params Purpose
add_backlog_item slug, item_type, title, mission, finish_criteria, queue? Seed a milestone or task and enqueue it.
add_queue name, repo Register a named work-stream queue bound to a repo path.
add_slice milestone, slug, body, title? Append a numbered slice doc under a milestone.
set_item_status id, status, queue? Set an item’s status (queued, active, done, blocked, deferred). At most one active.
reorder_backlog_item id, position (top/bottom/before/after), ref_id?, queue? Move an item’s row without changing status.
log_baton summary, iteration, item?, slice?, status?, … Append a numbered iteration entry to the append-only baton-log/.

These five work only inside a fleet member session (growlightd launches members with SOFTFIG_MEMBER set; elsewhere they are refused not_a_member). Each ends the session and hands the baton on, so a member calls one last. A refusal leaves the session running with an error code to correct.

Verb Key params Purpose
growlight_complete_slice summary, baton This session’s slice is done. Refused for tasks, restacks, and close-out units.
growlight_complete_entry outcome (done/deferred), summary, baton, deferred_tests? Close out a milestone, task, or restack. deferred requires the pending manual tests.
growlight_add_follow_up_session reason, baton, model?, variant?, new_slice? End early and run a fresh session on the same unit. Reasons: context_full, mcp_updated, daemon_restarted, session_fault, model_change, new_scope, preempted. Capped at 5 per unit.
growlight_block kind (human/stuck), reason, baton Park the entry until a human unblocks it.
growlight_add_sub_milestone slug, title, mission, finish_criteria, slices, baton, do_not_prioritize? Split the current slice’s remaining work into a sub-milestone (two levels deep at most).

There is no MCP verb for any vault operation — no reveal, seal, unseal, list-sealed, unlock, key rotation, or trust change. The verb registry contains no such entry; the only mention of the vault in the surface is the guard that refuses edits to sealed targets.

This is structural, not a matter of trust. Vault actions require the unlocked key and human-only policy that live in the daemon; they are CLI actions you take at a terminal (see softfig reveal / vault seal). Handing a garden to an assistant never hands it your secrets.


Related: Register softfig-mcp (setup), Working with Claude (the practice), CLI Reference (the human-facing surface), and Conventions (what the stamping enforces).