Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Parity

Everything the CLI can do can be done from a plugin, can be done over /v1, can be done from MCP.

That is a claim, and this file is generated from the four declarations it is about, so it cannot describe a surface that does not exist or leave one out. Each direction is also held by a test:

DirectionHeld by
every /v1 route has an operation, and every operation a routeTestEveryDaemonRouteIsDeclared, TestEveryDeclaredOpHasARoute
every operation that is not a stream has an MCP toolTestEveryNonStreamingOpIsReachableAsAnMCPTool
every operation has a CLI command, and the generated ones reach their routeTestEveryOperationIsReachableFromTheCLI, TestEveryGeneratedCommandReachesItsRoute
every command the binary runs is declared, and every declared one runsTestEveryDispatchedCommandIsDeclared
every command reaches an operation, or says why it cannotTestEveryCommandReachesAnOperationOrSaysWhy
every operation has a plugin method, and they work against a real daemonTestPluginOpsAreGenerated, TestThePluginSuiteRunsAgainstARealDaemon
this fileTestParityDocumentIsCurrent

A command marked generated is built from the operation’s declaration – flags from its parameters, positionals for its path – so it exists the moment the operation does. The plugin reaches every operation through DaemonClient.ops (plugin/opencode/mcpx/ops.gen.ts, generated the same way); the named methods beside it are conveniences with typed answers.

Privileged operations are offered rather than hidden. A caller that can reach the socket can already stop the daemon, so withholding the tool buys no safety and costs an agent the ability to restart a server that has wedged. What they carry instead is a description that says so and MCP annotations (readOnlyHint, destructiveHint) for a client that wants to scope on them.

/v1 operations (83)

OperationRouteCLIMCP toolPluginNotes
adapters_addPOST /v1/adaptersmcpx adapter addmcpx_adapters_addops.adaptersAdd()Privileged.
adapters_removeDELETE /v1/adapters/{name}mcpx adapter removemcpx_adapters_removeops.adaptersRemove()Privileged. Destructive.
artifacts_listGET /v1/artifactsmcpx artifact list generatedmcpx_artifacts_listops.artifactsList()
artifact_putPOST /v1/artifactsmcpx artifact put generatedmcpx_artifact_putops.artifactPut()Privileged.
artifact_deleteDELETE /v1/artifacts/{id}mcpx artifact delete generatedmcpx_artifact_deleteops.artifactDelete()Privileged. Destructive.
artifact_getGET /v1/artifacts/{id}mcpx artifact get generatedmcpx_artifact_getops.artifactGet()
ask_beginPOST /v1/askmcpx ask begin generatedmcpx_ask_beginops.askBegin()
ask_pollGET /v1/ask/{id}mcpx ask poll generatedmcpx_ask_pollops.askPoll()
ask_abandonPOST /v1/ask/{id}/abandonmcpx ask abandon generatedmcpx_ask_abandonops.askAbandon()Privileged. Destructive.
ask_answersPOST /v1/ask/{id}/answersmcpx ask answers generatedmcpx_ask_answersops.askAnswers()Privileged.
batchPOST /v1/batchmcpx batchmcpx_batchops.batch()
callPOST /v1/callmcpx callmcpx_callops.call(), call(), callAsTask()
call_pathPOST /v1/call/{server}/{tool}mcpx callmcpx_callops.callPath()
catalogGET /v1/catalogmcpx catalogmcpx_catalogops.catalog()
catalog_historyGET /v1/catalog/historymcpx history generatedmcpx_catalog_historyops.catalogHistory()
chat_completionsPOST /v1/chat/completionsmcpx proxymcpx_chat_completionsops.chatCompletions()
client_moduleGET /v1/client.tsmcpx clientmcpx_client_moduleops.clientModule()
completePOST /v1/completemcpx complete generatedmcpx_completeops.complete(), complete()
daemon_restartPOST /v1/daemon/restartmcpx restartmcpx_daemon_restartops.daemonRestart()Privileged. Destructive.
dashboardGET /v1/dashboardmcpx dashboardmcpx_dashboardops.dashboard()
diagnosePOST /v1/diagnosemcpx diagnosemcpx_diagnoseops.diagnose()
elicit_listGET /v1/elicitmcpx elicit listmcpx_elicit_listops.elicitList(), pendingElicitations()
elicit_getGET /v1/elicit/{id}mcpx elicit showmcpx_elicit_getops.elicitGet()
elicit_answerPOST /v1/elicit/{id}/{action}mcpx elicit answermcpx_elicit_answerops.elicitAnswer(), answer()Privileged.
embeddingsPOST /v1/embeddingsmcpx embeddingsmcpx_embeddingsops.embeddings()
embeddings_exportGET /v1/embeddings/exportmcpx embeddings exportmcpx_embeddings_exportops.embeddingsExport()
embeddings_importPOST /v1/embeddings/importmcpx embeddings importmcpx_embeddings_importops.embeddingsImport()
eventsGET /v1/eventsmcpx events generatednone: a stream; MCP carries it as subscriptions/listenops.events()Never ends; read it until you are done.
execPOST /v1/execmcpx execmcpx_execops.exec(), exec()Privileged.
feedbackPOST /v1/feedbackmcpx feedbackmcpx_feedbackops.feedback()
globalsGET /v1/globals.d.tsmcpx globals generatedmcpx_globalsops.globals()
healthGET /v1/healthmcpx health generatedmcpx_healthops.health(), health()
intentPOST /v1/intentmcpx promptmcpx_intentops.intent()
interactions_listGET /v1/interactionsmcpx interactionsmcpx_interactions_listops.interactionsList()
interactions_getGET /v1/interactions/{id}mcpx interactions showmcpx_interactions_getops.interactionsGet()
log_queryGET /v1/logmcpx logmcpx_log_queryops.logQuery(), logQuery()
log_recordPOST /v1/logmcpx log recordmcpx_log_recordops.logRecord(), record()Privileged.
metrics_tokensGET /v1/metrics/tokensmcpx metrics tokens generatedmcpx_metrics_tokensops.metricsTokens()
metrics_toolsGET /v1/metrics/toolsmcpx metrics tools generatedmcpx_metrics_toolsops.metricsTools()
namespacesGET /v1/namespacesmcpx lsmcpx_namespacesops.namespaces(), namespaces()
openapiGET /v1/openapi.jsonmcpx openapimcpx_openapiops.openapi()
preflightPOST /v1/preflightmcpx preflight generatedmcpx_preflightops.preflight()
prompt_getPOST /v1/promptmcpx promptsmcpx_prompt_getops.promptGet()
promptsGET /v1/promptsmcpx promptsmcpx_promptsops.prompts()
protocolGET /v1/protocolmcpx protocol generatedmcpx_protocolops.protocol()
recipes_listGET /v1/recipesmcpx recipes listmcpx_recipes_listops.recipesList()
recipe_getGET /v1/recipes/{name}mcpx recipes showmcpx_recipe_getops.recipeGet()
recipe_savePOST /v1/recipes/{name}mcpx recipes savemcpx_recipe_saveops.recipeSave()
recipe_runPOST /v1/recipes/{name}/runmcpx recipes runmcpx_recipe_runops.recipeRun()
refreshPOST /v1/refreshmcpx refreshmcpx_refreshops.refresh()Privileged.
registry_searchGET /v1/registry/searchmcpx registry searchmcpx_registry_searchops.registrySearch(), registrySearch()
reloadPOST /v1/reloadmcpx reloadmcpx_reloadops.reload()Privileged.
resolveGET /v1/resolvemcpx resolve generatedmcpx_resolveops.resolve(), resolve()
resource_readPOST /v1/resourcemcpx resourcesmcpx_resource_readops.resourceRead()
resource_templatesGET /v1/resource-templatesmcpx resources --templatesmcpx_resource_templatesops.resourceTemplates()
resourcesGET /v1/resourcesmcpx resourcesmcpx_resourcesops.resources()
restartPOST /v1/restartmcpx restartmcpx_restartops.restart()Privileged. Destructive.
searchGET /v1/searchmcpx searchmcpx_searchops.search()
secret_requests_listGET /v1/secret-requestsmcpx secrets requestsmcpx_secret_requests_listops.secretRequestsList()
secret_request_declineDELETE /v1/secret-requests/{id}mcpx secrets declinemcpx_secret_request_declineops.secretRequestDecline()Privileged.
secret_request_getGET /v1/secret-requests/{id}mcpx secrets requestmcpx_secret_request_getops.secretRequestGet()
secrets_listGET /v1/secretsmcpx secrets listmcpx_secrets_listops.secretsList()
secrets_unsetDELETE /v1/secrets/{name}mcpx secrets unsetmcpx_secrets_unsetops.secretsUnset()Privileged. Destructive.
secrets_setPUT /v1/secrets/{name}mcpx secrets setnone: a value sent as a tool argument would sit in the model’s context and transcript; the CLI reads it from standard input and OpenChamber from a password fieldops.secretsSet()Privileged.
servers_listGET /v1/serversmcpx servers listmcpx_servers_listops.serversList()
servers_addPOST /v1/serversmcpx servers addmcpx_servers_addops.serversAdd()Privileged.
servers_removeDELETE /v1/servers/{name}mcpx servers removemcpx_servers_removeops.serversRemove()Privileged. Destructive.
servers_getGET /v1/servers/{name}mcpx servers showmcpx_servers_getops.serversGet()
session_releasePOST /v1/session/releasemcpx session release generatedmcpx_session_releaseops.sessionRelease()Privileged.
settings_listGET /v1/settingsmcpx settings listmcpx_settings_listops.settingsList()
settings_unsetDELETE /v1/settings/{path}mcpx settings unsetmcpx_settings_unsetops.settingsUnset()Privileged.
settings_getGET /v1/settings/{path}mcpx settings getmcpx_settings_getops.settingsGet()
settings_setPUT /v1/settings/{path}mcpx settings setmcpx_settings_setops.settingsSet(), putSetting()Privileged.
shutdownPOST /v1/shutdownmcpx stopmcpx_shutdownops.shutdown(), shutdown()Privileged. Destructive.
stats_queryGET /v1/statsmcpx statsmcpx_stats_queryops.statsQuery(), stats()
statusGET /v1/statusmcpx statusmcpx_statusops.status(), status()
tasks_listGET /v1/tasksmcpx task list generatedmcpx_tasks_listops.tasksList(), tasks()
task_getGET /v1/tasks/{id}mcpx task get generatedmcpx_task_getops.taskGet(), task()
task_cancelPOST /v1/tasks/{id}/cancelmcpx task cancel generatedmcpx_task_cancelops.taskCancel(), cancelTask()
task_resultGET /v1/tasks/{id}/resultmcpx task result generatedmcpx_task_resultops.taskResult(), taskResult()
toolsGET /v1/toolsmcpx tools generatedmcpx_toolsops.tools()
tool_invokePOST /v1/tools/{tool}mcpx tool invoke generatedmcpx_tool_invokeops.toolInvoke()
typesGET /v1/typesmcpx typesmcpx_typesops.types(), types()

CLI commands (69)

Every command the binary dispatches, with the operations it reaches. A command that reaches none says why: those are decisions, not gaps.

CommandOperationsNotes
adapteradapters_add, adapters_remove
api–OpenAPI declarations are files the CLI reads; the tools they produce are served over MCP, and are not yet a tool source the daemon owns (#83).
artifact / artifactsartifacts_list, artifact_put, artifact_delete, artifact_getGenerated from the operation table.
askask_begin, ask_poll, ask_abandon, ask_answersGenerated from the operation table.
batchbatch
cache–Reads and prunes the cache directory on this machine; no daemon is involved.
callcall, call_path
catalogcatalog
clientclient_module
completecompleteGenerated from the operation table.
completion–Text about the binary, produced by the binary.
config–Reads the configuration files on the caller’s search path; settings is the running daemon’s view.
daemon–Starts a daemon, which a daemon’s own API cannot do.
daemons–Reads every daemon’s info file on this machine; one daemon cannot see the others. Daemons with their own state directory mirror their record into the default one, and records whose process is gone are pruned.
dashboarddashboard
diagnosediagnose
doctor–Checks this machine: binaries on PATH, permissions, configuration files.
elicitelicit_list, elicit_get, elicit_answer
embeddingsembeddings, embeddings_export, embeddings_import
eventseventsGenerated from the operation table.
execexec
explore–An interactive interface over the reads above; it consumes the API rather than extending it.
feedbackfeedback
globalsglobalsGenerated from the operation table.
healthhealthGenerated from the operation table.
help–Text about the binary, produced by the binary.
historycatalog_historyGenerated from the operation table.
hook–Reads the resolved hooks setting from the configuration chain on this machine.
init–Writes a file into the current directory.
interactionsinteractions_list, interactions_get
log / logslog_query, log_record
ls / list / namespacesnamespaces
man–Text about the binary, produced by the binary.
metricsmetrics_tokens, metrics_toolsGenerated from the operation table.
openapiopenapi
plugin–Plugin discovery is local: the CLI and daemon read paths.plugins and PATH on this machine, and the daemon serves each plugin as a server of its own.
preflightpreflightGenerated from the operation table.
promptintent
promptsprompt_get, prompts
protocolprotocolGenerated from the operation table.
proxychat_completions
recipesrecipes_list, recipe_get, recipe_save, recipe_run
refreshrefresh
registryregistry_search
reloadreload
resolveresolveGenerated from the operation table.
resourcesresource_read, resource_templates, resources
restartdaemon_restart, restart
run–Resolves a script name against the caller’s search path, which only the caller has; the source itself runs anywhere through exec.
schema–Reshapes what tools and types return into JSON Schema, OpenAPI or MCP form; the data is those operations’, the conversion is local.
scripts–Lists the caller’s script search path.
searchsearch
secretssecret_requests_list, secret_request_decline, secret_request_get, secrets_list, secrets_unset, secrets_set
serve–It is the MCP surface: a stdio shim over the daemon, which serves the same tools at /mcp itself.
serversservers_list, servers_add, servers_remove, servers_get
sessionsession_releaseGenerated from the operation table.
settingssettings_list, settings_unset, settings_get, settings_set
skills–Manages embedded agent skills.
statsstats_query
statusstatus
stdio-proxy–It is a byte pipe: it dials the daemon’s unix socket on this host and copies stdin/stdout to it, which no /v1 operation can express.
stopshutdown
supervise–Runs in its own process as the re-exec target of the supervised transport; it serves no API.
task / taskstasks_list, task_get, task_cancel, task_resultGenerated from the operation table.
tooltool_invokeGenerated from the operation table.
toolstoolsGenerated from the operation table.
tui–An interactive interface over the reads above; it consumes the API rather than extending it.
typestypes
upgrade–Replaces the running daemon with another binary, a decision for whoever runs the CLI rather than a tool a model can call.

Hand-written MCP tools (12)

The tools mcpx offered before the operation table existed. Where one already covers an operation, no second tool is generated for it.

ToolCoversSummary
batch_call–Alias for mcpx_batch.
mcpx_batchbatchExecute one or more tools in a single turn.
mcpx_callcall, call_pathCall one tool on one server.
mcpx_catalogcatalogEvery namespace with as many tool signatures as fit a token budget.
mcpx_execexecRun TypeScript against every server at once.
mcpx_log–Query mcpx’s durable log: what ran, what it cost, what failed.
mcpx_namespacesnamespacesList every MCP server mcpx knows about, with tool counts.
mcpx_registry–Search a public registry of MCP servers that are not yet configured here.
mcpx_searchsearchFind tools by name and description across every server.
mcpx_stats–Aggregate the log: calls, servers, errors, sessions, slowest, volume.
mcpx_statusstatusThe daemon, its pools and live instances.
mcpx_typestypesFull TypeScript signatures for named namespaces, including each server’s own guidance.

Boundaries (5)

Every restriction mcpx declares, and whether anything enforces it (decisions/0003). An enforced one names the tests that try to get round it; an advisory one names the issue that will enforce it. TestEveryEnforcedBoundaryNamesItsRefusal holds both.

RestrictionDeclaresStateEvidence
transport.allowedOriginsa web page on an origin that is not loopback, the daemon’s own address or listed in transport.allowedOrigins cannot use /v1 or /mcpenforcedTestAWebPageCannotRunCodeThroughTheDaemon, TestV1AndMCPAgreeOnOrigins
script.permissionsa script runs with no more than the permission profile named; a runtime with no permission model refuses a narrowed profileenforcedTestScriptPermissionsIsReachableFromEverySurface, TestAStrictScriptCannotReadFilesOnARuntimeWithoutPermissions, TestARestrictedProfileIsRefusedByARuntimeThatCannotEnforceIt
elicit.confirmDestructivewith it on, a call to a tool that may be destructive (annotated destructiveHint, or unannotated) does not run unless somebody confirms it; a remote server’s annotation never clears the call (#2191)enforcedTestADestructiveCallIsRefusedWhenNobodyConfirms, TestConfirmDestructiveHoldsOnAColdDaemon
autonomy.maxmcpx does no more on its own than the daemon’s autonomy.max allows: a prompt, a recipe run by name or a configured hook asked for above it is lowered to it and the answer says so, from /v1, the CLI, MCP and the plugin alike. It does not govern code a caller sends to /v1/exec itselfenforcedTestV1CannotRaiseAutonomyAboveTheCeiling, TestTheCeilingCannotBeRaisedAtRuntime, TestTheCLICannotRaiseAutonomyAboveTheCeiling, TestMCPCannotRaiseAutonomyAboveTheCeiling, TestThePluginCannotRaiseAutonomyAboveTheCeiling, TestHooksFromConfigDoNotRunAboveTheCeiling, TestRepairCannotRaiseAutonomyAboveTheCeiling, TestACallerCannotRaiseAClampedSetting
privileged operations (Admin)operations marked privileged change the daemon rather than read it; nothing checks who calls them, and every tool description and the OpenAPI document say soadvisory#253