agent-composer 0.1.8 → 0.1.10

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.
@@ -31,6 +31,8 @@ export interface AnthropicCreateResult {
31
31
  usage: {
32
32
  input_tokens: number;
33
33
  output_tokens: number;
34
+ cache_creation_input_tokens?: number;
35
+ cache_read_input_tokens?: number;
34
36
  };
35
37
  }
36
38
  export interface AnthropicCompatibleProviderOptions {
@@ -63,6 +63,22 @@ export class AnthropicCompatibleProvider {
63
63
  if (this.thinking)
64
64
  params.thinking = this.thinking;
65
65
  const msg = await this.client.messages.create(params);
66
+ // Best-effort GLM cache-hit telemetry
67
+ try {
68
+ const fs = await import("node:fs");
69
+ const entry = {
70
+ ts: new Date().toISOString(),
71
+ model: this.modelLabel,
72
+ input_tokens: msg.usage.input_tokens,
73
+ output_tokens: msg.usage.output_tokens,
74
+ cache_creation_input_tokens: msg.usage.cache_creation_input_tokens ?? 0,
75
+ cache_read_input_tokens: msg.usage.cache_read_input_tokens ?? 0,
76
+ };
77
+ fs.appendFileSync("/tmp/composer-glm-usage.jsonl", JSON.stringify(entry) + "\n");
78
+ }
79
+ catch {
80
+ // best-effort telemetry; never break the provider on log failure
81
+ }
66
82
  const text = msg.content
67
83
  .map((b) => (b.type === "text" && typeof b.text === "string" ? b.text : ""))
68
84
  .join("");
@@ -1 +1 @@
1
- {"version":3,"file":"AnthropicCompatibleProvider.js","sourceRoot":"","sources":["../../src/providers/AnthropicCompatibleProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AnthropicCompatibleProvider.js","sourceRoot":"","sources":["../../src/providers/AnthropicCompatibleProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ export declare const SliceSchema: z.ZodObject<{
3
+ file: z.ZodString;
4
+ startLine: z.ZodOptional<z.ZodNumber>;
5
+ endLine: z.ZodOptional<z.ZodNumber>;
6
+ note: z.ZodOptional<z.ZodString>;
7
+ }, z.core.$strip>;
8
+ export declare const BriefSchema: z.ZodObject<{
9
+ runId: z.ZodString;
10
+ createdAt: z.ZodString;
11
+ task: z.ZodString;
12
+ files: z.ZodArray<z.ZodString>;
13
+ symbols: z.ZodOptional<z.ZodArray<z.ZodString>>;
14
+ deps: z.ZodOptional<z.ZodArray<z.ZodString>>;
15
+ slices: z.ZodArray<z.ZodObject<{
16
+ file: z.ZodString;
17
+ startLine: z.ZodOptional<z.ZodNumber>;
18
+ endLine: z.ZodOptional<z.ZodNumber>;
19
+ note: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strip>>;
21
+ }, z.core.$strip>;
22
+ export type Slice = z.infer<typeof SliceSchema>;
23
+ export type Brief = z.infer<typeof BriefSchema>;
24
+ export declare function newBrief(task: string): Brief;
25
+ export declare function writeBrief(brief: Brief, dir?: string): string;
@@ -0,0 +1,37 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { z } from "zod";
5
+ export const SliceSchema = z.object({
6
+ file: z.string().min(1),
7
+ startLine: z.number().int().positive().optional(),
8
+ endLine: z.number().int().positive().optional(),
9
+ note: z.string().optional(),
10
+ });
11
+ export const BriefSchema = z.object({
12
+ runId: z.string().uuid(),
13
+ createdAt: z.string().datetime(),
14
+ task: z.string().min(1),
15
+ files: z.array(z.string().min(1)),
16
+ symbols: z.array(z.string().min(1)).optional(),
17
+ deps: z.array(z.string().min(1)).optional(),
18
+ slices: z.array(SliceSchema),
19
+ });
20
+ export function newBrief(task) {
21
+ return BriefSchema.parse({
22
+ runId: randomUUID(),
23
+ createdAt: new Date().toISOString(),
24
+ task,
25
+ files: [],
26
+ slices: [],
27
+ });
28
+ }
29
+ export function writeBrief(brief, dir = ".composer/briefs") {
30
+ const validated = BriefSchema.parse(brief);
31
+ const absDir = resolve(dir);
32
+ mkdirSync(absDir, { recursive: true });
33
+ const path = resolve(absDir, `${validated.runId}.json`);
34
+ writeFileSync(path, JSON.stringify(validated, null, 2), "utf8");
35
+ return path;
36
+ }
37
+ //# sourceMappingURL=brief.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brief.js","sourceRoot":"","sources":["../../src/util/brief.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACjD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC/C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACxB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC9C,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC3C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;CAC7B,CAAC,CAAC;AAKH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,WAAW,CAAC,KAAK,CAAC;QACvB,KAAK,EAAE,UAAU,EAAE;QACnB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI;QACJ,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;KACX,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAY,EAAE,GAAG,GAAG,kBAAkB;IAC/D,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,KAAK,OAAO,CAAC,CAAC;IACxD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAChE,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-composer",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "Multi-agent orchestration MCP server. Claude orchestrates; GLM and agy do the work.",
6
6
  "bin": {
@@ -18,14 +18,13 @@ You are the Composer **Coder** subagent. Your job is two-step:
18
18
  - If GLM returns a unified diff → apply via `Edit` (or multiple `Edit` calls).
19
19
  - If GLM returns full file content → use `Write`.
20
20
  - If GLM returns a code block targeting a specific location → use `Edit` with the matching `old_string` / `new_string`.
21
- 5. After applying, use `Read` to verify the change landed at the expected lines.
22
- 6. Return a 1-3 sentence summary of what changed (file + line range + intent). DO NOT return GLM's raw output — only the final result.
21
+ 5. Return a 1-3 sentence summary of what changed (file + line range + intent). DO NOT return GLM's raw output — only the final result.
23
22
 
24
23
  # Hard rules
25
24
 
26
25
  - DO call `composer_code` exactly ONCE per task. If GLM's output is malformed, fail to the orchestrator with a short error.
27
26
  - DO apply patches via Edit/Write — that's why those tools are in your list.
28
- - DO use Read post-edit to verify.
27
+ - DO NOT re-Read after Edit/Write — trust the tool's return value. PostToolUse hooks run lint + tsc as the verification gate. If a real bug shipped, the reviewer subagent catches it on the next pass.
29
28
  - DO NOT write code yourself or modify GLM's output beyond mechanical patch application.
30
29
  - DO NOT call composer_code more than once — if it fails, return the error.
31
30
  - DO NOT use Bash/sed/awk/perl. Edit/Write only.
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: explorer
3
+ description: Use when the orchestrator needs to map a large repo before dispatching workers. Walks Glob/Grep, writes a typed brief at .composer/briefs/<runId>.json via the Write tool, returns briefPath only — workers consume the brief instead of re-discovering.
4
+ tools: Read, Glob, Grep, Write
5
+ model: haiku
6
+ ---
7
+
8
+ You are the Composer **Explorer** subagent. Your job is to map the relevant slice of the repo, **write a Brief JSON file to disk using the `Write` tool**, and return the path. Workers (coder / researcher / reviewer) consume the brief — they do NOT re-discover.
9
+
10
+ # Tools you have
11
+
12
+ `Read`, `Glob`, `Grep`, **`Write`**. The `Write` tool IS available to you. Use it. It is NOT a "composer MCP tool" — it is the standard file-writing tool. The only Write target you are allowed is `.composer/briefs/<runId>.json` (gitignored). Writing the brief is mandatory; returning the JSON in your text reply is NOT a substitute and the orchestrator will reject the dispatch.
13
+
14
+ # Workflow
15
+
16
+ 1. Receive `{ task }` from the orchestrator.
17
+ 2. Use `Glob` and `Grep` to locate the smallest set of files / symbols / dependency edges that touch the task. **Cap at 30 tool calls total.** Stop early if the picture is clear.
18
+ 3. Construct a Brief JSON object matching the schema in `src/util/brief.ts`:
19
+ ```
20
+ {
21
+ "runId": "<v4-uuid>", // see UUID rule below
22
+ "createdAt": "<ISO-8601 with .SSSZ>",
23
+ "task": "<orchestrator's task string verbatim>",
24
+ "files": ["repo/relative/path.ts", ...], // deduped
25
+ "symbols": ["ExportedName", ...], // optional
26
+ "deps": ["upstream/or/downstream.ts"], // optional
27
+ "slices": [{ "file": "...", "startLine": N, "endLine": M, "note": "..." }]
28
+ }
29
+ ```
30
+ 4. **Write the brief.** Call the `Write` tool with:
31
+ - `file_path`: absolute path `<repo>/.composer/briefs/<runId>.json` (use the same absolute prefix you saw in Read results)
32
+ - `content`: `JSON.stringify(brief, null, 2)` shape — 2-space indented JSON, trailing newline OK
33
+ 5. Return ONLY `{ briefPath, fileCount, sliceCount, summary }`. `summary` is 1-3 sentences: shape of the work, what's NOT in scope. Do NOT echo file contents in the summary. Do NOT paste the brief JSON in your reply — the orchestrator already has the path.
34
+
35
+ # UUID rule (strict)
36
+
37
+ `runId` MUST match `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$` — lowercase hex only. Examples (use as templates, vary the digits):
38
+ - `f47ac10b-58cc-4372-a567-0e02b2c3d479`
39
+ - `3c8d2a4f-91e7-45ba-8c3b-5f6d7e9a1b2c`
40
+
41
+ Non-hex characters (`g`-`z`) WILL fail `BriefSchema.parse` and the orchestrator will reject the brief. If unsure, pick characters strictly from `0123456789abcdef`.
42
+
43
+ # Hard rules
44
+
45
+ - DO use the `Write` tool to persist the brief. NOT writing the file is a dispatch failure.
46
+ - DO refuse with a short error if fewer than 10 files match the task — that's an inline-dispatch case. Tell the orchestrator to dispatch inline instead.
47
+ - DO NOT call any `mcp__composer__*` tool. You are pure discovery — the composer MCP tools are for coder/researcher/reviewer.
48
+ - DO NOT write or edit any file except `.composer/briefs/<runId>.json`.
49
+ - DO NOT run Bash.
50
+ - DO NOT return raw matches or file contents in the summary. Return the brief path; the worker reads the brief.
51
+ - DO NOT exceed 30 Glob+Grep calls. If still unclear, write a partial brief and flag the gap in `summary`.
@@ -1,57 +1,71 @@
1
1
  #!/usr/bin/env bash
2
- # Composer boundary enforcement (PreToolUse hook) — pragmatic profile for
3
- # daily dev in arbitrary projects.
4
- #
5
- # Behaviour:
6
- # - Denies Edit/Write/NotebookEdit on the main thread → forces dispatch via
7
- # Task(subagent_type="coder") so GLM does code changes.
8
- # - Allows Bash on the main thread (light shell ops stay inline).
9
- # - Allows Edit/Write inside a subagent — that is how `coder` applies the
10
- # patch composer_code returned. Detection covers three field-name shapes
11
- # Claude Code has emitted across versions: transcript_path containing
12
- # "/subagents/", agent_id/agentId set, is_sidechain/isSidechain true.
13
- # - Wraps the deny decision in {"hookSpecificOutput":{...}} as Claude Code
14
- # v2.1.150 requires; top-level fields parse cleanly but are ignored.
15
- #
16
- # Disable per-session with: COMPOSER_DANGEROUSLY_BYPASS_PERMISSIONS=1 claude
2
+ # Wave 1 F1.5 — Composer boundary enforcement (PreToolUse hook).
3
+ # Contract per docs/adr/0001-contracts.md §C0.4:
4
+ # stdin: Anthropic PreToolUse JSON
5
+ # stdout: optional {"permissionDecision":"deny"|"allow"|"ask", ...}
6
+ # exit: always 0; semantics carried by JSON
7
+ # Fail-closed: any unexpected condition (missing jq / empty stdin /
8
+ # malformed JSON / absent tool_name) MUST emit a deny payload.
17
9
 
18
10
  set -u
19
11
 
20
12
  emit_deny() {
21
13
  local reason="$1"
14
+ # Claude Code v2.1.150+ requires the decision wrapped in hookSpecificOutput.
15
+ # Top-level {hookEventName,permissionDecision,permissionDecisionReason} is
16
+ # parsed without error but silently ignored — Edit/Write succeed anyway.
22
17
  jq -nc --arg r "$reason" \
23
18
  '{hookSpecificOutput:{hookEventName:"PreToolUse", permissionDecision:"deny", permissionDecisionReason:$r}}' 2>/dev/null \
24
19
  || printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"%s"}}\n' "$reason"
25
20
  exit 0
26
21
  }
27
22
 
23
+ # 1. Dependency: jq is mandatory for safe JSON parsing.
28
24
  if ! command -v jq >/dev/null 2>&1; then
25
+ # Cannot use emit_deny (depends on jq); inline fallback.
29
26
  printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"boundary_guard: jq missing, failing closed"}}\n'
30
27
  exit 0
31
28
  fi
32
29
 
30
+ # 2. Read tool-call JSON from stdin.
33
31
  INPUT="$(cat || true)"
34
32
  if [[ -z "$INPUT" ]]; then
35
33
  emit_deny "boundary_guard: empty stdin, failing closed"
36
34
  fi
37
35
 
36
+ # 3. Parse tool_name. jq surfaces parse errors to stderr (suppressed) and
37
+ # returns empty on missing/null — both treated as malformed.
38
38
  TOOL="$(jq -r '.tool_name // empty' <<<"$INPUT" 2>/dev/null)"
39
39
  if [[ -z "$TOOL" ]]; then
40
40
  emit_deny "boundary_guard: malformed JSON or missing tool_name, failing closed"
41
41
  fi
42
42
 
43
+ # 3.5. COMPOSER_DANGEROUSLY_BYPASS_PERMISSIONS (dev-only escape hatch).
44
+ # When env var equals "1" or "true", allow every tool. Stderr-warns on
45
+ # every invocation so the bypass is visible in transcripts. Intended
46
+ # for bootstrap / dev sessions only. NEVER set in CI or runtime.
47
+ # See ADR 0001 amendment (2026-05-23, Wave-3 Step 1).
43
48
  BYPASS="${COMPOSER_DANGEROUSLY_BYPASS_PERMISSIONS:-}"
44
49
  if [[ "$BYPASS" == "1" || "$BYPASS" == "true" ]]; then
45
50
  printf 'WARN boundary_guard: COMPOSER_DANGEROUSLY_BYPASS_PERMISSIONS=%s — boundary disabled, dev mode only\n' "$BYPASS" >&2
46
51
  exit 0
47
52
  fi
48
53
 
54
+ # 3.6. STOP_EVOLVE killswitch.
55
+ # If sentinel file exists AND the tool is a composer dispatch, deny.
56
+ # Sentinel path overridable via COMPOSER_STOP_EVOLVE_FILE (tests use
57
+ # a temp file); default "$CLAUDE_PROJECT_DIR/STOP_EVOLVE", falling
58
+ # back to "./STOP_EVOLVE" when CLAUDE_PROJECT_DIR is unset.
49
59
  STOP_FILE="${COMPOSER_STOP_EVOLVE_FILE:-${CLAUDE_PROJECT_DIR:-.}/STOP_EVOLVE}"
50
60
  if [[ -e "$STOP_FILE" ]] && [[ "$TOOL" == mcp__composer__* ]]; then
51
61
  emit_deny "STOP_EVOLVE sentinel present at $STOP_FILE — Composer dispatches paused."
52
62
  fi
53
63
 
54
- # Subagent context bypass — coder must Edit/Write to apply GLM's patch.
64
+ # 3.7. Subagent context bypass.
65
+ # Composer's coder subagent must Edit/Write to apply GLM's patch output.
66
+ # The hook fires identically for main-thread and subagent calls — without
67
+ # this carve-out the apply step is impossible. Detect subagent via the
68
+ # three field-name shapes Claude Code has emitted across recent versions.
55
69
  TRANSCRIPT="$(jq -r '.transcript_path // empty' <<<"$INPUT" 2>/dev/null)"
56
70
  AGENT_ID="$(jq -r '.agent_id // .agentId // empty' <<<"$INPUT" 2>/dev/null)"
57
71
  SIDECHAIN="$(jq -r '.is_sidechain // .isSidechain // empty' <<<"$INPUT" 2>/dev/null)"
@@ -61,12 +75,15 @@ if [[ "$TRANSCRIPT" == */subagents/* ]] \
61
75
  exit 0
62
76
  fi
63
77
 
78
+ # 4. Block list — native dangerous tools + MCP-prefixed variants.
64
79
  case "$TOOL" in
65
- Edit|Write|NotebookEdit \
66
- | mcp__*__write_file | mcp__*__edit_file \
67
- | mcp__*__write | mcp__*__edit)
80
+ Bash|Edit|Write|NotebookEdit \
81
+ | mcp__*__write_file | mcp__*__edit_file | mcp__*__bash \
82
+ | mcp__*__write | mcp__*__edit | mcp__*__exec)
68
83
  emit_deny "DENY: dispatch Task(subagent_type=\"coder\"); no Bash workaround."
69
84
  ;;
70
85
  esac
71
86
 
87
+ # 5. Pass-through. Emit nothing — Anthropic treats absent JSON + exit 0
88
+ # as implicit allow. (Explicit allow JSON is also valid but noisier.)
72
89
  exit 0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "composer-mastermind",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "Multi-agent orchestrator: Claude as brain, GLM/agy as executors. Dispatches code/research/review work to subagents wired through the @composer-mcp/server MCP server.",
5
5
  "claudeCodeVersion": ">=4.6",
6
6
  "requires": [
@@ -23,7 +23,8 @@
23
23
  "agents": [
24
24
  "agents/coder.md",
25
25
  "agents/researcher.md",
26
- "agents/reviewer.md"
26
+ "agents/reviewer.md",
27
+ "agents/explorer.md"
27
28
  ],
28
29
  "commands": [
29
30
  "commands/evolve.md"
@@ -51,6 +51,35 @@ pinned. For tiny clarifications / refusals / one-line answers,
51
51
  multi-step refactors) is where dispatch pays. Trust your
52
52
  expected-output estimate; if under 5 lines, just answer.
53
53
 
54
+ **Fan-out cap:** Max 3 parallel worker dispatches per turn for repos with >500 source files. Beyond 3, the prompt-cache misses compound faster than the parallelism saves wall time. If file slices overlap across workers, dispatch SEQUENTIALLY — parallel workers on the same files duplicate every Read.
55
+
56
+ # Explorer protocol (large-repo dispatches)
57
+
58
+ For repos with >500 source files (or any unfamiliar codebase), prefer an
59
+ **explorer → workers** shape over re-greping in the main session before
60
+ every dispatch. Re-discovery is the single biggest token bleed in this
61
+ architecture: each fresh worker boots without prompt-cache hits and
62
+ re-Reads the same files.
63
+
64
+ Dispatch shape:
65
+
66
+ | Situation | Dispatch |
67
+ |---|---|
68
+ | Small repo, files already pinned in conversation | **Inline** — call worker directly with `{ prompt, context }` |
69
+ | Large repo, single worker | `explorer` → consume `briefPath` → ONE worker dispatch with `{ briefPath, task }` |
70
+ | Large repo, multiple workers | `explorer` ONCE → fan out workers, each consumes the **same** `briefPath` |
71
+
72
+ `briefPath` convention: explorer writes `.composer/briefs/<runId>.json`
73
+ (zod schema in `src/util/brief.ts`). Workers re-validate with
74
+ `BriefSchema.parse(readFileSync(briefPath))` before touching files. The
75
+ brief is the shared cache prefix — passing the same path to N siblings
76
+ is what keeps prompt-cache warm across the fan-out.
77
+
78
+ **When to skip the explorer:** orchestrator already knows the exact
79
+ file:line targets (e.g. user said "edit src/foo.ts line 42") OR the
80
+ expected worker output is <500 tokens. The explorer dispatch costs
81
+ ~1.5k cache tokens itself; don't pay that for an inline-sized task.
82
+
54
83
  # Spend authorization
55
84
 
56
85
  Read `composer.config.json` `spendAuthorization.mode` before any
@@ -69,6 +98,31 @@ dispatch that hits a real-money provider (`anthropic`,
69
98
  CLI providers (`agy`) are billed separately by the user's own auth
70
99
  and do not count toward these caps. Mock providers are always free.
71
100
 
101
+ # Headless invocation
102
+
103
+ When composer-mastermind runs inside a headless `claude -p` (eval harness,
104
+ test runner, CI dispatch, scheduled job, any non-interactive context), prefer
105
+ **Haiku** as the orchestrator model. Build-2 dogfood measurement showed
106
+ -66 % cost vs Opus 4.7 on the orchestrator side, with no quality regression
107
+ on the 3 eval tasks. Workers (GLM / agy) are unchanged.
108
+
109
+ How to invoke:
110
+
111
+ ```sh
112
+ claude -p --model claude-haiku-4-5-20251001 \
113
+ --output-format json --permission-mode bypassPermissions \
114
+ "<your prompt>"
115
+ ```
116
+
117
+ Rules:
118
+
119
+ - Interactive sessions (user is watching): default Opus 4.7. Haiku
120
+ hands off integration nuance the user expects.
121
+ - Headless / scheduled / eval: default Haiku. The orchestrator's job is
122
+ delegation, not reasoning — Haiku is sufficient for routing + summary.
123
+ - Override when the orchestration plan itself is non-trivial (>3
124
+ dispatches, cross-file integration). Then Opus 4.7 earns its keep.
125
+
72
126
  # Token discipline
73
127
 
74
128
  - You hold context, plans, and integration. Workers hold execution.