@rosthq/cli 0.7.110 → 0.7.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -40689,7 +40689,7 @@ var aicosPulseSnapshotSchema = external_exports.object({
40689
40689
  // ../../packages/protocol/src/command-introspection.ts
40690
40690
  var requiredScopeSchema = external_exports.enum(["tenant_admin", "tenant", "seat", "user"]);
40691
40691
  var confirmationSchema = external_exports.enum(["none", "human_required", "credential_flow", "dangerous"]);
40692
- var trustedExecutionModeSchema = external_exports.enum(["eligible", "always_human", "not_applicable"]);
40692
+ var trustedExecutionModeSchema = external_exports.enum(["eligible", "eligible_bounded", "always_human", "not_applicable"]);
40693
40693
  var trustedExecutionRiskFlagSchema = external_exports.enum([
40694
40694
  "admin",
40695
40695
  "credential",
@@ -48239,7 +48239,7 @@ Drafting can be assisted by agents. Activation is a human decision. When authori
48239
48239
  order: 40,
48240
48240
  title: "Agent staffing playbook",
48241
48241
  summary: "How to decide whether a seat should be human, agent, or hybrid, and how to go live safely.",
48242
- version: "2026-07-14.2",
48242
+ version: "2026-07-20.1",
48243
48243
  public: true,
48244
48244
  audiences: ["human", "cli", "mcp", "in_app_agent"],
48245
48245
  stages: ["staffing"],
@@ -48297,7 +48297,7 @@ Two creation paths, both draft-first. Read the stock-agents guide for templates
48297
48297
  - From a template: list with \`agent_template.list\` / \`rost_list_agent_templates\`, then \`agent.create_from_template\` / \`rost_create_agent_from_template\` with \`seat_id\` and \`template_slug\`. Returns a draft agent and draft Charter only.
48298
48298
  - Custom: \`agent_setup.start\` / \`rost_start_agent_setup\` (returns a \`setup_id\`), iterate with \`agent_setup.get\` and \`agent_setup.update\`, then \`agent.create_custom\` / \`rost_create_custom_agent\`. Stage tools with \`agent.configure_tools\` (vault refs only) and sandbox with \`agent.run_dry_run\`.
48299
48299
  - Inspect runtime: \`agent.status\` / \`rost_get_agent_status\` with \`{"seat_id":"<seat-id>"}\` returns lane, live state, steward chain, dry-run result, and Runner availability.
48300
- - Run on demand: \`{{cli}} agent run-now --seat-id <seat-id>\` / \`agent.run_now\` / \`rost_run_agent_now\` queues an immediate live run without changing the saved schedule. Cloud agents dispatch to the Inngest executor; runner agents queue work for the paired runner. The command is ungated but still requires a live staffed agent and the normal server-side tool guard.
48300
+ - Run on demand: \`{{cli}} agent run-now --seat-id <seat-id>\` / \`agent.run_now\` / \`rost_run_agent_now\` queues an immediate live run without changing the saved schedule. Cloud agents dispatch to the Inngest executor; runner agents queue work for the paired runner. It is \`human_required\` (DER-1766/DER-2081): a human requesting a run acts directly, an agent re-running its OWN seat (same-seat) may auto-execute under a standing Trusted grant, and a cross-seat dispatch (one seat running a different seat's agent) always asks a human. It still requires a live staffed agent and passes the normal server-side tool guard.
48301
48301
  - Audit what an agent did (Trust Card): \`{{cli}} command agent.list_runs --json '{"seat_id":"<seat-id>"}'\` / \`rost_list_agent_runs\` returns the seat's run history with per-run Skill activation counts plus tool-call, guard-denied, and guard-held counts; \`{{cli}} agent get-run --seat-id <seat-id> --run-id <run-id>\` / \`agent.get_run\` / \`rost_get_agent_run_diagnostics\` reads one run's transcript reference, token/cost usage, outcome, product-visible run errors, and any Skill versions/files loaded for that run. Pass \`--transcript\` (\`{"transcript":true}\`) to also return the persisted, secret-scrubbed session transcript for that run when one exists \u2014 cloud-lane and runner turns persist a bounded transcript at turn end. Final run outcomes are no longer chopped to a short summary; the full report survives. Loaded Skill file hashes and sizes identify the immutable source package; the runtime may still bound or truncate prompt text before sending it to the model. \`{{cli}} command agent.list_tool_calls --json '{"seat_id":"<seat-id>"}'\` / \`rost_list_agent_tool_calls\` returns the tool-call ledger with each call's guard result. Both list commands include \`denied_tool_call_count\` and \`held_tool_call_count\` rollups: hard guard denials stay separate from actions escalated for review. Pass \`{"seat_id":"<seat-id>","held_only":true}\` to \`agent.list_tool_calls\` for only the held calls. The web seat page shows the same facts as a Trust Card, and its Activity tab additionally renders the full persisted transcript and artifacts rail for a selected session inline (no \`--transcript\` flag needed there) alongside the business-activity ledger (\`work.record\`/\`work.list\`) \u2014 counter tiles and a run-grouped feed with each record's verb, object, outcome, evidence, and \`template_ref\` when one was used.
48302
48302
 
48303
48303
  ## Review readiness before go-live
@@ -48312,7 +48312,7 @@ The lane a live agent runs on \u2014 cloud (the {{brand}}-managed runtime), a pa
48312
48312
 
48313
48313
  ## When to stop for confirmation
48314
48314
 
48315
- \`agent.create_from_template\`, \`agent.create_custom\`, \`staffing.assign_user\`, \`agent.go_live\`, \`agent.update_schedule\`, \`agent_setup.relane\`, and \`mcp_token.create\` are \`human_required\`; \`agent.configure_tools\` and \`credential.ingress\` are \`credential_flow\` (both gate through the vault-backed credential path with human approval; \`agent.configure_tools\` stages the request and only \`credential.ingress\` takes the raw secret, as a vault reference); \`agent.decommission\` is \`dangerous\`. \`agent.run_now\` is not human-gated because it does not expand authority or change the schedule; it only queues an immediate run for an already-live agent. An agent may draft, configure (with vault refs), dry-run, and request an on-demand run; the human approves go-live, credentials, schedule changes, and decommission. \`run_dry_run\` is ungated by human approval, but it is **precondition-gated**: the seat's permission manifest must be signed first (\`charter.sign_manifest\`). Attempting a dry run before sign-off returns a clean \`COMMAND_PRECONDITION_FAILED\` naming \`charter.sign_manifest\`, not a generic failure. Go-live after a passed dry run is \`human_required\`. See the confirmations guide.
48315
+ \`agent.create_from_template\`, \`agent.create_custom\`, \`staffing.assign_user\`, \`agent.go_live\`, \`agent.update_schedule\`, \`agent_setup.relane\`, and \`mcp_token.create\` are \`human_required\`; \`agent.configure_tools\` and \`credential.ingress\` are \`credential_flow\` (both gate through the vault-backed credential path with human approval; \`agent.configure_tools\` stages the request and only \`credential.ingress\` takes the raw secret, as a vault reference); \`agent.decommission\` is \`dangerous\`. \`agent.run_now\` is \`human_required\` (DER-1766/DER-2081): a cross-seat run always asks, while a same-seat re-run of the acting seat's own live agent may auto-execute only under a standing Trusted grant. An agent may draft, configure (with vault refs), dry-run, and request an on-demand run; the human approves go-live, credentials, schedule changes, and decommission. \`run_dry_run\` is ungated by human approval, but it is **precondition-gated**: the seat's permission manifest must be signed first (\`charter.sign_manifest\`). Attempting a dry run before sign-off returns a clean \`COMMAND_PRECONDITION_FAILED\` naming \`charter.sign_manifest\`, not a generic failure. Go-live after a passed dry run is \`human_required\`. See the confirmations guide.
48316
48316
 
48317
48317
  ## Non-negotiables
48318
48318
 
@@ -50009,7 +50009,7 @@ Set \`ROST_SKILL_INSTALL_ROOT\` only for a sandbox or CI override. Local copies
50009
50009
  order: 55,
50010
50010
  title: "Agent reference map",
50011
50011
  summary: "Where CLI sessions, MCP clients, and in-app agents should retrieve {{brand}} guidance before recommending setup changes.",
50012
- version: "2026-07-15.1",
50012
+ version: "2026-07-20.1",
50013
50013
  public: true,
50014
50014
  audiences: ["cli", "mcp", "in_app_agent"],
50015
50015
  stages: ["company_setup", "graph_design", "charter_design", "staffing", "operating_rhythm"],
@@ -50123,6 +50123,7 @@ Read the listed guide before recommending or running each workflow. Every workfl
50123
50123
  - Run the weekly Sync (compile, run, complete, assign): sync-rhythm-playbook.
50124
50124
  - Operate local runners and work orders: runner-guide.
50125
50125
  - Approve or reject a pending confirmation (human only): confirmations-guide.
50126
+ - Explain what a command or agent can do automatically versus what always asks a human, or how Trusted mode and the auto band work: governed-command-capability-matrix, then confirmations-guide.
50126
50127
  - Manage members, settings, and notifications: settings-guide, settings-members-and-invites-guide, notifications-guide.
50127
50128
  - Explain company-wide billing, payment, invoices, or usage true-ups: billing-and-pricing-guide, then settings-guide.
50128
50129
  - Diagnose a failure on any surface: troubleshooting-guide, then security-model-guide.
@@ -50133,7 +50134,7 @@ Read the listed guide before recommending or running each workflow. Every workfl
50133
50134
  - Graph design: responsibility-graph-playbook
50134
50135
  - Charter design: charter-design-playbook, charter-authoring-deep-dive
50135
50136
  - Staffing: agent-staffing-playbook, add-agents-guide, custom-agents-guide, agent-builder-guide, agent-definition-import-guide, how-agents-work, tool-access-and-vault, available-tools-guide, skill-builder-guide, agent-skill-authoring-guide, agent-skill-setup-guide, mcp-and-cli-guide, stock-agents-guide
50136
- - Operating rhythm: aicos-chat-guide, cascade-guide, signal-guide, friction-guide, confirmations-guide, steward-queue-guide, sync-rhythm-playbook, notifications-guide
50137
+ - Operating rhythm: aicos-chat-guide, cascade-guide, signal-guide, friction-guide, confirmations-guide, governed-command-capability-matrix, steward-queue-guide, sync-rhythm-playbook, notifications-guide
50137
50138
  - Local agents and runners: mcp-and-cli-guide, runner-guide, agent-reference-map
50138
50139
  - Security and troubleshooting: ai-model-data-handling-guide, security-model-guide, troubleshooting-guide
50139
50140
 
@@ -50253,7 +50254,7 @@ Agents can suggest commitments and report progress. They should not create a new
50253
50254
  order: 61,
50254
50255
  title: "Signal guide",
50255
50256
  summary: "How to define and read measurables so the company runs on evidence instead of status theater.",
50256
- version: "2026-07-20.1",
50257
+ version: "2026-07-20.2",
50257
50258
  public: true,
50258
50259
  audiences: ["human", "cli", "mcp", "in_app_agent"],
50259
50260
  stages: ["operating_rhythm"],
@@ -50312,7 +50313,7 @@ Avoid vanity numbers, manual-only status fields, and metrics nobody can act on.
50312
50313
  - Add a measurable: \`measurable.create\` (scope: seat) defines a measurable a seat owns \u2014 name, unit, direction, target, cadence. The seat owns it; readings attach to it afterward.
50313
50314
  - Record a reading: \`{{cli}} status record --measurable-id <id> --value <n>\` (\`status.record\`, scope: seat) writes a status event with the reading. This is not gated. An agent's \`status.record\` never downgrades a human-confirmed reading: a routine agent read that lands on a period a human already confirmed leaves the confirmed value and its confirmation intact (invariants #7/#8 \u2014 agents recommend; humans decide).
50314
50315
  - Confirm a reading: \`{{cli}} signal confirm\` / \`signal.confirm_reading\` / \`rost_confirm_signal_reading\` marks a reading human-verified. \`signal.correct_reading\` / \`rost_correct_signal_reading\` overwrites a reading with a human-confirmed value.
50315
- - Draft first readings from a connected source: \`signal.draft_first_readings\` pulls a measurable's bound source once (read-only, SSRF-guarded \u2014 the same pull path as \`signal.preview\`) and lands the value as a DRAFT reading for the current period, for a human to confirm. It is for a measurable that has a connected source but no confirmed reading yet: the Signal page shows a "Draft first readings" button on those rows so the row stops being a permanent blank. Nothing is published \u2014 a human clears the draft with \`signal.confirm_reading\` (invariant #7) \u2014 and it never fabricates a value: a non-numeric or blocked pull drafts nothing and says so.
50316
+ - Draft first readings from a connected source: \`signal.draft_first_readings\` pulls a measurable's bound source once (read-only, SSRF-guarded \u2014 the same pull path as \`signal.preview\`) and lands the value as a DRAFT reading for the current period, for a human to confirm. It is strictly for a measurable that has a connected source but has never had a confirmed reading \u2014 in ANY period, not just the current one. A measurable that already carries a confirmed reading (even an older one) is rejected with an "already has readings" outcome and no pull happens, so the first-reading flow can never be repurposed as an ongoing draft source; use \`signal.report\` to add a current-period datapoint or \`signal.correct_reading\` to change a confirmed value instead. The Signal page shows a "Draft first readings" button on the eligible (never-measured) rows so the row stops being a permanent blank. Nothing is published \u2014 a human clears the draft with \`signal.confirm_reading\` (invariant #7) \u2014 and it never fabricates a value: a non-numeric or blocked pull drafts nothing and says so.
50316
50317
 
50317
50318
  ## Run Signal without an agent
50318
50319
 
@@ -50708,6 +50709,86 @@ The billing area in Settings answers:
50708
50709
  Settings labels subscription usage separately from the setup model allowance and the inference hard cap. Payment methods and invoice payment stay in Stripe. {{brand}} renders subscription ids/status and invoice summaries only; it does not store card, bank, payment-method, or invoice-payment details.
50709
50710
 
50710
50711
  Do not claim that a live charge happened unless Stripe test/live evidence proves it. For internal or design-partner validation, use Stripe test mode only unless a human owner explicitly completes a real live-payment step.`
50712
+ },
50713
+ {
50714
+ slug: "governed-command-capability-matrix",
50715
+ order: 72,
50716
+ title: "Governed command capability matrix",
50717
+ summary: "How to read {{brand}}'s command capability classification: the four confirmation classes, the Trusted-eligibility classes, the five-command auto band, and the always-human floor.",
50718
+ version: "2026-07-20.1",
50719
+ public: true,
50720
+ audiences: ["human", "cli", "mcp", "in_app_agent"],
50721
+ stages: ["charter_design", "staffing", "operating_rhythm"],
50722
+ relatedCommandIds: [
50723
+ "command.list",
50724
+ "command.describe",
50725
+ "agent.update_schedule",
50726
+ "goal.bind_measurable",
50727
+ "skill.assign_to_seat",
50728
+ "friction.resolve",
50729
+ "agent.run_now",
50730
+ "agent.trust.create",
50731
+ "confirmation.approve"
50732
+ ],
50733
+ legal: {
50734
+ publicRisk: "low",
50735
+ notes: [
50736
+ "Describes {{brand}}-native command governance classification; no third-party or proprietary content."
50737
+ ]
50738
+ },
50739
+ sources: [
50740
+ {
50741
+ label: "Governed command capability matrix (generated)",
50742
+ internalPath: "docs/reference/governed-command-capability-matrix.md",
50743
+ note: "Authoritative, command-by-command capability table regenerated from the command registry (`pnpm generate:capability-matrix`) and kept in sync by a drift test."
50744
+ }
50745
+ ],
50746
+ body: `# Governed command capability matrix
50747
+
50748
+ Every {{brand}} command that changes state \u2014 through the human app, the CLI, an MCP client, or the in-app AI Chief of Staff \u2014 carries the same registry-derived governance classification. This guide answers the question every agent and every human operator eventually asks: what can my agents do right now, and how do I change that? Which commands ask a human every time, which can automate under Trusted mode, and which stay off-limits to automation no matter what.
50749
+
50750
+ The full command-by-command table is generated directly from the command registry and lives at \`docs/reference/governed-command-capability-matrix.md\`. A drift test keeps it honest: it fails CI the moment the registry changes without the table being regenerated, so the table can never quietly go stale. This guide is the curated companion \u2014 read it first to understand the classification scheme, then open the generated table to look up any specific command's exact row.
50751
+
50752
+ ## The four confirmation classes
50753
+
50754
+ Every command declares one of four confirmation classes:
50755
+
50756
+ - **None** \u2014 no human gate at all. The command runs immediately (for example a status update, a work log entry, or a task creation the acting seat already owns).
50757
+ - **Human required** \u2014 the durable-change default. The command mints a pending confirmation a human must approve before it takes effect, unless it qualifies for Trusted auto-band execution (below).
50758
+ - **Credential flow** \u2014 the command routes through the vault-backed credential flow. A raw secret never appears in a prompt, a log, or a CLI argument.
50759
+ - **Dangerous** \u2014 an irreversible or high-blast-radius action (for example decommissioning an agent) that always asks, with extra confirmation friction.
50760
+
50761
+ ## The Trusted-eligibility classes
50762
+
50763
+ Turning on Trusted mode for a seat does not change a command's confirmation class. It changes whether that seat may execute a \`human_required\` command's proposal automatically, under a standing authorization a human deliberately established. Every action taken this way is still recorded as its own human-authorized decision \u2014 Trusted mode automates the button-press, not the accountability. Every command falls into one of four Trusted-eligibility classes:
50764
+
50765
+ - **Auto** \u2014 a small, confirmation-free allowlist of low-risk worker actions (status updates, task creation, work logging, and similar) that already run without a human gate and are safe for a Trusted agent to keep doing unattended.
50766
+ - **Auto-bounded** \u2014 a \`human_required\` command that may auto-execute under Trusted, but only for a narrow, founder-approved bounded sub-case of its input (the five-command auto band, below). Every other input on the same command still mints a normal human confirmation.
50767
+ - **Always ask** \u2014 a command carrying a protected risk category (credential, spend, external send, production/go-live, destructive, self-approval, or admin) or otherwise gated. Trusted mode never changes this; it always asks a human.
50768
+ - **Not applicable** \u2014 a discovery or read command with no durable action to automate.
50769
+
50770
+ ## The five-command auto band
50771
+
50772
+ Exactly five commands carry an auto band today \u2014 a founder-approved, narrow bounded sub-case where a \`human_required\` command may auto-execute under a standing Trusted grant on a human-initiated turn. Any input outside the described bound still mints a human confirmation:
50773
+
50774
+ 1. **\`agent.update_schedule\`** (schedule set) \u2014 setting or changing a seat's routine schedule. Clearing a schedule is out of band and still asks.
50775
+ 2. **\`goal.bind_measurable\`** (informs Signal bind) \u2014 binding a Signal in the conservative "informs" role, which never drives goal status. A "drives status" binding is out of band and still asks.
50776
+ 3. **\`skill.assign_to_seat\`** (published skill assign) \u2014 assigning an already-published, immutable skill version to a seat. A proposed (non-approved) assignment, or a version that does not resolve to a published skill, is out of band and still asks.
50777
+ 4. **\`friction.resolve\`** (routine Friction resolve) \u2014 resolving a Friction the acting seat already owns within its own member-seat subtree. A Friction outside that subtree, or a turn with no identifiable human initiator, is out of band and still asks.
50778
+ 5. **\`agent.run_now\`** (same-seat run now) \u2014 re-running the acting seat's own live agent. A cross-seat dispatch, where one seat runs a different seat's agent, is out of band and still asks.
50779
+
50780
+ Widening this set, or adding a sixth command, is a deliberate founder decision \u2014 not something a code change alone can slip in. The registry enforces it: a command cannot carry an auto band unless it is one of these five ids.
50781
+
50782
+ ## The always-human floor
50783
+
50784
+ A command carrying any of these risk categories always asks a human, even under Trusted mode: credential handling, spend or billing changes, external sends (invitations, outbound messages), production or go-live actions, destructive actions, self-approval of your own confirmation, or an admin-scope change. No autonomy setting removes this floor. It is a deliberate, conservative-by-default boundary \u2014 see confirmations-guide for how human gates work end to end.
50785
+
50786
+ ## Where to look up a specific command
50787
+
50788
+ - The generated, authoritative table: \`docs/reference/governed-command-capability-matrix.md\` \u2014 one row per command with its required scope, confirmation class, Trusted mode, autonomy class, auto-band class (when it has one), MCP exposure, CLI availability, and whether the AI Chief of Staff can reach it as a governed tool call.
50789
+ - A single command's exact schema and classification: {{cli}} command schema <id> (CLI) or rost_describe_command (MCP).
50790
+ - How pending confirmations are approved or rejected: confirmations-guide.
50791
+ - How Trusted grants are created, inspected, and revoked: agent-staffing-playbook.`
50711
50792
  },
50712
50793
  {
50713
50794
  slug: "settings-guide",
@@ -50920,7 +51001,7 @@ Every notification should include the seat, cause, evidence, and requested decis
50920
51001
  order: 75,
50921
51002
  title: "Local runner guide",
50922
51003
  summary: "How local agent sessions and runner surfaces should operate through {{brand}} without bypassing Charters or audit.",
50923
- version: "2026-07-20.1",
51004
+ version: "2026-07-20.2",
50924
51005
  public: true,
50925
51006
  audiences: ["human", "cli", "mcp", "in_app_agent"],
50926
51007
  stages: ["staffing", "operating_rhythm"],
@@ -51016,7 +51097,7 @@ Use this flow when a headless or desktop runner cannot use the interactive web c
51016
51097
 
51017
51098
  ## When to stop for confirmation
51018
51099
 
51019
- \`runner.pairing.start\`, \`work_order.enqueue\`, and \`agent.run_now\` are \`none\`, so they do not create a separate pending confirmation, but \`runner.pairing.start\` is still owner/admin-only at the command authorization layer. \`runner.revoke\` and \`work_order.cancel\` are \`human_required\`. List and status reads are not gated. Revoking a runner or cancelling work is the human-approved act. An agent inspects runner state and proposes the action.
51100
+ \`runner.pairing.start\` and \`work_order.enqueue\` are \`none\`, so they do not create a separate pending confirmation, but \`runner.pairing.start\` is still owner/admin-only at the command authorization layer. \`runner.revoke\`, \`work_order.cancel\`, and \`agent.run_now\` are \`human_required\` (DER-1766/DER-2081): a cross-seat run always asks, and a same-seat re-run of the acting seat's own agent may auto-execute only under a standing Trusted grant. List and status reads are not gated. Revoking a runner or cancelling work is the human-approved act. An agent inspects runner state and proposes the action.
51020
51101
 
51021
51102
  ## Guardrails
51022
51103
 
@@ -52916,7 +52997,7 @@ var COMMAND_MANIFEST = [
52916
52997
  { "id": "agent.resume", "namespace": "agent", "action": "resume", "title": "Resume agent", "description": "Resume a paused agent back to live. Blocks if the steward chain no longer resolves to a human.", "requiredScope": "tenant", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "seat_id", "flag": "seat-id", "type": "string", "required": true }, { "name": "reason", "flag": "reason", "type": "string", "required": false }], "hasComplexInput": false, "help": "Resume a paused agent back to live; the no-orphan guard blocks a resume whose steward chain no longer resolves to a human." },
52917
52998
  { "id": "agent.run_dry_run", "namespace": "agent", "action": "run_dry_run", "title": "Run agent dry run", "description": "Run the sandbox dry run for a draft agent. Durable and idempotent per Charter version; a passed result is reused, never re-run.", "requiredScope": "seat", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "seat_id", "flag": "seat-id", "type": "string", "required": true }, { "name": "charter_version_id", "flag": "charter-version-id", "type": "string", "required": true }], "hasComplexInput": false, "help": "Run the sandbox dry run for a draft agent after the manifest is signed; the result is durable and idempotent per Charter version, and a passed run is reused.", "example": { "seat_id": "0190aaaa-aaaa-7aaa-8aaa-aaaaaaaaaaaa", "charter_version_id": "0190cccc-cccc-7ccc-8ccc-cccccccccccc" } },
52918
52999
  { "id": "agent.run_heartbeats", "namespace": "agent", "action": "run_heartbeats", "title": "Get run heartbeats", "description": "Reads the per-seat run-heartbeat roll-up (quiet-but-healthy vs stalled) for long-running agent programs.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "seat_ids", "flag": "seat-ids", "type": "array", "required": false, "itemType": "string" }], "hasComplexInput": false, "help": "Read the per-seat run-heartbeat roll-up to tell a quiet-but-healthy long-running agent program apart from a stalled one." },
52919
- { "id": "agent.run_now", "namespace": "agent", "action": "run_now", "title": "Run agent now", "description": "Queue and dispatch an immediate work order for a live cloud or runner agent on a seat. task_id is cloud-lane only; a runner-lane agent rejects it.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "seat_id", "flag": "seat-id", "type": "string", "required": true }, { "name": "task_id", "flag": "task-id", "type": "string", "required": false }], "hasComplexInput": false, "help": "Queue and dispatch an immediate live agent run without changing the agent's saved schedule. task_id is cloud-lane only; a runner-lane agent rejects it (run task-linked runner work as an interactive agent turn)." },
53000
+ { "id": "agent.run_now", "namespace": "agent", "action": "run_now", "title": "Run agent now", "description": "Queue and dispatch an immediate work order for a live cloud or runner agent on a seat. task_id is cloud-lane only; a runner-lane agent rejects it.", "requiredScope": "tenant", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "seat_id", "flag": "seat-id", "type": "string", "required": true }, { "name": "task_id", "flag": "task-id", "type": "string", "required": false }], "hasComplexInput": false, "help": "Queue and dispatch an immediate live agent run without changing the agent's saved schedule. task_id is cloud-lane only; a runner-lane agent rejects it (run task-linked runner work as an interactive agent turn)." },
52920
53001
  { "id": "agent.show_markdown", "namespace": "agent", "action": "show_markdown", "title": "Show agent setup as markdown", "description": "Compose a seat's agent setup, steward, model, tools, and Charter into a clean, human-skimmable markdown card for review.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "seat_id", "flag": "seat-id", "type": "string", "required": true }], "hasComplexInput": false, "help": "Render a seat's agent setup, model, steward, tools, and Charter as a clean markdown card to show your human a quick review." },
52921
53002
  { "id": "agent.status", "namespace": "agent", "action": "status", "title": "Get agent status", "description": "Return the agent occupancy, lane, schedule, live/offline state, steward chain, dry-run result, and Runner availability for a seat.", "requiredScope": "seat", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "seat_id", "flag": "seat-id", "type": "string", "required": true }], "hasComplexInput": false, "help": "Check an agent's lane, live state, steward chain, dry-run result, and Runner availability before relying on it." },
52922
53003
  { "id": "agent.trust.create", "namespace": "agent", "action": "trust.create", "title": "Create agent Trusted grant", "description": "Create a bounded Trusted execution grant for a live agent after a human steward/admin signs the current activation receipt digest.", "requiredScope": "tenant", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "agent_id", "flag": "agent-id", "type": "string", "required": true }, { "name": "expected_scope_digest", "flag": "expected-scope-digest", "type": "string", "required": true }, { "name": "budget_cents", "flag": "budget-cents", "type": "integer", "required": true }, { "name": "expires_at", "flag": "expires-at", "type": "string", "required": false }, { "name": "reason", "flag": "reason", "type": "string", "required": false }], "hasComplexInput": false, "help": "Create a bounded Trusted execution grant only after reviewing the activation receipt digest, budget, and always-human boundary. Human steward/admin only." },
@@ -57737,6 +57818,7 @@ ${usage()}
57737
57818
  let failed = false;
57738
57819
  let activeSessions = 0;
57739
57820
  const activeTurnExecutionIds = /* @__PURE__ */ new Set();
57821
+ let serverHeartbeatContractVersion = null;
57740
57822
  do {
57741
57823
  const detectedCapabilities = await detectCapabilities(cliVersion, env, homeDir, config2.maxSessionsOverride);
57742
57824
  const capabilities = capabilitiesForConfiguredRuntime(detectedCapabilities, config2.runtime);
@@ -57745,7 +57827,8 @@ ${usage()}
57745
57827
  const heartbeat = await post2(fetchImpl, options.appUrl, "/api/runner/heartbeat", buildHeartbeatBody({
57746
57828
  capabilities,
57747
57829
  telemetry: detectTelemetry(capabilities, env, activeSessions, cliVersion),
57748
- activeTurnExecutionIds: [...activeTurnExecutionIds]
57830
+ activeTurnExecutionIds: [...activeTurnExecutionIds],
57831
+ serverContractVersion: serverHeartbeatContractVersion
57749
57832
  }), state.runner_secret);
57750
57833
  if (heartbeat.status !== 200) {
57751
57834
  options.io.stderr.write(`heartbeat ${heartbeat.status}: ${redactForLog(JSON.stringify(heartbeat.json))}
@@ -57753,6 +57836,10 @@ ${usage()}
57753
57836
  failed = true;
57754
57837
  } else {
57755
57838
  heartbeatSucceeded = true;
57839
+ const learnedVersion = readHeartbeatContractVersion(heartbeat.json);
57840
+ if (learnedVersion !== null) {
57841
+ serverHeartbeatContractVersion = learnedVersion;
57842
+ }
57756
57843
  options.io.stdout.write(`heartbeat ok #${beat} runner_id=${state.runner_id} claude=${capabilities.claude.installed} codex=${capabilities.codex.installed}
57757
57844
  `);
57758
57845
  }
@@ -57766,7 +57853,11 @@ ${usage()}
57766
57853
  capabilities,
57767
57854
  io: options.io,
57768
57855
  telemetry: () => detectTelemetry(capabilities, env, activeSessions, cliVersion),
57769
- activeTurnIds: () => [...activeTurnExecutionIds]
57856
+ activeTurnIds: () => [...activeTurnExecutionIds],
57857
+ serverContractVersion: () => serverHeartbeatContractVersion,
57858
+ recordServerContractVersion: (v) => {
57859
+ serverHeartbeatContractVersion = v;
57860
+ }
57770
57861
  });
57771
57862
  try {
57772
57863
  await claimAndExecute(fetchImpl, options.appUrl, state, config2, options.io, localRuntime, activeTurnExecutionIds);
@@ -57791,13 +57882,17 @@ ${usage()}
57791
57882
  localRuntime,
57792
57883
  capabilities,
57793
57884
  () => detectTelemetry(capabilities, env, activeSessions, cliVersion),
57794
- activeTurnExecutionIds
57885
+ activeTurnExecutionIds,
57886
+ () => serverHeartbeatContractVersion,
57887
+ (v) => {
57888
+ serverHeartbeatContractVersion = v;
57889
+ }
57795
57890
  );
57796
57891
  }
57797
57892
  } while (!config2.once);
57798
57893
  return heartbeatSucceeded && !failed ? 0 : 1;
57799
57894
  }
57800
- async function waitForNextHeartbeat(fetchImpl, appUrl2, state, config2, io, runtime, capabilities, telemetry, activeTurnExecutionIds) {
57895
+ async function waitForNextHeartbeat(fetchImpl, appUrl2, state, config2, io, runtime, capabilities, telemetry, activeTurnExecutionIds, serverContractVersion, recordServerContractVersion) {
57801
57896
  const deadline = Date.now() + config2.heartbeatMs;
57802
57897
  const stopWait = runtime ? startTurnHeartbeat({
57803
57898
  fetchImpl,
@@ -57807,7 +57902,9 @@ async function waitForNextHeartbeat(fetchImpl, appUrl2, state, config2, io, runt
57807
57902
  capabilities,
57808
57903
  io,
57809
57904
  telemetry,
57810
- activeTurnIds: () => [...activeTurnExecutionIds]
57905
+ activeTurnIds: () => [...activeTurnExecutionIds],
57906
+ serverContractVersion,
57907
+ recordServerContractVersion
57811
57908
  }) : null;
57812
57909
  try {
57813
57910
  while (Date.now() < deadline) {
@@ -57827,12 +57924,17 @@ async function waitForNextHeartbeat(fetchImpl, appUrl2, state, config2, io, runt
57827
57924
  stopWait?.();
57828
57925
  }
57829
57926
  }
57927
+ var HEARTBEAT_ACTIVE_TURN_MIN_CONTRACT_VERSION = 2;
57928
+ function readHeartbeatContractVersion(json2) {
57929
+ const value = json2.heartbeat_contract_version;
57930
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
57931
+ }
57830
57932
  function buildHeartbeatBody(input) {
57831
57933
  const body = {
57832
57934
  capabilities: input.capabilities,
57833
57935
  telemetry: input.telemetry
57834
57936
  };
57835
- if (input.activeTurnExecutionIds.length > 0) {
57937
+ if (input.activeTurnExecutionIds.length > 0 && (input.serverContractVersion ?? 0) >= HEARTBEAT_ACTIVE_TURN_MIN_CONTRACT_VERSION) {
57836
57938
  body.active_turn_execution_ids = input.activeTurnExecutionIds;
57837
57939
  }
57838
57940
  return body;
@@ -57853,11 +57955,17 @@ function startTurnHeartbeat(deps) {
57853
57955
  const response = await post2(deps.fetchImpl, deps.appUrl, "/api/runner/heartbeat", buildHeartbeatBody({
57854
57956
  capabilities: deps.capabilities,
57855
57957
  telemetry: deps.telemetry(),
57856
- activeTurnExecutionIds: deps.activeTurnIds()
57958
+ activeTurnExecutionIds: deps.activeTurnIds(),
57959
+ serverContractVersion: deps.serverContractVersion()
57857
57960
  }), deps.secret, controller.signal);
57858
57961
  if (!stopped && response.status !== 200) {
57859
57962
  deps.io.stderr.write(`turn heartbeat ${response.status}: ${redactForLog(JSON.stringify(response.json))}
57860
57963
  `);
57964
+ } else if (!stopped && response.status === 200) {
57965
+ const learnedVersion = readHeartbeatContractVersion(response.json);
57966
+ if (learnedVersion !== null) {
57967
+ deps.recordServerContractVersion(learnedVersion);
57968
+ }
57861
57969
  }
57862
57970
  } catch (error51) {
57863
57971
  if (!stopped) {