Expand description
Agent control port: a hardened loopback JSON-lines server, its client, and the standard method set every app answers.
agent / MCP / CLI ──TCP 127.0.0.1──▶ Server (connection threads) ──Request──▶ app thread
│ handle(req, dispatch, ui, info)
◀────────── {"id","ok","result"|"error"} ◀──────────┘The server never touches app state: it parses, authenticates and queues Requests; the app
thread answers them with handle (standard app.*/engine.* methods from any
ashlar_command::Dispatch, everything else from the app’s UiHandler). The protocol is
documented in docs/control-protocol.md.
Modules§
- key
- The control key: a random secret the app writes to a file only its user can read, and that
every request must carry. One rule for the app (which writes it) and the clients (which read
it):
<dir>/control-key.<instance>,<dir>being a folder the app chooses (its settings folder),<instance>the Flatpak instance id orlocal-<port>.
Structs§
- AppInfo
- Who is answering: reported by
app.version. - Client
- A connection to
127.0.0.1:<port>(the control port is loopback only, so the key never leaves the machine). Reconnects when the app closed the kept connection or restarted (a restart also means a new key, read again from the key file), but only before a request was sent: once any byte of a request reached the socket it is never sent again, so a mutating command cannot run twice when the app dies mid-request. - Config
- Server settings.
Config::newgives the hardened defaults. - NoUi
- No UI: a headless session.
ui.*methods are refused with a hint. - Request
- One request on its way to the app thread. Answer it with
Request::reply(or a shortcut); a request dropped unanswered replies with an error by itself, so the connection never hangs. It may be kept and answered on a later frame (the element is not on screen yet, a screenshot needs the next paint). - Server
- A running control server. Dropping it closes the port and every open connection, and removes the key file.
Enums§
- ClockOp
- What an
app.clockrequest asks for. - Control
Error - Why a control-port operation failed.
- Reply
- One reply.
detailcarries machine-readable context for an error (aCommandErroras JSON, the step results of a failed batch).
Constants§
- APP_
CLOCK - The clock method. Answered by the windowed runtime (
ashlar-app), which lists it inapp.version; a headless session refuses it. - DEBUG_
METHODS - The debugger vocabulary (element snapshots with refs, actions on targets, waits; see
docs/control-protocol.md). Not part ofUI_METHODS: aUiHandlerreports each one only once it answers it, so clients never list a tool the app cannot serve. - DEFAULT_
MAX_ LINE - Default longest request line (bytes, without the newline).
- MAX_
BATCH - Most steps one
engine.batchmay hold. - MAX_
REPLY - Longest reply line accepted (screenshots travel inline as base64).
- MAX_
STEP_ MS - Longest single
step_ms: one minute. - PROTOCOL_
VERSION - Version of the method vocabulary, reported by
app.version. Bumped on incompatible changes. - STANDARD_
METHODS - Methods every app answers, headless or not (
authis handled by the transport). - UI_
METHODS - The canonical UI vocabulary. A
UiHandleranswers the ones it supports (and may add moreui.*methods). Seedocs/control-protocol.mdfor the parameters. - UI_
SCENE ui.scene {name?}: apply one of the app’s named scenes, or with no name list them ({scenes: [..]}). Answered only by apps that declare scenes.
Traits§
- UiHandler
- The app’s answer to everything outside
STANDARD_METHODS:ui.*,app.quitand any app-specific methods. Implemented by the UI runtime.
Functions§
- answer
- Answer one request synchronously (headless serving, tests). A request the UI handler keeps for later is answered with an error.
- explain
- A command’s error as a reply, explained against
commands(what the app lists).detailkeeps the error’skindandid; an unknown command addssuggestions([{id, params}]) and says “did you mean …” in the message, bad parameters addtakes(the command’s parameters) and name them in the message unless it already lists them. - explain_
reply explainfor a reply that came from elsewhere (a running app, a worker): an error whosedetail.kindisunknownorbad_params(or whose message starts with “unknown command”) and that is not explained yet.commandsis only called when there is something to explain. Anything else comes back unchanged.- handle
- Answer one request on the app thread: standard methods from
dispatch, everything else fromui(which may keep the request for a later frame). - matches_
query - Whether a command matches a lower-case filter on its id, label or menu path.
- serve_
stream - Serve the control protocol on a private byte stream (a child’s stdin/stdout) without a key:
handleanswers each request synchronously. Returns wheninputends or sends junk.
Type Aliases§
- Wake
- Repaint callback: called after a request is queued for the app thread.