MCP · 13. Tool reference, part 2
This is the complete contract for the remaining 49 of the daemon's 118 MCP tools. The first 70 are in chapter 12, whose section 12.0 defines every column used below and is worth reading first.
This chapter is reference.
Two things to know before you use anything here. Ten of these tools are advertised in tools/list but their daemon endpoints return 501 until the orchestrators and punchcards work ships, 13.14 and 13.15 say which. And 24 of the 49 tools in this chapter appear nowhere in the Crux repository's own agent documentation; this reference is their first published description. See chapter 15.
13.1 Coordination: projects, work kanban, live sessions
All nine tools proxy corecruxd over loopback with scope admin:read,facts:write (coordination.rs:18).
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
list_projects | mod.rs:1753 | coordination.rs:269 | [local] | - | , |
get_project_context | mod.rs:1758 | coordination.rs:275 | [local] | - | , |
list_work | mod.rs:1768 | coordination.rs:289 | [local] | - | ExecPlan projection needs CRUX_EXECPLANS_ROOT |
create_work | mod.rs:1785 | coordination.rs:306 | [local] | - | , |
update_work_state | mod.rs:1807 | coordination.rs:353 | [local] | - | , |
comment_on_work | mod.rs:1827 | coordination.rs:393 | [local] | - | , |
status_feed | mod.rs:1843 | coordination.rs:432 | [local] | - | CORECRUXD_FEATURE_STATUS_FEED, default off |
coord_status | mod.rs:1855 | coordination.rs:450 | [local] | - | CORECRUXD_COORD, default on |
coord_announce | mod.rs:1866 | coordination.rs:464 | [local] | - | CORECRUXD_COORD, default on |
CORECRUXD_COORD defaults on (config.rs:1336); only an explicit 0 or false disables it. The presence window is set by CORECRUXD_COORD_PRESENCE_TTL_SECS (config.rs:1337).
list_projects
No parameters. Output: {projects: [{id, name, planning_target?, default_passport_id, created_at_unix_ms}]}.
get_project_context
| Param | Type | Required |
|---|---|---|
project_id | string | yes |
Output: {id, name, planning_target?, default_passport_id, members: [{passport_id, role}], tenants: [{tenant_id, default_passport_id?}]}.
list_work
All four parameters are optional; a bare {} lists everything.
| Param | Type | Required | Constraints |
|---|---|---|---|
project_id | string | no | |
state | string | no | One of planned, in_progress, blocked, archive, complete, deployed |
tenant_id | string | no | |
assignee_passport | string | no |
Output: {count, work: [{id, project_id, state, title, body, assignee_passport?, tenant_id?, linked_pr?, linked_issue?, blocker_reason?, created_by_passport, created_at_unix_ms, updated_at_unix_ms}]}.
The response merges kanban rows with a read-time projection over ExecPlan markdown files, but only when CRUX_EXECPLANS_ROOT is set in the daemon's process environment (work_execplans.rs:58). Unset means no ExecPlan items, silently.
create_work
| Param | Type | Required | Constraints |
|---|---|---|---|
project_id | string | yes | Must be an existing project id. There is no implicit default project; an unknown id returns "project not found" |
title | string | yes | |
created_by_passport | string | yes | Typically your bound session passport |
body | string | no | |
state | string | no | The same six-value set as list_work; defaults to planned |
assignee_passport | string | no | Defaults to the current passport |
tenant_id | string | no | |
linked_pr | string | no | |
linked_issue | string | no |
Output: the created work item.
update_work_state
| Param | Type | Required | Constraints |
|---|---|---|---|
work_id | string | yes | |
state | string | yes | The same six-value set |
by_passport | string | yes | |
blocker_reason | string | no | Required when transitioning to blocked, enforced server-side, not by the schema |
blocker_kind | string | no | needs_info or needs_approval; defaults to needs_info on a blocked transition |
Output: {applied, work?, queued?} where queued is {action_id, work_id, requested_by_passport, target_state, status: 'pending', requested_at_unix_ms}.
If the caller's passport has agent_work_gate = true, the move queues for human approval (HTTP 202) instead of applying. Check applied, a false there is not an error.
comment_on_work
| Param | Type | Required |
|---|---|---|
work_id | string | yes |
author_passport | string | yes |
body | string | yes |
Output: {id, work_id, author_passport, body, posted_at_unix_ms}.
status_feed
A glance feed in six verbs: CLAIMED, BLOCKED, HUMAN_HOLD, RESUMED, DONE, FAILED. Read-only.
| Param | Type | Required | Default |
|---|---|---|---|
work_id | string | no | , omit for all items |
limit | integer | no | 200, most recent kept |
Output: {enabled, events: [{work_id, verb, transition_id, from_state, to_state, by_passport, at_unix_ms}], note?}.
With CORECRUXD_FEATURE_STATUS_FEED unset it returns a disabled notice rather than an error (status_feed.rs:40); check enabled.
coord_status
Who is live right now, and what each session is doing.
| Param | Type | Required | Notes |
|---|---|---|---|
project_id | string | no | Sessions bound to no project are always included |
Output: {now_unix_ms, presence_ttl_secs, project_id?, active_sessions: [{session_id_hex, passport_id, tenant_id, project_id?, bound_at_unix_ms, last_seen_at_unix_ms, active_until_unix_ms, intent?, leases?}], work_in_flight: [WorkItem]}. An intent is {execplan_slug?, milestone?, paths, note?, announced_at_unix_ms, expires_at_unix_ms}; a lease is {punchcard_id, resource, mode, holder_passport, expires_at_unix_ms}.
coord_announce
Declares this session's focus. A re-announce replaces the previous declaration.
| Param | Type | Required | Default | Constraints |
|---|---|---|---|---|
session_id | string | yes | - | Your bound session id in hex, as minted by cuecrux_session |
project_id | string | yes | - | |
by_passport | string | no | - | The session binding's passport wins when the session is bound |
execplan_slug | string | no | - | |
milestone | string | no | - | |
deploy_target | string | no | - | For example deploy:crux. A live peer on the same target produces a deploy_target warning in overlaps[] |
paths | array<string> | no | - | Repo-relative files or directories. Informational only, use punch_in for an enforceable lease |
note | string | no | - | |
ttl_seconds | integer | no | 14400, four hours | Maximum 86400. 0 clears the intent |
Output: {intent, cleared, live_peer_intents, overlaps: [{peer_session_id_hex, peer_passport_id, kind, theirs, yours}]}. kind is execplan, deploy_target, intent_path or lease.
The intent is stored as a private fact attributed to the session's passport. Everything here is advisory. Overlaps never block. The only enforcement seam in the coordination plane is check_punchcard, 13.15.
13.2 GitHub indexed corpus
Loopback scope admin:read (github.rs:16). These tools read a corpus populated by repositories selected through /v1/integrations/github/repos.
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
github_search | mod.rs:1891 | github.rs:136 | [local] | - | none |
github_recent_commits | mod.rs:1908 | github.rs:154 | [local] | - | none |
github_open_prs | mod.rs:1921 | github.rs:170 | [local] | - | none |
github_open_issues | mod.rs:1934 | github.rs:195 | [local] | - | none |
github_comments_since | mod.rs:1948 | github.rs:237 | [local] | - | none |
None of the five has a feature flag. tools/github.rs contains zero environment reads. They are always listed and always callable, and simply return empty results when nothing has been indexed. Their only precondition is a configured daemon_base_url (github.rs:33). What populates the corpus is separately gated by CORECRUXD_INTEGRATIONS_ENABLED, which defaults on (config.rs:1377).
| Tool | Param | Type | Required | Default |
|---|---|---|---|---|
github_search | query | string | yes | - |
repo | string | no | , an owner/repo filter | |
top_k | integer | no | 20 | |
github_recent_commits | repo | string | yes | - |
limit | integer | no | 20 | |
github_open_prs | repo | string | yes | - |
limit | integer | no | 20 | |
github_open_issues | repo | string | yes | - |
label | string | no | , exact match | |
limit | integer | no | 20 | |
github_comments_since | limit | integer | no | 50 |
github_comments_since takes no since parameter despite its name. limit is its only parameter. It is "recent comments across selected repos", ordered newest first.
All five return {count, facts: [Fact]}. The value strings hold JSON-encoded records, and the entity prefix tells you which.
| Tool | Entity form | Fields in the value JSON |
|---|---|---|
github_recent_commits | github::owner/repo::commit/{sha} | sha, message, author_name, author_login?, committed_at, parents[], html_url |
github_open_prs | github::owner/repo::pr/{number} | title, state, author_login?, head_sha, base_branch, body, merged_at?, closed_at?, html_url |
github_open_issues | github::owner/repo::issue/{number} | title, state, labels[], body, closed_at?, html_url |
github_comments_since | github::owner/repo::comment/{id} | author_login?, body, posted_at, parent_number, html_url |
github_search | any of the above | Commit, PR, issue or comment record, by prefix |
13.3 Workspace storyline and repo registration
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
get_workspace_storyline | mod.rs:1960 | storyline.rs:55 | [local] | - | , |
register_repo | mod.rs:1965 | repos.rs:168 | [local] | - | , |
list_repos | mod.rs:1970 | repos.rs:198 | [local] | - | , |
get_workspace_storyline
Per-endpoint call tree from the latest workspace scan. It requires a scan to have been run first, via POST /v1/workspace/scan. Without one there is nothing to return.
| Param | Type | Required | Default | Constraints |
|---|---|---|---|---|
endpoint | string | no | - | A 'METHOD PATH' filter, for example 'POST /v1/projects'. Omit for every route |
format | string | no | tree | tree or json. Validated in the handler (storyline.rs:55); anything else returns INVALID_PARAMS |
include_tests | boolean | no | false | Include edges pointing at test files. Off by default because test code skews density metrics |
Output with format=tree: plaintext ASCII tree art as text/plain. With format=json: {files: [{p, c, m, d, f, t}], edges: [[from_id, to_id, count, to_symbol]], routes: [{m, p, h, f, chain: [file_ids]}]}.
register_repo
| Param | Type | Required | Default | Notes |
|---|---|---|---|---|
tenant_id | string | yes | - | Owner of the registration |
repo_id | string | no | a slug derived from root_path or clone_url | |
root_path | string | no | - | Local absolute path. Scanned immediately, and sets last_scan_id |
clone_url | string | no | - | Recorded without cloning; the scan is deferred |
languages | array<string> | no | [] |
Output, proxied from POST /v1/repos: {repo_id, tenant_id, root_path?, clone_url?, languages: [string], enabled, added_at_unix_ms, last_scan_id?}.
list_repos
| Param | Type | Required |
|---|---|---|
tenant_id | string | yes |
Output, proxied from GET /v1/repos: {repos: [{repo_id, tenant_id, root_path?, clone_url?, languages, enabled, last_scan_id?}]}, scoped to the caller's tenant.
13.4 Substrate: entities
Banner: "Substrate: entities / edges / kinds" (mod.rs:1974). No feature flag gates any substrate tool.
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
entity_upsert | mod.rs:1976 | entities.rs:31 | [local] | - | , |
entity_get | mod.rs:1993 | entities.rs:66 | [local] | - | , |
entity_list | mod.rs:2007 | entities.rs:88 | [local] | - | , |
entity_delete | mod.rs:2020 | entities.rs:115 | [local] | - | , |
entity_history | mod.rs:2033 | entities.rs:103 | [local] | - | , |
| Tool | Param | Type | Required | Default | Constraints |
|---|---|---|---|---|---|
entity_upsert | kind | string | yes | - | Must be a registered kind; lens crates register kinds at startup |
id | string | yes | - | Entity id within its kind | |
payload | object | yes | - | Validated against the kind's JSON-Schema | |
entity_get | kind | string | yes | - | |
id | string | yes | - | ||
include_deleted | boolean | no | false | ||
entity_list | kind | string | no | - | Omit for all kinds |
limit | integer | no | - | No documented cap | |
include_deleted | boolean | no | false | ||
entity_delete | kind | string | yes | - | Soft delete; the version chain is preserved |
id | string | yes | - | ||
entity_history | kind | string | yes | - | |
id | string | yes | - |
Outputs, all inside content: entity_upsert and entity_delete return {entity}; entity_get returns {entity} which may be null; entity_list returns {entities, count} sorted by kind then id; entity_history returns {versions, count} oldest first, where the last entry has deleted: true if the entity was deleted.
An entity record is {kind, id, payload, created_at, updated_at, version, deleted, actor}.
13.5 Substrate: edges
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
edge_upsert | mod.rs:2046 | edges.rs:33 | [local] | - | , |
edge_get | mod.rs:2063 | edges.rs:55 | [local] | - | , |
edge_list | mod.rs:2079 | edges.rs:69 | [local] | - | , |
edge_delete | mod.rs:2096 | edges.rs:88 | [local] | - | , |
edge_upsert, edge_get and edge_delete take the full five-tuple, all five required: from_kind, from_id, edge_kind, to_kind, to_id, all strings. edge_upsert additionally accepts an optional payload object.
edge_list takes any prefix of the tuple; every parameter is optional.
| Param | Type | Required | Default |
|---|---|---|---|
from_kind | string | no | - |
from_id | string | no | - |
to_kind | string | no | - |
to_id | string | no | - |
edge_kind | string | no | - |
limit | integer | no | - |
include_deleted | boolean | no | false |
Outputs: edge_upsert and edge_delete return {edge}; edge_get returns {edge} which may be null; edge_list returns {edges, count}.
An edge record is {edge_id, from_kind, from_id, edge_kind, to_kind, to_id, payload, created_at, updated_at, version, deleted, actor}.
13.6 Features lens
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
feature_file_search | mod.rs:2113 | features.rs:29 | [local] | - | none |
feature_coverage_report | mod.rs:2123 | features.rs:62 | [local] | - | none |
feature_trigger_audit | mod.rs:2128 | features.rs:74 | [local] | - | none |
feature_suggest_next | mod.rs:2143 | features.rs:144 | [local] | - | none |
tools/features.rs reads no environment variables. All four are always available.
| Tool | Param | Type | Required | Default | Constraints |
|---|---|---|---|---|---|
feature_file_search | path | string | yes | - | Substring-matched against each capability's files list |
feature_coverage_report | none | ||||
feature_trigger_audit | id | string | yes | - | Capability id |
status | string | yes | - | One of audited, gap, waived, blocked | |
auditor | string | no | - | ||
notes | string | no | - | ||
feature_suggest_next | limit | integer | no | 5 |
Outputs: feature_file_search returns {capabilities: [{id, name, system, files}], count}; feature_coverage_report returns {report} where the report holds total_capabilities, total_tested, total_audited, maturity and systems; feature_trigger_audit returns {capability, version} where capability is the updated payload; feature_suggest_next returns {suggestions: [{kind, capability_id?, gap_type?, severity?, promise?, rationale}], count}, derived from gap analysis and the weakest promise.
13.7 Substrate: kinds
Physically these two sit after the features tools, under the Features lens banner (mod.rs:2111), though they belong to the substrate.
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
kind_list | mod.rs:2152 | kinds.rs:16 | [local] | - | , |
kind_get | mod.rs:2157 | kinds.rs:37 | [local] | - | , |
kind_list, no parameters. Output: {kinds: [{kind, description, allowed_outgoing_edges, allowed_incoming_edges}], count}.
kind_get, kind (string, required). Output: {registration}, which may be null, and which includes the kind's JSON-Schema.
13.8 Typed action traces
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
tool_trace_recent | mod.rs:2168 | tools/traces.rs:73 | [local] | default 2000 | CORECRUXD_FEATURE_TOOL_TRACES, default on |
Per-passport. Reserved-prefix effects are stripped. Schema at tools/traces.rs:42.
| Param | Type | Required | Default | Source |
|---|---|---|---|---|
turn_id | string | no | - | Only traces tagged with this turn |
top_k | integer | no | 50 | DEFAULT_TOP_K, tools/traces.rs:36 |
token_budget | integer | no | 2000 | DEFAULT_TOKEN_BUDGET, tools/traces.rs:40 |
Output: {content, traces: [{tool, ts_us, turn_id?, predicted_effects: [{kind, entity, key, ts_us?}], outcome}], count, feature_disabled?}.
This is the cleanest token_budget contract in the crate: the default is a named constant, declared in the schema, and applied in the handler at tools/traces.rs:78.
Flag default is on, Err(_) => true at traces.rs:80. Trace retention is CORECRUXD_FEATURE_TOOL_TRACES_TTL_SECS, default 3600 (traces.rs:53). With the flag off the tool returns {traces: [], count: 0, feature_disabled: true} rather than an error.
13.9 Session mining and loop weighting
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
learn | mod.rs:2174 | tools/learn.rs:60 | [local] | - | CORECRUXD_FEATURE_TOOL_TRACES, default on, the same flag as its data source |
Mines the calling passport's recent traces for looping re-fetches, a signature repeated three or more times, with pagination variants folded together, and proposes guardrails ranked by measured token waste. Read-only and propose-only: it writes nothing.
| Param | Type | Required | Default | Constraints |
|---|---|---|---|---|
min_repeats | integer | no | 3 | minimum: 2; values below 2 are rejected in the handler |
scan | integer | no | 1000: DEFAULT_SCAN at tools/learn.rs:33 | How many recent traces to mine, newest first |
Output: {content, proposals: [{signature, occurrences, wasted_tokens, draft_guardrail}], count, scanned, propose_only: true, feature_disabled?}.
learn has no token_budget despite being a scan-shaped tool. It is bounded by scan instead.
13.10 Holdout savings
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
token_savings | mod.rs:2180 | token_savings.rs:32 | [local] | - | CRUX_OUTPUT_HOLDOUT, a numeric fraction; 0 is off and is the default |
No parameters at all, the schema is {"type":"object","properties":{},"examples":[{}]} (token_savings.rs:21).
Output: {content, holdout_enabled, holdout_fraction?, n_control, n_treatment, reduction_pct, ci95_low_pct, ci95_high_pct, control_tokens, treatment_tokens}.
It reports live shaped-versus-unshaped token saving as a point estimate with a 95% confidence interval, never a bare counterfactual. With CRUX_OUTPUT_HOLDOUT at or below zero there is no live control arm, so the tool returns a disabled stub carrying the literal hint set CRUX_OUTPUT_HOLDOUT=0.05 to sample a live control arm (token_savings.rs:35).
The flag is a float clamped to the range 0 to 1 (holdout.rs:38). Setting it also forces the unshaped path in query (query.rs:98) and query_facts (facts.rs:471) for the sampled fraction; it is a live experiment, not a report.
13.11 Activity log
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
activity_recent | mod.rs:2186 | tools/activity.rs:81 | [local] | default 500 | CORECRUXD_FEATURE_ACTIVITY_LOG, default off (daemon-side) |
Loopback scope facts:read (tools/activity.rs:37). A cheap "what just happened in this session" pull across the activity categories.
| Param | Type | Required | Default | Constraints |
|---|---|---|---|---|
session_id | string | yes | - | |
tenant_id | string | no | default | |
since | string | no | - | Return only entries with a seq greater than this, exclusive |
kinds | array<string> | no | - | question, answer, reasoning, command, fact, execplan, handoff, error. Also accepts a comma-separated string, despite the schema declaring type: array |
token_budget | integer | no | 500 | Caps response size. An explicit 0 also falls back to 500 (tools/activity.rs:116) |
Output: {content, session_id, tenant_id, feature_enabled, token_budget, returned, truncated, rows: [{turn_id?, seq, ts, kind, intent?, tool?, confidence?, fact_refs, receipt_ids, preview}]}, newest first, reserved-prefix stripped, privacy-scoped, budget-trimmed.
The gate is daemon-side (activity.rs:58); MCP maps the resulting HTTP 404 to feature_enabled: false rather than an error (tools/activity.rs:137). Retention is CORECRUXD_FEATURE_ACTIVITY_LOG_TTL_SECS, default 365 days (activity.rs:68).
The tool description at mod.rs:2189 claims "Required: session_id, token_budget". Only session_id is required. The budget defaults to 500.
To dereference a turn to verbatim content, use the daemon's /v1/activity/turn/{turn_id} HTTP route. It is not exposed as an MCP tool.
13.12 Token accounting
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
session_token_usage | mod.rs:2216 | token_usage.rs:42 | [local] | ignored | - |
| Param | Type | Required | Default | Notes |
|---|---|---|---|---|
token_budget | integer | no | 500 in the schema | The payload is fixed size, so any positive integer is fine. The handler signature ignores its arguments entirely (token_usage.rs:42), the parameter is accepted for conformance and discarded |
Output: {content, passport, used, tokens_in, tokens_out, declared_budget_in, calls, estimator, limit?, pct?}.
used is the sum of estimated argument and result tokens across every tools/call this daemon process has dispatched for the passport, at roughly four characters per token. It is comparable, not exact, and it resets when the process restarts. limit comes from CORECRUXD_SESSION_TOKEN_BUDGET; unset or 0 means no limit and pct is omitted. Unauthenticated callers accumulate under the __anon__ sentinel.
CORECRUXD_SESSION_TOKEN_BUDGET is report-only. Exceeding it neither fails nor truncates anything; it only makes pct exceed 100.
13.13 Risk-tiered human-in-the-loop approvals
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
approval_request | mod.rs:2222 | approvals.rs:231 | [local] | required | CORECRUXD_FEATURE_APPROVAL_QUEUE, default off |
approval_decide | mod.rs:2268 | approvals.rs:375 | [local] | - | same |
Slack notification, when configured, is CORECRUXD_APPROVALS_SLACK_WEBHOOK_URL (approvals.rs:191).
approval_request
| Param | Type | Required | Default | Constraints |
|---|---|---|---|---|
action_summary | string | yes | - | |
risk_tier | string | yes | - | One of low, medium, high |
scope | string | yes | - | Tenant id or scoped resource path |
token_budget | integer | yes | - | Any positive integer. The check is presence only, so 0 passes |
tenant_id | string | no | the value of scope | |
payload | object | no | - | For example predicted effects, or the original tool call |
Output: {content, request_id, status, risk_tier, tenant_id, feature_enabled}. status is pending or feature_disabled.
It returns immediately. High-tier requests block on an operator decision; medium and low may auto-approve per tenant policy. Pending entries appear in list_work(state='pending_approval').
Ordering quirk worth knowing at 3am: the token_budget presence check runs at approvals.rs:279, before the feature-flag check at :317. A call against a disabled feature that omits token_budget reports the missing budget, not the disabled feature. The error is real but it is not the reason nothing happened.
approval_decide
Requires an operator-tier passport. Forwards through the cross-tenant guard: a reviewer in tenant A cannot decide for tenant B.
| Param | Type | Required | Constraints |
|---|---|---|---|
request_id | string | yes | Minted by approval_request |
decision | string | yes | approve or reject |
reviewer_notes | string | no | Embedded in the receipt body |
reviewer_tier | string | no | Intended to be stamped by the daemon HTTP layer. Tests pass elite or operator |
reviewer_tenant_id | string | no | Used to enforce the cross-tenant guard |
Output: {content, ok, request_id, status, reviewer_passport, decided_at, receipt_id, receipt_body_hash_hex, tenant_id, risk_tier}. status is approved or rejected. Emits an ApprovalDecision CROWN receipt; the daemon HTTP layer attaches the Ed25519 signature. Non-operator callers receive a 403-style JSON-RPC error carrying why_denied.
Disclosure: reviewer_tier and reviewer_tenant_id are caller-supplied strings in the MCP schema even though they are meant to be stamped by the daemon HTTP layer. An MCP caller can set them directly. The authorisation decision is made downstream at approvals.rs:375; do not treat the MCP-side values as trusted.
13.14 Orchestrators (Package S scaffold)
Status: SCAFFOLD. Every daemon endpoint behind these five tools is stubbed and returns 501 until the orchestrators work ships (mod.rs:2837). They are advertised in
tools/listregardless. Calling one is not an error you can fix by configuring anything.
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
create_orchestrator | mod.rs:2250 | orchestrators.rs:52 | [local] | - | CORECRUXD_ORCHESTRATORS, default off |
attach_to_orchestrator | mod.rs:2294 | orchestrators.rs:69 | [local] | - | same |
detach_from_orchestrator | mod.rs:2311 | orchestrators.rs:89 | [local] | - | same |
list_orchestrators | mod.rs:2326 | orchestrators.rs:98 | [local] | - | same |
update_orchestrator | mod.rs:2338 | orchestrators.rs:115 | [local] | - | same |
CORECRUXD_ORCHESTRATORS is read at agentgraph_kinds.rs:144; the route class is at route_auth.rs:527. It uses parsing dialect 5, which accepts on, see 15.1.
| Tool | Param | Type | Required | Constraints |
|---|---|---|---|---|
create_orchestrator | name | string | yes | |
created_by_passport | string | yes | ||
assignee_passport | string | no | ||
tenant_id | string | no | ||
state | string | no | One of planned, active, done, archived | |
attach_to_orchestrator | orchestrator_id | string | yes | |
member_ref | string | yes | A work item (w_…), an execplan (execplan:…), a handoff (ho_…), or a passport | |
member_type | string | no | One of passport, work, execplan, handoff; inferred from member_ref when omitted | |
detach_from_orchestrator | orchestrator_id | string | yes | |
member_ref | string | yes | ||
list_orchestrators | tenant_id | string | no | |
state | string | no | The same four-value set | |
update_orchestrator | orchestrator_id | string | yes | |
name | string | no | ||
assignee_passport | string | no | ||
state | string | no | The same four-value set; archived closes it out |
An orchestrator record is {id, name, assignee_passport, created_by_passport, tenant_id, state, members[], created_at_unix_ms, updated_at_unix_ms}. list_orchestrators returns {count, orchestrators}.
13.15 Punchcards (Package S scaffold)
Status: MIXED.
punch_in,punch_outandlist_punchcardsare documented as 501-until-shipped scaffolds (mod.rs:2842).check_punchcardis live, and is the tool the PreToolUse hook calls before every edit.
| Tool | Definition | Handler | Surface | token_budget | Flag |
|---|---|---|---|---|---|
punch_in | mod.rs:2356 | punchcards.rs:53 | [local] | - | CORECRUXD_PUNCHCARD, default off |
punch_out | mod.rs:2375 | punchcards.rs:76 | [local] | - | same |
list_punchcards | mod.rs:2392 | punchcards.rs:99 | [local] | - | same |
force_release | mod.rs:2406 | punchcards.rs:116 | [local] | - | same |
check_punchcard | mod.rs:2423 | punchcards.rs:142 | [local] | - | same |
CORECRUXD_PUNCHCARD is a mode enum, advisory or enforce, off by default (agentgraph_kinds.rs:159). enforce is what makes check_punchcard blocking. Route at punchcards.rs:75.
| Tool | Param | Type | Required | Constraints |
|---|---|---|---|---|
punch_in | resource | string | yes | file://<path> or a deploy-target id |
holder_passport | string | yes | ||
mode | string | no | modify or deploy | |
tenant_id | string | no | ||
reason | string | no | ||
expires_at_unix_ms | integer | no | ||
punch_out | resource | string | yes | |
holder_passport | string | yes | ||
release_commit_sha | string | no | ||
tenant_id | string | no | ||
list_punchcards | resource | string | no | |
holder_passport | string | no | ||
tenant_id | string | no | ||
status | string | no | One of held, released, expired, force_released | |
force_release | punchcard_id | string | yes | |
confirm | boolean | yes | Must be true. Force-release is destructive and this is the deliberate friction | |
reason | string | no | ||
by_passport | string | no | The operator passport performing the override | |
check_punchcard | resource | string | yes | file://<path>, tree://<subtree> or service://<name> |
mode | string | no | modify or deploy | |
passport | string | no | The probing passport; defaults to the calling passport |
Outputs: punch_in returns {id, resource, mode, holder_passport, tenant_id, status, acquired_at_unix_ms, expires_at_unix_ms?, receipt_acquire}; punch_out returns the released record with released_at_unix_ms, release_commit_sha? and receipt_release; list_punchcards returns {count, punchcards}; force_release returns the force-released record with force_released_by and receipt_release.
check_punchcard returns {held_by_other, enforce, holder_passport, resource, mode, expires_at_unix_ms}. It always returns 200 and fails open; the PreToolUse hook denies only when held_by_other and enforce are both true. This is the enforcement seam for the whole coordination plane; everything in 13.1 is advisory by comparison.
One schema inconsistency: punch_in's own schema example (mod.rs:2361) shows only the file:// scheme, while tree:// is documented on check_punchcard (mod.rs:2428). tree:// works on both.
Sources
- crates/crux-mcp/src/tools/mod.rs:1751, the Coordination banner, where this chapter's range starts
- crates/crux-mcp/src/tools/mod.rs:2728,
tool_output_docs, the output contract - crates/crux-mcp/src/tools/coordination.rs:18, coordination loopback scope
- crates/crux-mcp/src/tools/github.rs:16, GitHub loopback scope
- crates/corecruxd/src/agentgraph_kinds.rs:139, observe, orchestrator and punchcard flags
All line references were verified at commit 93b41a7.

