The local agent tool surface is declared in internal/mcp/registry.go and dispatched by internal/mcp/runtime.go. The registry contains 39 entries; standard MCP discovery exposes the 38 tools with runtime handlers and excludes repo.dependency_context. Use the generated .roundtable/mcp/tools.schema.json for the supported tool schemas; regenerate assets with roundtable mcp inspect --write after registry changes.
roundtable start serves standard MCP Streamable HTTP at http://127.0.0.1:7117/mcp by default and the legacy Unix socket against the same runtime. Harnesses that launch stdio processes use roundtable mcp stdio --root DIR; this bridge requires the HTTP owner to already be running. The Unix socket remains a Roundtable-specific newline-delimited JSON protocol, not MCP JSON-RPC. It has no cryptographic agent identity; actor fields are caller-supplied. Protect the project account and do not treat tool names or capability flags as an OS sandbox.
External CLI agents do not use the legacy coordinator socket or unrestricted /mcp endpoint. The supervisor creates a private per-session MCP Unix socket and injects a short-lived bearer capability through the container environment. The server resolves that token on every tool call and checks the persisted enabled agent, role, active session/run, task assignment, and allowed operation. Review/test/security executions are additionally bound to one proposal; repository reads require a claim within the task’s operator-authored readable_paths. Reviewers may claim only read/review, testers only read, and neither role receives implementation-write or approval-policy administration. Capability expiry/revocation is enforced server-side, not from client-supplied role headers or arguments.
For Codex CLI, configure the stdio process in project-local .codex/config.toml or add it with the Codex MCP CLI; do not edit global configuration as part of project setup:
[mcp_servers.roundtable]
command = "/absolute/path/to/roundtable"
args = ["mcp", "stdio", "--root", "/absolute/path/to/project"]
Other stdio harnesses use the same command/argument vector in their own MCP configuration format. For a remote listener, export ROUNDTABLE_MCP_TOKEN to both the start process and the stdio bridge process, or supply the bearer token through a trusted client credential mechanism. Direct HTTP clients send Authorization: Bearer <token>. Never put the token in command-line arguments, checked-in configuration, or logs. The default local HTTP endpoint is unauthenticated and loopback-only.
OpenRuntime(root) first loads .roundtable/config.yaml through the runtime configuration loader, opens SQLite using filepath.Join(root, storage.sqlite_path), and then loads the Markdown policy engine. Configuration/database/policy-load errors abort initialization; policy-load failure closes the newly opened database. It constructs claim, proposal, security-review, and symbol-index services around that root/store. Cleanup closes the database and ignores close errors. It does not register a workspace, sync configured agents, import tasks, run reconciliation, launch adapters, or start a Chair tick loop merely by opening this runtime.
Configuration and policy are loaded once per runtime instance, not on every tool dispatch. Editing YAML or policy Markdown does not hot-reload an already-running socket server’s service objects. A later direct-mode CLI call opens another runtime and can therefore see newer configuration/policy than the existing listener. HTTP configuration revisions are a separate control plane and do not configure this initialization path. Coordinate root/database/run attribution explicitly when using several processes.
Call dispatches through a fixed tool-name switch; it does not consult registry schemas for validation, permissions, or dynamic handler installation. A successfully parsed call can still fail handler-specific checks or reach the unimplemented fallback. Services perform their own persistence/filesystem work; dispatch supplies no encompassing transaction, global repository lock, durable request deduplication, or automatic compensation. Turn lifecycle synchronization uses a runtime-instance mutex, not a cross-process lock. Do not interpret the transport’s ok flag as proof of test success, safe patch application, authenticated actor identity, or atomic rollback on error.
The server accepts one request per Unix-domain connection. Send one JSON object terminated by a newline; the supported fields are tool (string) and args (object). For example:
{"tool":"task.list","args":{}}
The server writes one newline-terminated JSON response and closes the connection. Success uses {"ok":true,"result":{...}}; a tool or decoding failure uses {"ok":false,"error":"..."}. result and error are omitted when not applicable. Missing/null args is normalized to an empty object; unknown JSON fields are ignored by Go’s decoder. There is no JSON-RPC id, method, initialize handshake, tools/list exchange, protocol-version negotiation, or server-push notification framing. Agents discover names and input schemas from generated registry assets, then send Roundtable call envelopes.
Envelope parsing uses json.Unmarshal into CallRequest, not the HTTP limited decoder. The complete first-line bytes must contain one valid JSON value: trailing JSON values or malformed trailing data fail parsing. Unknown properties are ignored, struct field names match case-insensitively, and later duplicate keys can overwrite earlier values. JSON null decodes to the zero-value envelope and then receives empty args; it is not rejected as a non-object before dispatch. Empty/missing/null tool similarly reaches the unimplemented-tool path rather than a dedicated required-tool error. Tool strings are not trimmed or case-normalized, so names must match the dispatch switch exactly.
args must decode as an object or null; arrays/scalars and non-string tool values produce JSON type errors. Nested numbers use Go’s default float64 JSON representation, not json.Number; large integer IDs can lose precision before handler conversion. Use small exact integer event IDs and the documented field types. Unadvertised argument keys can reach handlers because there is no schema-validation pass.
Response encoding sets ok solely from whether the returned Go error is nil. On error it emits the error string and discards any accompanying result map; it does not expose partial effects, typed status codes, retry hints, or rollback evidence. A nil/empty success map can omit result because of omitempty, yielding only {"ok":true}. An empty error string can likewise omit error despite ok:false. Error text is not passed through a general secrets redactor. If a result cannot be JSON-marshaled, the socket handler logs the encoding failure and attempts a generic ok:false response; if writing the response to the socket fails, it logs that failure. Logs do not establish whether a mutation completed, and a client that receives no complete response must inspect authoritative state before retrying.
Each accepted connection is handled in its own goroutine, but it carries only one call. The server reads through newline or EOF and has no explicit request-line byte limit or per-connection read deadline. Clients should send compact bounded JSON, include the newline, read one response line, and close. Do not build an untrusted network listener around this local implementation.
EOF after nonempty bytes is accepted as a complete request, so a client can finish its write side without a newline. A client that sends neither newline nor EOF can leave a connection goroutine blocked indefinitely. Leading/trailing ASCII space, tab, CR, and LF are removed from the first line; an empty line closes without a response. Only that first line is processed: multiple newline-separated calls on one connection do not create a session or batch. Non-EOF read failures close without a problem envelope. This transport has no cancellation request, progress stream, replay cursor, request ID, or per-call retry key.
Encoding and socket-write errors are logged by the server. A client receiving no complete response must not infer that the tool did not execute or that persisted/file effects were rolled back. Inspect authoritative state before repeating a mutation. There is no response-byte cap, write deadline, connection-count limit, or bounded worker pool; tool output and open clients can consume process resources. Handler execution receives the server startup context, not a distinct client-disconnection cancellation context.
NewServer(root, socketPath, registry) retains the supplied root/socket and defaults a nil registry to DefaultRegistry(). It does not canonicalize those paths or apply an allowed-root policy at construction. Registry() exposes the metadata registry, but calls dispatch through the runtime opened from root; supplying a custom registry does not add executable handlers or enforce its schemas. Socket directory creation requests mode 0755, subject to umask, without tightening an existing directory or explicitly setting a restrictive socket mode. Review actual directory/socket ownership and permissions; there is no peer-credential check here.
Start opens the runtime before directory cleanup/listening and returns after launching goroutines. Runtime-open, parent-directory, path-removal, or listener errors abort startup; later non-closed accept errors are retried without a backoff or reported health transition. Do not repeatedly start another server at the same socket path: startup removal is not coordinated with an existing listener and can make that listener unreachable by pathname while existing connections remain.
Cancellation closes the listener and invokes runtime cleanup, but does not explicitly close accepted connections, wait for their completion, or interrupt a connection blocked in ReadBytes. The internal wait group tracks goroutines but no public wait/drain operation is provided. Close() alone closes the listener; it does not cancel the startup context or independently run runtime cleanup. Treat graceful shutdown and completed mutation evidence separately rather than assuming listener closure drains all tool calls.
roundtable mcp inspect only prints sorted tool names. Adding --write writes three derived files: the Markdown agent manifest, a JSON object containing the tools array (name, description, input_schema), and server.json metadata (name, transport, socket_path, manifest_path, tools_schema_path). These are Roundtable-specific integration assets, not a drop-in MCP server configuration for every client.
roundtable run starts this socket alongside the interactive coordinator; roundtable mcp serve starts only the tool server, without the TUI or coordinator tick loop. Thus a standalone server accepts state/tool calls but will not itself emit agent.turn_scheduled; turn requests advance only while an orchestrator roundtable run loop is ticking the same database. Startup opens the local runtime/database, creates the socket parent directory, removes the configured socket path recursively, then binds a Unix listener. Configure a dedicated socket pathname only: a stale socket is replaced, but the implementation does not first verify that an existing path is a socket. The socket has no application-level authentication, and every caller inherits the authority of the Roundtable OS process. Filesystem permissions and the account boundary are therefore the access controls.
The default is .roundtable/mcp/roundtable.sock. Keep it inside the project runtime directory, do not forward it to untrusted clients, and avoid paths that name valuable files or directories. Cancellation closes the listener and database; process termination also stops the service. Tool-call errors are returned in the JSON response over the socket, while roundtable mcp call --socket converts ok:false into a non-zero CLI error.
An agent that has something time-sensitive to report or do requests a turn with agent.turn_request (run_id, agent_id, reason_md). The run must exist and have exact status active; the global agent record must exist and be enabled. reason_md is trimmed and must contain 1–1,000 Unicode code points after trimming. The tool does not verify that the caller is that agent, that the agent belongs to the run/workspace, or that its reason is actually urgent: agent_id is an asserted event actor, not an authenticated identity. The request does not interrupt an agent already working or preempt a scheduled turn.
A new request appends agent.turn_requested to the run’s event stream. Its actor is the supplied agent_id; its JSON payload contains agent_id, the trimmed reason_md, and a UTC RFC3339Nano requested_at. The returned request_event_id is the durable event ID; queue_position is a one-based position calculated from outstanding requests’ event IDs. The event ID is the authoritative ordering key: the orchestrator sorts ascending and schedules only the oldest eligible request, recording agent.turn_scheduled with agent_id, request_event_id, the reason, and position 1. This is FIFO, not urgency/priority scoring; the reason is informational and does not reorder the queue.
An agent can have only one outstanding request per run. A repeated request by that agent before its request completes returns the existing event ID and position with duplicate: true; the newly supplied reason is ignored and no event is appended. Once the request has a matching agent.turn_completed event, another request from that agent may be recorded. Requests are scoped by run, so an agent may have requests outstanding in different runs. Queue position is only a snapshot: requests can be added or completed immediately afterward.
Poll table.watch with the run ID and after_event_id: 0, then pass each response’s next_after_event_id on the next poll until the matching agent.turn_scheduled appears. This cursor mode returns bounded events in ascending order with has_more_events, so a caller can drain every page; calls without a cursor retain the recent-activity snapshot behavior. After finding the matching schedule event, call agent.turn_start; after completing the work call agent.turn_complete, allowing the Chair to advance the queue.
Each lifecycle call requires run_id, agent_id, and request_event_id. The run must still have exact status active; the referenced request event must exist in that run and have the same actor ID. agent.turn_start additionally requires a matching agent.turn_scheduled event and rejects a second start. agent.turn_complete requires a start and rejects an already completed request. Both append lifecycle events whose payload contains agent_id and request_event_id; start/complete events are attributed to the supplied agent. The schema declares the ID as an integer with minimum 1. The handler converts numeric arguments through its integer helper before checking positivity and ownership; it does not independently reject fractional JSON numbers before conversion. Supply the exact positive integer returned by the request. These checks establish event consistency, not caller identity. Requests coordinate MCP turn ownership and do not launch or interrupt external agent processes. A scheduled but unfinished request blocks scheduling later requests indefinitely; there is no timeout, lease, cancellation, or stale-owner recovery. Completing the current request makes the next FIFO request eligible on a subsequent orchestrator tick, not synchronously in the completion tool call.
“Required” and “optional” below refer to the registry JSON schema except where runtime validation imposes an additional requirement, noted explicitly. An omitted optional property is not necessarily populated with a meaningful default.
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
table.get_state |
none | Returns runs, agents, tasks, claims, proposals, transactions, human_approvals, security_reviews, and memory from local state. It does not return votes or decisions in this response; use their dedicated tools/related proposal reads. |
table.watch |
none | run_id, limit; optional after_event_id enables cursor polling and returns next_after_event_id/has_more_events. Without a cursor, returns the recent event/transaction activity snapshot. It is not a blocking stream. |
agent.turn_request |
run_id, agent_id, reason_md |
Records a durable FIFO request; one outstanding request per agent. |
agent.turn_start |
run_id, agent_id, request_event_id |
Acknowledge only after the Chair emits a matching agent.turn_scheduled event. |
agent.turn_complete |
run_id, agent_id, request_event_id |
Call after the scheduled work finishes; the next FIFO request is then eligible for scheduling on the next orchestration tick. |
table.get_state and table.watch call the same sequential snapshot loader. It reads runs, agents, tasks, claims, proposals, transactions, approvals, security reviews, and memories with separate list queries, stopping at the first query/scan/iteration error. There is no encompassing read transaction, so concurrent writes can make the returned collections reflect different database moments. table.watch reads events separately after the snapshot; event IDs and projected counts therefore are not guaranteed to describe one consistent instant. Neither response should be treated as a transactionally frozen view for making a write decision.
table.watch normalizes limit <= 0 to 10 and caps values above 200. Without an after_event_id key, even if its value is zero, it returns the newest limited event window in ascending database-ID order, sets has_more_events false, and reports the last returned event ID as next_after_event_id (or zero when empty). This mode does not signal that older events were omitted. Supplying after_event_id selects cursor mode: negative values fail; events strictly greater than the cursor are returned ascending up to the limit, with one extra fetched to set has_more_events. The next cursor advances to the last returned ID and stays at the input cursor when no events are returned. If has_more_events is true, continue polling with that cursor until drained. Runtime numeric conversion truncates JSON floating-point values and defaults unconvertible types to zero; supply an exact nonnegative integer. Event cursor filtering applies to the selected run_id, while snapshot counts and record lists remain database-wide. Transactions are selected from the tail of the store’s list order, not filtered by run or sorted by applied time in this handler.
The returned projection includes events, next_after_event_id, has_more_events, transactions, blocked_tasks, pending_proposals, required_approvals, active_claims, suspended_claims, open_tasks, and active_agents, plus the supplied run_id. Status matches are exact strings: open-task count includes open, in_progress, and blocked; blocked tasks separately include exact blocked; pending proposals are pending or in_review; approvals are exact requested; agent count uses enabled flags rather than live sessions. Claims are counted by status without an expiry check. Lists include their full source records and may be empty arrays. The run filter scopes only events; it does not scope these state projections.
The registry schemas describe advertised fields; the local socket server dispatches parsed arguments directly to handlers without applying JSON Schema validation. Runtime checks, types, and defaults therefore determine the accepted behavior. Several handlers recognize extra ID/status fields not advertised in the registry; their detailed reference pages identify those implementation fields separately. Do not assume schema required alone establishes a server-side check or that unknown keys are rejected.
Most string helpers accept only actual JSON strings and default only for missing/empty values, not whitespace-only values. Numeric integer helpers accept JSON numbers and truncate floating-point values; string numbers fall back to defaults. Boolean helpers accept actual booleans, with other types falling back. Turn lifecycle handlers check that the converted request ID is positive; the schema requires an integer, so callers should supply an integer rather than relying on numeric truncation. See each tool’s behavior before constructing calls.
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
task.create |
title, body_md |
priority, risk, assigned_agent_id, readable_paths. The task creator defines the assigned agent’s repository path scope; it defaults to no readable paths and rejects credential/config locations. See Tasks and Assignments. |
task.get |
task_id |
Fetch one task. |
task.list |
none | Lists all local tasks ordered by priority, creation time, and ID; no run/workspace filter. |
task.update_status |
task_id |
Nonempty status/assigned_agent_id update those fields; empty values preserve them. See Tasks and Assignments. |
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
repo.read_file |
path |
Reads through the repository tool boundary; it is not a write API. |
repo.search |
query |
path narrows the search. |
repo.symbols |
none | Optional path, language; parser support/limitations are in Symbol Index. |
repo.dependency_context |
path |
Advertised only; no runtime handler. Calls fail with tool not implemented: repo.dependency_context. |
There is currently no local dependency-context parser, manifest discovery, lockfile resolution, transitive dependency graph, package-version lookup, or vulnerability scan behind repo.dependency_context. Supplying a valid manifest path does not change the result: the runtime reaches its unimplemented-tool fallback before any path inspection. The name remains in the internal registry for future implementation, but standard MCP discovery, mcp inspect, and generated tool schemas exclude it.
For current work, read known manifests and lockfiles using repo.read_file and inspect relevant imports with repo.search or repo.symbols. Those tools expose file content or declarations, not a resolved dependency graph. Clearly distinguish direct manifest declarations from lockfile-resolved versions and transitive dependencies in any agent summary. Do not infer installed packages, successful dependency resolution, compatibility, or security status merely from a manifest. External package-manager commands are separate operations with their own trust and execution boundaries; see Tests and Evidence.
repo.read_file requires a nonempty string path. Relative paths resolve against the runtime repository root, not the calling agent’s working directory. Absolute paths are accepted when the resolved target remains inside that root. The guard resolves the root’s symlinks, attempts to resolve the candidate’s symlinks, and rejects a resolved relative path equal to .. or beginning with ../ (using platform separators). If candidate symlink evaluation fails, it checks the unresolved absolute candidate instead; the subsequent file read may then fail. This is a path check, not an operating-system sandbox or protection against concurrent symlink replacement.
The response is {path, content}. Its path is the caller’s path with slash conversion, not necessarily the canonical path that was read. The entire file is read into memory and returned as a string; there is no line range, byte limit, pagination, binary-file filter, encoding detector, secret redaction, or ignore-file check. Hidden files inside the repository, including local configuration, are not excluded by this handler. Read failures return tool errors rather than an empty content value.
repo.search requires a nonempty string query. It lowercases both the query and each line and performs literal substring matching; it does not trim the query, interpret regular expressions/globs, rank results, or search across line boundaries. Whitespace-only queries are literal queries. Each matching line produces one result even if the substring occurs multiple times on that line.
With an explicit path, the same path guard used by file reads is applied and only that single path is read. A directory path is not recursively expanded: its read fails and is silently skipped, yielding no matches. Without path, the handler walks the repository tree and skips directories named .git or .roundtable at any depth. It does not honor .gitignore, exclude dependencies/build outputs, or filter by language, extension, hidden-file status, or binary content. Walk errors abort the operation; individual file-read errors are silently skipped.
Symlink limitation: the full-tree walk does not descend through directory symlinks, but collected file paths are read without reapplying the explicit-path guard. A file symlink within the tree can therefore expose content from outside the repository. Do not treat full-tree search as a secure read boundary in an untrusted checkout. Explicit-path checks also have a check/read race and are not a substitute for filesystem isolation.
The response is {matches: [...]} with each match containing a slash-normalized repository-relative path, one-based line, and original line content. Empty results may be JSON null, because the handler builds a nil slice until a match is found. There is no maximum result count, context-line option, output-size cap, or cancellation check inside the scan. Large dependency trees and files can consume substantial memory and produce large responses. Supply an explicit file path when possible and avoid publishing responses that may contain local secrets.
repo.symbols also uses the explicit-path guard, but its returned paths use the resolved indexer input rather than the caller’s path. Despite the advertised optional property, the handler requires path; see Symbol Index for parser and identifier details.
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
resource.claim |
resource_type, resource_id, claim_type, task_id |
ttl_seconds, rationale. Valid claim modes: read/write/review/exclusive. Claims do not grant reads outside the task’s operator-authored readable_paths. Agent capability calls ignore caller-provided claim IDs. |
resource.claim_status |
none | Filter by resource_id and/or agent_id; inspect active/suspended/expired state. |
resource.get |
resource_id |
Fetch resource metadata. |
resource.release |
claim_id |
Release a previously granted claim. |
resource.search |
query |
Optional resource_type. |
Conflict coverage and stale-claim rules are documented in Claims. Claim IDs/actor fields do not enforce operating-system access controls.
resource.get requires an actual nonempty string resource_id and performs an exact key lookup; it returns the complete stored resource record, including current hash and raw metadata JSON. It does not refresh hashes, validate that metadata matches the ID, check claims, or resolve the record’s path against the current repository. Missing rows and store errors are returned as tool errors.
resource.search lists every stored resource ordered by ID, then filters in memory. query must be a string to be used; missing, empty, or wrongly typed values become an empty query and match every resource. Nonempty query text is lowercased but not trimmed, and substring-matched case-insensitively against ID, type, path, symbol, and language. Current hash, metadata JSON, and claims are not searched. Optional resource_type is an exact, case-sensitive filter; a wrong-typed value is treated as omitted. Results retain ID order. There is no pagination, result cap, resource refresh, or filesystem discovery, and an empty match slice may encode as JSON null. Large resource tables can therefore produce large responses; use a selective query/type and do not treat a search result as current filesystem truth.
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
proposal.create |
task_id, agent_id, title, summary_md, affected_resources, risk, patch |
expected_tests, rollback_notes. The patch is stored for validation; affected resources must cover touched files. |
proposal.attach_patch |
proposal_id, patch |
Attaches/replaces the patch content. |
proposal.get |
proposal_id |
Fetch one proposal. |
proposal.list |
none | Filter with task_id and/or status. |
proposal.request_review |
proposal_id |
Requests relevant review records/agent work. |
vote.cast |
proposal_id, agent_id, vote, reason_md |
confidence, default 0. Requires an existing proposal but stores nonempty vote strings and caller-provided agent IDs without role authentication or an enum check. Policy counts its recognized vote strings; other values do not contribute. |
vote.list |
proposal_id |
List recorded votes. |
decision.record |
decision, rationale_md, decided_by |
Optional proposal_id, task_id. Persists a decision record. |
patch.validate |
proposal_id |
Reports claim, diff, resource coverage, temporary-apply, policy, human approval, and security-review results. |
patch.apply |
proposal_id |
Revalidates, checks gates, applies through the service, and records a transaction/rollback artifact. Not an ordinary agent write shortcut. |
patch.reject |
proposal_id, reason_md |
Rejects the proposal and records a decision. |
The exact apply flow and non-atomic failure boundaries are described in Proposals and Transactions.
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
human.request_approval |
subject, reason_md |
approval_id, proposal_id, task_id, requested_by, status, decision_md, decided_by, override_policy. Creates/replaces an approval record with caller-supplied decision fields. See Human Approvals for selection and identity limits. |
human.approval_status |
approval_id |
Returns persisted status. |
security.review |
At least one of proposal_id or resource_id at runtime |
Optional review_id, task_id, reviewer_id, status, summary_md. A proposal with omitted/empty status runs the automatic patch scan; supplying status records a manual review and skips scanning. A resource-only review with omitted status defaults to approved. See Security Reviews for fields, heuristics, selection order, and trust limits. |
See Test Execution and Evidence for suggestions, execution status, log persistence, and failure handling.
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
test.suggest |
none | Optional proposal_id, task_id; suggests test commands. |
test.evidence.submit |
proposal_id, command, outcome, summary_md |
Tester-only. Submits a bounded, proposal/session-attributed agent report with outcome passed, failed, or inconclusive. Stored with status reported; it is not host-verified test execution and cannot be represented as a trusted pass. |
test.run |
command |
Optional proposal_id, task_id; executes /bin/sh -lc in the repository root and persists output to .roundtable/testlogs/. The current guard checks the executable name against cargo, git, go, make, node, npm, pnpm, printf, pytest, ruby, swift, vitest, and yarn, and rejects selected shell-control characters (; | & > < backtick $ newline carriage-return). It does not fully inspect executable arguments or sandbox filesystem/network effects; an allowlisted command can still be misused. Only invoke reviewed, known read-only/test commands; this tool is not a security sandbox. |
test.get_result |
test_run_id |
Fetches a stored test run/result. A previous result is not proof the current patch has been tested. |
| Tool | Required arguments | Optional arguments / behavior |
|---|---|---|
memory.query |
query |
scope, kind, limit. Search durable project knowledge. |
memory.record |
scope, kind, title, body_md |
source_event_id, importance. Stores a durable memory entry. |
memory.summarize |
none | Scope by task_id, proposal_id, and/or scope. |
memory.mark_stale |
memory_id, reason_md |
Marks contradicted/outdated memory as stale; does not delete its history. |
roundtable init, roundtable run, and roundtable mcp inspect --write generate:
.roundtable/mcp/AGENT_MCP_MANIFEST.md
.roundtable/mcp/tools.schema.json
.roundtable/mcp/server.json
The manifest includes mandatory read-only/proposal rules, startup/resume checklist, and turn scheduling protocol. Generated files are derived artifacts; edit the registry and regenerate them rather than editing the generated copies.
Before acting, read table.get_state, query task-relevant memory, fetch the assigned task, and inspect relevant claim status. Read repository content through repo tools, claim affected resources, submit a patch proposal, and wait for review/governance results. Explicitly request/start/complete a turn when the coordinator is using the FIFO turn queue. Never treat free-form conversation or local CLI history as authoritative shared state.