agent-afk 5.301.2 → 5.302.0

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.
@@ -1,2 +1,10 @@
1
1
  import type { MessageParam } from '@anthropic-ai/sdk/resources';
2
- export declare function repairOrphanToolUses(messages: MessageParam[]): void;
2
+ export interface OrphanRepairReport {
3
+ hoistedMessageIndices: number[];
4
+ orphanToolUseIds: string[];
5
+ orphanAssistantIndices: number[];
6
+ bridgedIndices: number[];
7
+ messageCountBefore: number;
8
+ shapeBefore: string;
9
+ }
10
+ export declare function repairOrphanToolUses(messages: MessageParam[]): OrphanRepairReport | null;
@@ -1,4 +1,26 @@
1
1
  import { z } from 'zod';
2
+ export declare const BackgroundAgentStartedPayloadSchema: z.ZodObject<{
3
+ transition: z.ZodLiteral<"started">;
4
+ jobId: z.ZodString;
5
+ subagentId: z.ZodString;
6
+ label: z.ZodString;
7
+ model: z.ZodString;
8
+ }, z.core.$strip>;
9
+ export declare const BackgroundAgentCompletedPayloadSchema: z.ZodObject<{
10
+ transition: z.ZodLiteral<"completed">;
11
+ jobId: z.ZodString;
12
+ subagentId: z.ZodString;
13
+ durationMs: z.ZodNumber;
14
+ outputBytes: z.ZodNumber;
15
+ }, z.core.$strip>;
16
+ export declare const BackgroundAgentFailedPayloadSchema: z.ZodObject<{
17
+ transition: z.ZodLiteral<"failed">;
18
+ jobId: z.ZodString;
19
+ subagentId: z.ZodString;
20
+ durationMs: z.ZodNumber;
21
+ errorClass: z.ZodString;
22
+ errorMessage: z.ZodString;
23
+ }, z.core.$strip>;
2
24
  export declare const BackgroundAgentCancelledPayloadSchema: z.ZodObject<{
3
25
  transition: z.ZodLiteral<"cancelled">;
4
26
  jobId: z.ZodString;
@@ -10,3 +32,71 @@ export declare const BackgroundAgentCancelledPayloadSchema: z.ZodObject<{
10
32
  cancelledBy: z.ZodOptional<z.ZodLiteral<"model">>;
11
33
  reason: z.ZodOptional<z.ZodString>;
12
34
  }, z.core.$strip>;
35
+ export declare const BackgroundAgentJoinedPayloadSchema: z.ZodObject<{
36
+ transition: z.ZodLiteral<"joined">;
37
+ jobId: z.ZodString;
38
+ subagentId: z.ZodString;
39
+ jobStatus: z.ZodEnum<{
40
+ failed: "failed";
41
+ completed: "completed";
42
+ cancelled: "cancelled";
43
+ }>;
44
+ }, z.core.$strip>;
45
+ export declare const BackgroundAgentDeliveredPayloadSchema: z.ZodObject<{
46
+ transition: z.ZodLiteral<"delivered">;
47
+ jobId: z.ZodString;
48
+ subagentId: z.ZodString;
49
+ jobStatus: z.ZodEnum<{
50
+ failed: "failed";
51
+ completed: "completed";
52
+ cancelled: "cancelled";
53
+ }>;
54
+ }, z.core.$strip>;
55
+ export declare const BackgroundAgentPayloadSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
56
+ transition: z.ZodLiteral<"started">;
57
+ jobId: z.ZodString;
58
+ subagentId: z.ZodString;
59
+ label: z.ZodString;
60
+ model: z.ZodString;
61
+ }, z.core.$strip>, z.ZodObject<{
62
+ transition: z.ZodLiteral<"completed">;
63
+ jobId: z.ZodString;
64
+ subagentId: z.ZodString;
65
+ durationMs: z.ZodNumber;
66
+ outputBytes: z.ZodNumber;
67
+ }, z.core.$strip>, z.ZodObject<{
68
+ transition: z.ZodLiteral<"failed">;
69
+ jobId: z.ZodString;
70
+ subagentId: z.ZodString;
71
+ durationMs: z.ZodNumber;
72
+ errorClass: z.ZodString;
73
+ errorMessage: z.ZodString;
74
+ }, z.core.$strip>, z.ZodObject<{
75
+ transition: z.ZodLiteral<"cancelled">;
76
+ jobId: z.ZodString;
77
+ subagentId: z.ZodString;
78
+ source: z.ZodEnum<{
79
+ explicit: "explicit";
80
+ cascade: "cascade";
81
+ }>;
82
+ cancelledBy: z.ZodOptional<z.ZodLiteral<"model">>;
83
+ reason: z.ZodOptional<z.ZodString>;
84
+ }, z.core.$strip>, z.ZodObject<{
85
+ transition: z.ZodLiteral<"joined">;
86
+ jobId: z.ZodString;
87
+ subagentId: z.ZodString;
88
+ jobStatus: z.ZodEnum<{
89
+ failed: "failed";
90
+ completed: "completed";
91
+ cancelled: "cancelled";
92
+ }>;
93
+ }, z.core.$strip>, z.ZodObject<{
94
+ transition: z.ZodLiteral<"delivered">;
95
+ jobId: z.ZodString;
96
+ subagentId: z.ZodString;
97
+ jobStatus: z.ZodEnum<{
98
+ failed: "failed";
99
+ completed: "completed";
100
+ cancelled: "cancelled";
101
+ }>;
102
+ }, z.core.$strip>], "transition">;
@@ -774,6 +774,7 @@ export declare const TraceEventInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject
774
774
  stop_inject_dropped: "stop_inject_dropped";
775
775
  stop_hook_continuation: "stop_hook_continuation";
776
776
  stop_hook_cap_reached: "stop_hook_cap_reached";
777
+ orphan_repair: "orphan_repair";
777
778
  }>;
778
779
  durationMs: z.ZodOptional<z.ZodNumber>;
779
780
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -1183,6 +1184,7 @@ export declare const TraceEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1183
1184
  stop_inject_dropped: "stop_inject_dropped";
1184
1185
  stop_hook_continuation: "stop_hook_continuation";
1185
1186
  stop_hook_cap_reached: "stop_hook_cap_reached";
1187
+ orphan_repair: "orphan_repair";
1186
1188
  }>;
1187
1189
  durationMs: z.ZodOptional<z.ZodNumber>;
1188
1190
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -36,6 +36,7 @@ export declare const SessionPhaseNameSchema: z.ZodEnum<{
36
36
  stop_inject_dropped: "stop_inject_dropped";
37
37
  stop_hook_continuation: "stop_hook_continuation";
38
38
  stop_hook_cap_reached: "stop_hook_cap_reached";
39
+ orphan_repair: "orphan_repair";
39
40
  }>;
40
41
  export declare const SessionPhasePayloadSchema: z.ZodObject<{
41
42
  phase: z.ZodEnum<{
@@ -75,6 +76,7 @@ export declare const SessionPhasePayloadSchema: z.ZodObject<{
75
76
  stop_inject_dropped: "stop_inject_dropped";
76
77
  stop_hook_continuation: "stop_hook_continuation";
77
78
  stop_hook_cap_reached: "stop_hook_cap_reached";
79
+ orphan_repair: "orphan_repair";
78
80
  }>;
79
81
  durationMs: z.ZodOptional<z.ZodNumber>;
80
82
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -0,0 +1,106 @@
1
+ import { z } from 'zod';
2
+ export declare const ToolFailureClassSchema: z.ZodEnum<{
3
+ budget: "budget";
4
+ abort: "abort";
5
+ "policy-refusal": "policy-refusal";
6
+ timeout: "timeout";
7
+ "permission-denied": "permission-denied";
8
+ "hook-block": "hook-block";
9
+ "elicitation-declined": "elicitation-declined";
10
+ "denial-breaker": "denial-breaker";
11
+ "repeat-failure": "repeat-failure";
12
+ "no-such-target": "no-such-target";
13
+ }>;
14
+ export declare const SubagentStartedPayloadSchema: z.ZodObject<{
15
+ transition: z.ZodLiteral<"started">;
16
+ subagentId: z.ZodString;
17
+ parentId: z.ZodString;
18
+ model: z.ZodString;
19
+ allowedTools: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
20
+ systemPromptHash: z.ZodOptional<z.ZodString>;
21
+ promptHead: z.ZodOptional<z.ZodString>;
22
+ agentType: z.ZodOptional<z.ZodString>;
23
+ resolvedAgentType: z.ZodOptional<z.ZodString>;
24
+ }, z.core.$strip>;
25
+ export declare const SubagentSucceededPayloadSchema: z.ZodObject<{
26
+ transition: z.ZodLiteral<"succeeded">;
27
+ subagentId: z.ZodString;
28
+ durationMs: z.ZodNumber;
29
+ turnCount: z.ZodNumber;
30
+ totalCostUsd: z.ZodOptional<z.ZodNumber>;
31
+ outputBytes: z.ZodNumber;
32
+ stopReason: z.ZodOptional<z.ZodString>;
33
+ }, z.core.$strip>;
34
+ export declare const SubagentFailedPayloadSchema: z.ZodObject<{
35
+ transition: z.ZodLiteral<"failed">;
36
+ subagentId: z.ZodString;
37
+ errorClass: z.ZodString;
38
+ errorMessage: z.ZodString;
39
+ partialOutputBytes: z.ZodNumber;
40
+ failureClass: z.ZodOptional<z.ZodEnum<{
41
+ budget: "budget";
42
+ abort: "abort";
43
+ "policy-refusal": "policy-refusal";
44
+ timeout: "timeout";
45
+ "permission-denied": "permission-denied";
46
+ "hook-block": "hook-block";
47
+ "elicitation-declined": "elicitation-declined";
48
+ "denial-breaker": "denial-breaker";
49
+ "repeat-failure": "repeat-failure";
50
+ "no-such-target": "no-such-target";
51
+ }>>;
52
+ }, z.core.$strip>;
53
+ export declare const SubagentCancelledPayloadSchema: z.ZodObject<{
54
+ transition: z.ZodLiteral<"cancelled">;
55
+ subagentId: z.ZodString;
56
+ source: z.ZodEnum<{
57
+ explicit: "explicit";
58
+ cascade: "cascade";
59
+ }>;
60
+ timeout: z.ZodOptional<z.ZodBoolean>;
61
+ }, z.core.$strip>;
62
+ export declare const SubagentLifecyclePayloadSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
63
+ transition: z.ZodLiteral<"started">;
64
+ subagentId: z.ZodString;
65
+ parentId: z.ZodString;
66
+ model: z.ZodString;
67
+ allowedTools: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
68
+ systemPromptHash: z.ZodOptional<z.ZodString>;
69
+ promptHead: z.ZodOptional<z.ZodString>;
70
+ agentType: z.ZodOptional<z.ZodString>;
71
+ resolvedAgentType: z.ZodOptional<z.ZodString>;
72
+ }, z.core.$strip>, z.ZodObject<{
73
+ transition: z.ZodLiteral<"succeeded">;
74
+ subagentId: z.ZodString;
75
+ durationMs: z.ZodNumber;
76
+ turnCount: z.ZodNumber;
77
+ totalCostUsd: z.ZodOptional<z.ZodNumber>;
78
+ outputBytes: z.ZodNumber;
79
+ stopReason: z.ZodOptional<z.ZodString>;
80
+ }, z.core.$strip>, z.ZodObject<{
81
+ transition: z.ZodLiteral<"failed">;
82
+ subagentId: z.ZodString;
83
+ errorClass: z.ZodString;
84
+ errorMessage: z.ZodString;
85
+ partialOutputBytes: z.ZodNumber;
86
+ failureClass: z.ZodOptional<z.ZodEnum<{
87
+ budget: "budget";
88
+ abort: "abort";
89
+ "policy-refusal": "policy-refusal";
90
+ timeout: "timeout";
91
+ "permission-denied": "permission-denied";
92
+ "hook-block": "hook-block";
93
+ "elicitation-declined": "elicitation-declined";
94
+ "denial-breaker": "denial-breaker";
95
+ "repeat-failure": "repeat-failure";
96
+ "no-such-target": "no-such-target";
97
+ }>>;
98
+ }, z.core.$strip>, z.ZodObject<{
99
+ transition: z.ZodLiteral<"cancelled">;
100
+ subagentId: z.ZodString;
101
+ source: z.ZodEnum<{
102
+ explicit: "explicit";
103
+ cascade: "cascade";
104
+ }>;
105
+ timeout: z.ZodOptional<z.ZodBoolean>;
106
+ }, z.core.$strip>], "transition">;
@@ -1,4 +1,4 @@
1
- export type SessionPhaseName = 'bootstrap_start' | 'bootstrap_done' | 'session_init_start' | 'session_init_done' | 'mcp_connect_start' | 'mcp_connect_done' | 'mcp_server_start' | 'mcp_server_done' | 'loop_start' | 'loop_end' | 'model_ttfb' | 'interrupt_halt' | 'rate_limit' | 'ttfb_timeout' | 'usage_limit_pause' | 'usage_limit_resume' | 'overload_pause' | 'overload_resume' | 'idle_watchdog_fired' | 'pause_extension_granted' | 'suspected_loop' | 'compaction_disabled' | 'boot_warning' | 'workspace_subscribed' | 'workspace_delivery' | 'gate_shape' | 'session_id_assigned' | 'many_image_degraded' | 'stream_accepted_after_drop' | 'connection_retry' | 'usage_notice' | 'tool_degraded' | 'strategy_nudge_fired' | 'stop_inject_dropped' | 'stop_hook_continuation' | 'stop_hook_cap_reached';
1
+ export type SessionPhaseName = 'bootstrap_start' | 'bootstrap_done' | 'session_init_start' | 'session_init_done' | 'mcp_connect_start' | 'mcp_connect_done' | 'mcp_server_start' | 'mcp_server_done' | 'loop_start' | 'loop_end' | 'model_ttfb' | 'interrupt_halt' | 'rate_limit' | 'ttfb_timeout' | 'usage_limit_pause' | 'usage_limit_resume' | 'overload_pause' | 'overload_resume' | 'idle_watchdog_fired' | 'pause_extension_granted' | 'suspected_loop' | 'compaction_disabled' | 'boot_warning' | 'workspace_subscribed' | 'workspace_delivery' | 'gate_shape' | 'session_id_assigned' | 'many_image_degraded' | 'stream_accepted_after_drop' | 'connection_retry' | 'usage_notice' | 'tool_degraded' | 'strategy_nudge_fired' | 'stop_inject_dropped' | 'stop_hook_continuation' | 'stop_hook_cap_reached' | 'orphan_repair';
2
2
  export interface SessionPhasePayload {
3
3
  phase: SessionPhaseName;
4
4
  durationMs?: number;
@@ -1,13 +1,72 @@
1
1
  ---
2
2
  name: automate
3
- description: "Set up a scheduled headless afk run that pushes a summary to Telegram. Use when the user wants to automate a recurring task via the afk daemon scheduler (cron) with push-notified results."
3
+ description: "Set up a scheduled headless afk run that pushes a summary to Telegram. Accepts a task description, directory path, or session ID — for session IDs, runs an isolation-contamination probe via read_witness to assess automation fit before gating on an explicit APPROVE token. Use when the user wants to automate a recurring task via the afk daemon scheduler (cron) with push-notified results."
4
4
  disable-model-invocation: true
5
5
  context: load
6
+ failure_modes:
7
+ - contaminated fit verdict (probe sub-agent receives original session rationale)
8
+ - APPROVE token accepted without presenting command sequence preview
9
+ - schedule created without confirming Telegram end-to-end
6
10
  ---
7
11
 
8
12
  Set up a recurring headless task using afk's **native** scheduler. Do NOT hand-roll launchd plists or shell scripts — afk has first-class scheduling: the `create_schedule` tool writes `~/.afk/config/schedules.json` entries that `afk daemon` runs on cron.
9
13
 
14
+ ## Input routing
15
+
16
+ The argument is one of three forms:
17
+ - **Task description / directory path** — proceed directly to the Scout + Prompt designer wave below.
18
+ - **Session ID** — run the fit-assessment flow first (Waves 0–1 + authorization gate) to determine whether the session is automatable before building a schedule.
19
+
20
+ ---
21
+
22
+ ## Session ID path: fit-assessment
23
+
24
+ ### Wave 0 — Signal extraction (orchestrator, synchronous)
25
+
26
+ Read the session facet with `get_facet` (pass `fields: ["duration_minutes", "user_message_count"]` so the goal and first prompt never enter the extraction) and the session's tool calls with `read_witness` (`kinds: ["tool_call"]`), then extract four flat signals:
27
+
28
+ - `duration` — the facet's `duration_minutes`
29
+ - `user_messages` — the facet's `user_message_count`. Do not count witness events for this: the trace records no user turns, and its `queued_user_message` events cover only messages typed mid-turn, so they undercount.
30
+ - `llm_branch_steps` — count of tool calls whose branch condition is model output rather than exit code (i.e., tool calls following a reasoning step that is not mechanically determined)
31
+ - `command_sequence` — ordered list of distinct bash/shell commands issued, with item count
32
+
33
+ Emit **Artifact 1**: `duration=Xm, user_messages=N, llm_branch_steps=M, command_sequence=[cmd1, cmd2, …] (K distinct commands)`. This is the only input forwarded to Wave 1 — the session ID, original user message, and any rationale are withheld.
34
+
35
+ ### Wave 1 — Automation-fit probe (isolated sub-agent)
36
+
37
+ Receives Artifact 1 **only**. Denied: session ID, original user message, any framing about why the task was run manually. Denied write tools.
38
+
39
+ Applies the five-point rubric:
40
+
41
+ | Criterion | Points |
42
+ |---|---|
43
+ | `duration ≤ 10m` | +1 |
44
+ | `user_messages ≤ 2` | +1 |
45
+ | `llm_branch_steps == 0` | +1 |
46
+ | Command sequence is idempotent with no destructive commands lacking a guard | +1 |
47
+ | No step requires live user judgment | +1 |
48
+
49
+ Emits one of:
50
+ - `FIT [score=N]` (≥ 4) — proceed to gate
51
+ - `PARTIAL [score=N, guard=<exact modification required>]` (2–3) — surface the guard to the user before the gate; do not proceed until acknowledged
52
+ - `UNFIT [score=N]` (≤ 1) — halt with explanation; do not generate a schedule
53
+
54
+ ### Authorization gate
55
+
56
+ For FIT or acknowledged-PARTIAL verdicts, the orchestrator presents the proposed schedule: name, cron expression, and command sequence preview. Waits for an explicit token:
57
+
58
+ - `APPROVE` (or bare "yes") — proceed to Scout + schedule creation
59
+ - `MODIFY <field> <value>` — adjust one parameter and re-present
60
+ - `ABORT` — exit with `AUTOMATED_NOTHING`
61
+
62
+ Do not proceed to schedule creation until APPROVE is recorded.
63
+
64
+ ---
65
+
66
+ ## Schedule creation (all paths)
67
+
10
68
  Dispatch two sub-agents in parallel:
69
+
11
70
  1. **Scout** — call `list_schedules` and inspect `~/.afk/config/schedules.json` for existing or overlapping jobs, run `afk service status` to see whether the daemon is installed as a launchd service and running, confirm Telegram is configured (`TELEGRAM_BOT_TOKEN` + `AFK_TELEGRAM_ALLOWED_CHAT_IDS`), and scan the target project folder for conventions. Report conflicts, daemon/service state, and any missing prerequisite.
12
71
  2. **Prompt designer** — draft the recurring task's `command` string: a self-contained prompt (or `/skill --flags` invocation) sent verbatim into a freshly spawned session each run. The daemon session starts cold, so encode all input context explicitly, and require the run to END by calling the `send_telegram` tool with a concise, push-ready summary.
13
72
 
@@ -17,3 +76,13 @@ When both return:
17
76
  - Schedules only fire while the daemon is running, so make it survive reboot/crash: if `afk service status` shows the daemon isn't installed, run `afk service install daemon` (launchd `RunAtLoad` + `KeepAlive` on macOS).
18
77
 
19
78
  Dispatch a **verification** sub-agent to confirm the job registered (`list_schedules`), the daemon is running (`afk service status`), and — by running the task's `command` once as a one-shot (`afk chat "<command>"`) — that the Telegram summary actually arrives. On failure, diagnose (Telegram config, daemon not running, cron syntax, prompt shape) and fix before exiting. Report the schedule id, cron, `notifyOn`, daemon/service status, and the next scheduled run.
79
+
80
+ ## Completeness contract (session ID path only)
81
+
82
+ Before claiming Done, confirm all five items are present in the terminal report:
83
+
84
+ 1. **Wave 0 signal report** — duration, user-message count, LLM-branch count, command sequence with item count stated
85
+ 2. **Wave 1 fit verdict** — score and tier (FIT / PARTIAL / UNFIT) stated
86
+ 3. **Authorization token** — APPROVE, MODIFY \<field\> \<value\>, or ABORT recorded
87
+ 4. **Schedule artifact** — schedule ID and cron expression stated
88
+ 5. **PARTIAL guard** — if applicable, exact guard surfaced to user before the gate
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: shadow-verify
3
- description: "Dispatch a parallel adversarial verifier wave after any high-stakes sub-agent investigation (code reviews, audits, findings reports, large refactors, gap analyses) — or whenever a sub-agent asserts a claim with high-confidence language (\"confident\", \"certain\", \"clearly\", ≥80%), since confidence is a trigger, not a verdict. Shadow verifiers independently re-derive 2–3 key claims from scratch using tool calls only, returning CONFIRMED/REFUTED/STALE/UNVERIFIABLE, and flag disagreements before the user acts. Use when sub-agent output will drive decisions, file changes, commits, or external side-effects."
3
+ description: "Dispatch a parallel adversarial verifier wave after any high-stakes sub-agent investigation (code reviews, audits, findings reports, large refactors, gap analyses) — or whenever a sub-agent asserts a claim with high-confidence language (\"confident\", \"certain\", \"clearly\", ≥80%), since confidence is a trigger, not a verdict. Default mode: shadow verifiers independently re-derive 2–3 key claims from scratch using tool calls only. --findings-list mode: exhaustively verifies every finding in a pre-existing findings document before any action phase is dispatched, producing a numbered completeness checklist and a terminal gate verdict (VERIFIED/PARTIAL/BLOCKED). Both modes return CONFIRMED/REFUTED/STALE/UNVERIFIABLE verdicts and flag disagreements before the user acts."
4
+ argument-hint: "[--findings-list <file | inline-findings>] [--goal <session-goal>] [--action <planned-action>]"
4
5
  context: load
5
6
  ---
6
7
 
@@ -9,29 +10,43 @@ context: load
9
10
 
10
11
  When a sub-agent (or wave) returns investigation findings, code-review conclusions, audit claims, refactor plans, gap-analysis results, or counts that will drive user decisions or file changes, do NOT surface the report. Instead, run a shadow verification wave **before** merging.
11
12
 
13
+ ---
14
+
15
+ ## Invocation modes
16
+
17
+ This skill has two invocation modes that share the same verifier machinery, normalization pre-flight, merge rules, gate logic, and composition-axis guard — but differ in scope and output shape.
18
+
19
+ **Default mode (no flag):** Sample 2–3 highest-stakes claims from a sub-agent's live output and verify them before surfacing the report. Optimized for latency — catches critical errors without blocking on exhaustive coverage.
20
+
21
+ **`--findings-list` mode:** Exhaustively verify every finding in a pre-existing findings document (a file path or inline text) before any downstream action phase is dispatched. Every finding 1–N must appear in the output checklist — no finding may be omitted or left blank. Produces a terminal gate verdict (`VERIFIED` / `PARTIAL` / `BLOCKED`) that controls whether a downstream action phase may proceed. Use this when an operator supplies a research-phase output and wants a completeness guarantee before committing to action.
22
+
23
+ ---
24
+
12
25
  ### Pre-flight: claim normalization and scale guard
13
26
 
14
- Before dispatching verifiers, the coordinating agent normalizes each claim to a canonical form:
27
+ Before dispatching any verifiers (in either mode), the coordinating agent normalizes each finding/claim to a canonical tuple:
15
28
 
16
29
  ```
17
- [CLAIM_ID] <subject> :: <predicate> :: <evidence_ref>
30
+ [FINDING_ID] <subject> :: <predicate> :: <evidence_ref>
18
31
  ```
19
32
 
20
- `evidence_ref` must be a concrete pointer — a file path, line number, git ref, config key, or API endpoint. Claims that cannot be anchored to a concrete `evidence_ref` are classified **`UNVERIFIABLE`** immediately and removed from the verification queue. They are preserved in the final output under a dedicated section with the reason they could not be anchored (no re-derivation sub-agent is dispatched for them).
33
+ `evidence_ref` must be a concrete pointer — a file path, line number, git ref, config key, or API endpoint. Claims that cannot be anchored to a concrete `evidence_ref` are classified **`UNVERIFIABLE`** immediately and removed from the verification queue. They are preserved in the final output under a **dedicated UNVERIFIABLE section** with the reason they could not be anchored (no re-derivation sub-agent is dispatched for them).
21
34
 
22
- **Scale cap:** if the normalized claim list exceeds 50 items, the coordinating agent halts and asks the operator to scope the investigation before proceeding. Verification at scale degrades into noise; a 50-item cap prevents a finding flood from becoming an echo-chamber rubber-stamp.
35
+ **Scale cap:**
36
+ - *Default mode:* if the normalized claim list exceeds 50 items, the coordinating agent halts and asks the operator to scope the investigation before proceeding. Verification at scale degrades into noise; a 50-item cap prevents a finding flood from becoming an echo-chamber rubber-stamp.
37
+ - *`--findings-list` mode:* if the normalized findings list exceeds 30 items, the orchestrator halts and asks the operator to scope before proceeding. Exhaustive verification is more expensive per item; a tighter cap prevents runaway fan-out.
23
38
 
24
- Select 2–3 of the highest-stakes normalized claims to send to the verifier wave. Prefer claims that are (a) decision-driving, (b) expressed with high-confidence language, or (c) hard to re-derive from a single artifact.
39
+ **Claim selection (default mode only):** After normalization, select 2–3 of the highest-stakes normalized claims to send to the verifier wave. Prefer claims that are (a) decision-driving, (b) expressed with high-confidence language, or (c) hard to re-derive from a single artifact. In `--findings-list` mode, every finding after normalization enters the queue — no sampling.
25
40
 
26
41
  ---
27
42
 
28
43
  **Wave 2 — Adversarial verifiers (parallel, independent):**
29
- 1. Extract 2–3 concrete, re-checkable claims from the returned report (e.g., "X function is unused", "file Y exceeds 300 lines", "PR targets main", "no tests cover Z") and normalize them to `[CLAIM_ID] subject :: predicate :: evidence_ref` form as described above.
44
+ 1. Normalize claims as described above. In default mode, extract 2–3 concrete, re-checkable claims from the returned report (e.g., "X function is unused", "file Y exceeds 300 lines", "PR targets main", "no tests cover Z"). In `--findings-list` mode, all normalized findings enter the queue.
30
45
  2. Dispatch one shadow sub-agent per claim, in parallel. Each receives the normalized claim text + the user's original goal + **the search surface** — the inventory of files, directories, or URLs the original investigation touched. It must NOT receive the original agent's reasoning, verdict, confidence language, or the specific line/region it concluded from. **Withhold the conclusion, not the map.** Withholding the map too does not buy extra independence — the verifier still has to reach the same evidence, it just spends its budget guessing paths to get there. Measured: one verifier denied the inventory spent 70 `grep` + 18 `read_file` calls re-locating files the parent already had paths for, guessed 5 nonexistent paths on the way, and hit its tool-loop ceiling before finishing. The independence that matters is epistemic (re-deriving the verdict), not navigational.
31
46
  - The inventory is a **starting surface, not a boundary**: it does not satisfy the composition-axis guard below, and a verifier that reads only inside it still returns `evidence_base: artifact-internal`. At least one primary source outside that surface is still required for `independent-rederivation`.
32
47
  - **Default to `subagent_type: "research-agent"` (mechanically locked to Read/Grep/Glob/WebFetch/WebSearch — cannot Edit/commit/push).** If the claim requires Bash to verify (running a failing test, `gh pr view`, `git log origin/...`), fall back to a Bash-capable subagent type with `isolation: "worktree"` and prepend this prefix to the prompt: *"Verifier sub-agent — do not Edit, Write, commit, push, `gh pr create`, or `curl`. Return findings only."*
33
48
  - **Set `id_prefix`** to a short label identifying the claim being verified, e.g. `"verify: unused export"` or `"verify: missing null check"`, so the live TUI shows which claim each verifier is checking.
34
- - **Every verifier dispatch carries an explicit budget** — `max_tool_use_iterations` (a wave of 2–3 claim checks needs ~15–25 rounds each, not 50) plus the cheapest sufficient model. An unbudgeted verifier does not fail loudly: it exhausts the default tool-round ceiling, terminates `stopReason: "tool_use_loop_capped"`, and emits its verdict from a tools-stripped wind-down round built on partial evidence. A `CONFIRMED` produced that way is indistinguishable from a real one and silently defeats the entire point of the wave. Check each returned verifier's stop reason before merging its verdict; treat a capped or wind-down verifier as `UNVERIFIABLE`, not as a verdict.
49
+ - **Every verifier dispatch carries an explicit budget** — `max_tool_use_iterations` (a wave of 2–3 claim checks needs ~15–25 rounds each, not 50; `--findings-list` waves with many findings should budget proportionally but cap individual verifiers at 12 rounds each) plus the cheapest sufficient model. An unbudgeted verifier does not fail loudly: it exhausts the default tool-round ceiling, terminates `stopReason: "tool_use_loop_capped"`, and emits its verdict from a tools-stripped wind-down round built on partial evidence. A `CONFIRMED` produced that way is indistinguishable from a real one and silently defeats the entire point of the wave. Check each returned verifier's stop reason before merging its verdict; treat a capped or wind-down verifier as `UNVERIFIABLE`, not as a verdict.
35
50
  3. Each verifier re-derives the verdict independently using tool calls only — never re-reading the original report's reasoning. Returns `{claim_id, verifier_verdict, evidence_pointer, evidence_base}`, where `verifier_verdict` is one of `CONFIRMED`, `REFUTED`, `STALE`, or `UNVERIFIABLE`, and `evidence_base` is `independent-rederivation` (read primary sources *outside* the cited artifact's boundary) or `artifact-internal` (re-read only the cited file/region). On `REFUTED` or `STALE`, the verifier also emits a corrected or updated finding.
36
51
 
37
52
  ---
@@ -53,7 +68,9 @@ Bound the loop: at most 3 verification rounds per session. Claims still unresolv
53
68
 
54
69
  **Gate verdict:**
55
70
 
56
- After all verifier results are merged, the coordinating agent emits a single gate verdict before surfacing findings downstream:
71
+ After all verifier results are merged, the coordinating agent emits a single gate verdict before surfacing findings downstream. The verdict shape differs by mode:
72
+
73
+ *Default mode:*
57
74
 
58
75
  | Verdict | Condition |
59
76
  |---|---|
@@ -61,7 +78,31 @@ After all verifier results are merged, the coordinating agent emits a single gat
61
78
  | `WARN` | One or more claims are `STALE`, `UNVERIFIABLE`, or `UNVERIFIED-COMPOSITION`/`UNVERIFIED-ECHO-CHAMBER`; proceed only with explicit caveats attached |
62
79
  | `FAIL` | One or more claims `REFUTED`; findings must not be forwarded until re-investigated |
63
80
 
64
- A `FAIL` verdict blocks downstream use. The coordinating agent surfaces the specific refuted claims and their contradicting evidence to the operator before any remediation work begins. A `WARN` may proceed but must carry the flagged claims and their tags — stripping the caveats before forwarding is a protocol violation.
81
+ *`--findings-list` mode* — emit a numbered completeness checklist followed by a terminal gate verdict:
82
+
83
+ ```
84
+ Verification checklist (N findings total):
85
+ [1] <finding summary> → CONFIRMED (file:line)
86
+ [2] <finding summary> → REFUTED (contradicting_pointer) [was: confident, now: refuted]
87
+ [3] <finding summary> → STALE (updated_pointer) [was true, now stale]
88
+ [4] <finding summary> → UNVERIFIABLE (reason: no concrete evidence_ref) [needs-human-review]
89
+ ...
90
+
91
+ UNVERIFIABLE findings (pre-flight, no verifier dispatched):
92
+ [5] <finding summary> → UNVERIFIABLE (reason: file not found)
93
+
94
+ Gate verdict: BLOCKED — finding [2] refuted; do not proceed to action phase.
95
+ ```
96
+
97
+ Terminal gate verdicts for `--findings-list` mode:
98
+
99
+ | Verdict | Condition |
100
+ |---|---|
101
+ | `VERIFIED` | All findings are `CONFIRMED` or `UNVERIFIABLE` with annotation; action phase may proceed |
102
+ | `PARTIAL` | ≥1 finding is `STALE` or `UNVERIFIABLE [budget-exhausted]`; proceed with explicit caveats |
103
+ | `BLOCKED` | ≥1 finding is `REFUTED`; action phase must not be dispatched until the operator resolves the conflict or re-scopes the finding list |
104
+
105
+ In both modes: a `FAIL` / `BLOCKED` verdict blocks downstream use. The coordinating agent surfaces the specific refuted claims and their contradicting evidence to the operator before any remediation work begins. A `WARN` / `PARTIAL` may proceed but must carry the flagged claims and their tags — stripping the caveats before forwarding is a protocol violation.
65
106
 
66
107
  ---
67
108
 
@@ -78,6 +119,8 @@ A verifier that re-derives a claim by re-reading the *same* file/region the orig
78
119
  **When to invoke:**
79
120
  Any time sub-agent output will drive user decisions, file edits, commits, external side-effects, or is the basis of a user-facing summary — including gap analyses, audit findings, and issue lists that will be forwarded to a downstream session. Treat **high-confidence language as a trigger in its own right**: when a review/audit sub-agent asserts a claim with markers like "confident", "certain", "clearly", "obviously", "must be", or a stated probability ≥ 80%, verify it as if it were decision-driving regardless of stakes. Confidence is a trigger, not a verdict.
80
121
 
122
+ Use `--findings-list` when the operator supplies a pre-existing findings document (from a prior research session, a handed-off report, or an audit output) and needs a completeness guarantee — a numbered checklist with every finding accounted for — before an action phase is dispatched.
123
+
81
124
  **Skip when:**
82
125
  Sub-agent ran inside an orchestrator skill that already verifies (`resolve`, `diagnose`, `appmap`); sub-agent returned explicit failure; work was purely exploratory and no decision follows; or the session is **text-terminal** — a pure explanation, architecture walkthrough, onboarding Q&A, or capability map that names no mutated artifact (file/PR/commit/test), where there are no re-checkable state claims for adversarial verifiers to re-derive (assess coverage, coherence, and citation density instead of dispatching re-derivation sub-agents).
83
126
 
@@ -11,6 +11,7 @@ export declare function checkXaiAuth(): Promise<Check>;
11
11
  export interface NpmBinOnPathDeps {
12
12
  platform?: NodeJS.Platform;
13
13
  pathDelimiter?: string;
14
+ execSync?: typeof import('child_process').execSync;
14
15
  }
15
16
  export declare function checkNpmBinOnPath(deps?: NpmBinOnPathDeps): Promise<Check>;
16
17
  export declare function checkDirWritable(name: string, getDir: () => string): Promise<Check>;