Commands — app program invocation
Source:
harness/docs/plugins/commands.md
Status: current. Staged verbatim for documentation ingestion.
Commands — app program invocation
Section titled “Commands — app program invocation”Commands are not PEW/Work. They are app-managed programs: a Client Scheme (Arrival) half for pickers and projections, and a commit of name+args as a JSON-RPC action on the session socket.
Grain: ../canon/grain.md (Command = app program).
Surfaces ladder: plugins/tldr.md.
Inventory grounding: ../runtime/drivers.md (drivers[] is still projected; it is not the behavior surface).
The Client Scheme does not implement a mini-app UI framework. It declares session-hub projections (catalog, faces, commands) into a unified choice / action surface. The Client owns navigation, search, chrome, and rebuild.
Registration is extensions.tools.inhuman.commands — { description, importPath }
to a Scheme file. File-driven so require works. polish.md.
1. Split
Section titled “1. Split”| Half | Where | Role |
|---|---|---|
| Sandbox | Client | Scheme file (Arrival); read session-hub projections; fast local UX |
| Commit | Session socket | name+args as a JSON-RPC action |
Commit holds { type, args } — programs never await
(../runtime/control-effects.md).
2. Law (sandbox half)
Section titled “2. Law (sandbox half)”| Command declares | Client owns | |
|---|---|---|
| Content | Choice rows over DriverSpecs + ConnectionSpecs + faces | Fuzzy, arrows, focus, multi-rep (TUI / remote / voice) |
| Primary | action (commit) or nested choice (drill) |
Enter / default activate |
| Additional | actions list (manage ops on the same subject) |
Bind chrome; optional hotkeys |
| Hotkeys | Optional triggers on action/choice — never the behavior itself | Keymap |
| Navigation | — | Esc / back / stack / cleanup |
| Inventory | Read driver + connection faces only | Re-interpret whole surface when atoms change (v0 all-or-nothing) |
| Product knowledge | Never invent package-form import paths, whitelist entries, badges, doors, Back rows | Chrome, empty states, session-attached gate |
| World | Current is immutable (reads / provenance) | Next via commit of kv/set / named actions |
One verb, one concern.
| Verb | Owns | Must not |
|---|---|---|
/connect |
ConnectionSpec registry: list wires, adopt/drop, set current wire (+ last-used model on that wire) | Model catalog / free model pick as primary product |
/model |
Models from connection faces; free model id; set session model | Adopt/drop drivers/connections |
/mcp |
ConnectionSpecs whose can includes mcp: health, tool count, session disable, authenticate, add/drop |
Completion wires / model catalog |
Selecting a connection is kv/set connection (then last-used model on that wire) — not a special “use pipeline.” Selecting a model is kv/set connection, then model, then last-used on that wire. Reactivity does the rest. Adopted offers are omitted. Unused add-by-default drivers adopt from the driver row. OpenRouter opens a PKCE key-exchange URL. ChatGPT and Grok park an OIDC browser sign-in and store a refreshable session. /model lists faces with fewer than 20 ids first; catalogs of 20 or more sit below.
Packs may register extra operator verbs through extensions.tools.inhuman.commands. Those commands are absent from the model tool catalog.
3. Surface grammar
Section titled “3. Surface grammar”choice = { kind: "choice", rows }row = title, description?, state? primary: InhumanAction.ref(args) | choice | input actions: list of { label, hotkeys?, action }action = name + args → { type, args } issued as JSON-RPC hotkeys?: optional triggers onlySame grammar can be lensed to TUI, remote UI, or voice — the command does not care.
{ title: "…", description: "…", state: "warning", primary: selectConnection.ref({ id: c.id }), actions: [ { label: "disconnect", hotkeys: ["control-x"], action: dropConnection.ref({ id: c.id }) }, ],}Missing adopt settings (base URL) are a harness/input callback form from connect/adopt, not a nested input dict in the command program. openai-compat’s OpenAI-compatible door is an adoptable offer with empty settings: Enter parks Base URL, then an optional secret API key (empty skips). The written wire is named by a well-known catalog when the host matches (Groq, Fireworks, OpenRouter, …), else the URL’s eTLD+1, so many custom endpoints coexist. The door is never hidden after adopt.
/mcp is the same grammar over can: ["mcp"]. Rows have no primary select (not a completion wire). Add is mcp-server/adopt, not connect/adopt: remainder on the root action is the dropped URL or stdio command (:input); Enter on the Add MCP row parks. HTTP remainder that 401s with Protected Resource Metadata parks the same PKCE harness/open-url as connect/login; otherwise an optional token. Session disable is kv/set mcp-disabled:{id}, not config.json. Row tool counts are live.tools (what the server listed). The durable catalog cut is tools on the connection; toolSeverity overlays auto-class — ../client/operate.md § /mcp.
No kind: "pick" ceremony if the host treats every row as choosable context. Free model id is remainder-as-:input on kv/set.
/goal and /plan are pack command files
(plugins/inhuman-plugin-goal/tools/inhuman/commands/goal.scm,
plugins/inhuman-plugin-fusion/tools/inhuman/commands/plan.scm). They call
call/method and harness/action-with-choices. The client Arrival interpreter
does not evaluate those forms, and the behavior capability does not either.
4. Projections (connect example)
Section titled “4. Projections (connect example)”Subject of each define must match the name (connections vs drivers):
| Projection | Meaning |
|---|---|
prompt-drivers |
DriverSpecs whose pre-load can includes completion |
used-connections |
ConnectionSpecs whose DriverSpec is prompt-capable. Titles prefer live.catalogName over the config.json name. Dim annotation (user · $balance / displayName) and tertiary hint (key mask / plan caption) are client-composed from live.account / live.identity / live.keyMask. Adopted rows do not show the URL |
offers |
class-bootstrap offers on those drivers, minus already-adopted. openai-compat names loopback catalogs by port (Ollama, LM Studio, …) and seeds remote catalogs on load |
unused-drivers |
prompt DriverSpecs with no ConnectionSpec and no offers |
Rebuild: whole connect-surface re-runs when Spec inventory/faces change — not per-define fine-grained computeds (v0).
5. Registration
Section titled “5. Registration”"commands": { "connect": { "description": "Manage provider connections", "importPath": "./commands/connect.scm" }}On extensions.tools.inhuman.commands. The Scheme file is loaded file-driven (Arrival require against that path). The plugin JS module does not load on the Client. Dual ambient (manifest vs Client eval): lifecycle.md.
6. Session-hub ambient + entities
Section titled “6. Session-hub ambient + entities”(harness/kernel/…) reads KernelRoot.drivers / KernelRoot.connections — live entities, not view dicts.
(harness/action 'kv/set :params …) is a named RPC, not a Scheme mutate of the kernel.
The operation is the first positional argument. A branded host instance is opaque identity: (:id c) doors. Field reads are (:field entity).
(harness/kernel/drivers :can 'completion) ; DriverSpec list(harness/kernel/connections) ; ConnectionSpec list(harness/kernel/offers d) ; class-bootstrap connection construction(:models (:live c)) ; openai-compat invocation ids on spec.live(harness/session/get-current key) ; immutable current(harness/action 'kv/set :params (dict :key "connection" :value (:id c) :remember "1"))(harness/action 'connect/adopt :params (dict :driver (:name d) :name n :settings s))(harness/action 'connect/drop :name "Remove connection" :hotkey "control-x" :params (dict :id (:id c)))(harness/action 'mcp-server/adopt :name "Add MCP" :params (dict :input ""))| Entity | Field reads ((:field entity)) |
|---|---|
| connection (ConnectionSpec) | id, name, driver, issue, error, configuration, live |
| driver (DriverSpec) | name, description, can (Expectation model names), multiplicity |
| offer | name, description, adoptable, settings |
connect/adopt takes driver name + offer name + settings. can is readable before ensure; broken connections surface sticky failure messages, not silent absence. add-by-default unused drivers adopt from the driver row. Secrets stay in process-local secrets.json, never config.json.
7. Host obligations
Section titled “7. Host obligations”- Session attached (session-hub catalog present).
- Interpret surface → choice/action tree; fuzzy + arrows.
- Primary activate / additional actions / hotkeys as triggers.
- Esc / back / dismiss — never command rows.
- Re-interpret on reactive projection change.
- Commit
InhumanAction.ref(args)/ host{ type, args }.
8. Observation vs work
Section titled “8. Observation vs work”| Surface | System |
|---|---|
| Slash command picker | declarative choice/action + DriverSpec / ConnectionSpec faces |
| Behavior guards and hooks | critical path and parallel notes (lifecycle.md) |
| Chat completion | PEW + ensure → PEWConnection.resolve → ExpectationActor |
Listing connections/models = observation. Running a completion = work.
9. Shipped command files
Section titled “9. Shipped command files”../packages/harness-server/src/defaults/commands/connect.scm../packages/harness-server/src/defaults/commands/model.scm../packages/harness-server/src/defaults/commands/mcp.scm../runtime/drivers.md(internal —drivers[]is still projected)