peaks-loop 4.0.25 → 4.0.26

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cli/commands/core/memory-command.js +1 -3
  3. package/dist/cli/commands/dispatch-commands.js +11 -67
  4. package/dist/cli/commands/memory-commands.d.ts +0 -2
  5. package/dist/cli/commands/memory-commands.js +4 -7
  6. package/dist/cli/commands/preferences-commands.js +0 -1
  7. package/dist/cli/commands/qa-commands.js +5 -5
  8. package/dist/cli/commands/sub-agent-shared.d.ts +0 -4
  9. package/dist/cli/commands/sub-agent-shared.js +0 -14
  10. package/dist/cli/commands/workflow-commands.js +5 -5
  11. package/dist/services/context/build-dispatch-system-prompt.d.ts +4 -4
  12. package/dist/services/context/build-dispatch-system-prompt.js +6 -6
  13. package/dist/services/context/context-guard.d.ts +2 -4
  14. package/dist/services/context/context-guard.js +4 -6
  15. package/dist/services/context/{headroom-fetcher.d.ts → doc-cache-fetcher.d.ts} +2 -2
  16. package/dist/services/context/{headroom-fetcher.js → doc-cache-fetcher.js} +4 -3
  17. package/dist/services/context/memory-preflight-service.js +6 -17
  18. package/dist/services/context/threshold.d.ts +0 -3
  19. package/dist/services/context/threshold.js +0 -3
  20. package/dist/services/dispatch/batch-counter.js +1 -1
  21. package/dist/services/dispatch/leak-detector.js +1 -1
  22. package/dist/services/fuzzy-matching/fzf-pick-service.d.ts +1 -1
  23. package/dist/services/fuzzy-matching/fzf-pick-service.js +1 -1
  24. package/dist/services/memory/llm-reranker.d.ts +4 -5
  25. package/dist/services/memory/llm-reranker.js +6 -8
  26. package/dist/services/memory/memory-search-service.d.ts +0 -32
  27. package/dist/services/memory/memory-search-service.js +0 -37
  28. package/dist/services/preferences/preferences-service.d.ts +5 -8
  29. package/dist/services/preferences/preferences-service.js +0 -30
  30. package/dist/services/preferences/preferences-types.d.ts +0 -22
  31. package/dist/services/preferences/preferences-types.js +0 -12
  32. package/dist/services/retrospective/retrospective-search-service.d.ts +0 -18
  33. package/dist/services/retrospective/retrospective-search-service.js +0 -32
  34. package/dist/services/slice/slice-benchmark-service.d.ts +1 -1
  35. package/dist/services/slice/slice-benchmark-service.js +1 -1
  36. package/dist/services/slice/slice-pick-service.d.ts +1 -1
  37. package/dist/services/slice/slice-pick-service.js +1 -1
  38. package/package.json +5 -6
  39. package/skills/bee/peaks-qa/references/qa-context-governance.md +1 -1
  40. package/skills/bee/peaks-rd/SKILL.md +2 -2
  41. package/skills/bee/peaks-rd/references/rd-context-governance.md +2 -2
  42. package/skills/bee/peaks-txt/SKILL.md +1 -1
  43. package/skills/bee/peaks-ui/SKILL.md +1 -1
  44. package/skills/peaks-code/SKILL.md +1 -1
  45. package/skills/peaks-code/references/context-governance.md +7 -34
  46. package/skills/peaks-code/references/envelope-contract.md +2 -7
  47. package/skills/peaks-code/references/sub-agent-dispatch.md +2 -4
  48. package/dist/services/context/headroom-client.d.ts +0 -34
  49. package/dist/services/context/headroom-client.js +0 -117
  50. package/dist/services/context/headroom-prefs.d.ts +0 -46
  51. package/dist/services/context/headroom-prefs.js +0 -34
  52. package/skills/peaks-code/references/headroom-integration.md +0 -107
@@ -35,10 +35,9 @@
35
35
  *
36
36
  * Why 4-bytes-per-token:
37
37
  *
38
- * - `headroom-client.ts:60` already uses `BYTES_PER_TOKEN = 4` as
39
- * its rough English-text approximation. Reusing the same constant
40
- * keeps token estimates comparable across the headroom + rerank
41
- * pipelines in the AC-ZA-5 benchmark.
38
+ * - `BYTES_PER_TOKEN = 4` is the standard rough English-text
39
+ * approximation (1 token ≈ 4 bytes). It keeps token estimates
40
+ * stable and comparable in the AC-ZA-5 benchmark.
42
41
  *
43
42
  * Out of scope (YAGNI per Karpathy #2 Simplicity First):
44
43
  *
@@ -49,9 +48,8 @@
49
48
  * - No integration with `memory-search-service.ts` (Z-A is a spike;
50
49
  * the wiring into `peaks memory search` is Z-B).
51
50
  */
52
- // Approximate 1 token = 4 bytes for English text. Matches
53
- // `headroom-client.ts:60` so the AC-ZA-5 benchmark can compare
54
- // rerank input cost against headroom compressed cost directly.
51
+ // Approximate 1 token = 4 bytes for English text. Standard rough
52
+ // approximation used across the pipeline (AC-ZA-5 benchmark).
55
53
  const BYTES_PER_TOKEN = 4;
56
54
  // Hard caps so a pathological query / 60-candidate list cannot blow
57
55
  // up the LLM prompt. These are conservative defaults; Z-B may tune.
@@ -62,7 +60,7 @@ const MAX_DESCRIPTION_CHARS = 240;
62
60
  const DEFAULT_CHAT_TIMEOUT_MS = 5_000;
63
61
  /**
64
62
  * Estimate token count for a string. `1 token ≈ 4 bytes` for English
65
- * text — same approximation as `headroom-client.ts:60`.
63
+ * text (standard rough approximation).
66
64
  */
67
65
  export function estimateTokens(text) {
68
66
  return Math.ceil(Buffer.byteLength(text, 'utf8') / BYTES_PER_TOKEN);
@@ -59,35 +59,3 @@ export declare function loadMemoryIndex(projectRoot: string): MemoryIndexSnapsho
59
59
  * spec §Component Details).
60
60
  */
61
61
  export declare function searchMemory(input: MemorySearchInput): MemorySearchResult[];
62
- /**
63
- * Envelope for the optional headroom-compressed version of the search
64
- * result text. The compressed text is intended for the LLM-side prompt
65
- * (it preserves the entry names + descriptions in a more token-efficient
66
- * form); the structured `matches` array is unchanged and remains the
67
- * machine-readable form. `null` when compression was not requested,
68
- * did not run, or failed (see `warning` for the reason).
69
- */
70
- export interface CompressedResultsEnvelope {
71
- readonly mode: 'balanced' | 'aggressive' | 'conservative';
72
- readonly originalSize: number;
73
- readonly compressedSize: number;
74
- readonly compressionRatio: number;
75
- readonly compressedText: string;
76
- readonly warning: string | null;
77
- }
78
- export interface MemorySearchWithResults {
79
- readonly matches: MemorySearchResult[];
80
- readonly compressedResults: CompressedResultsEnvelope | null;
81
- }
82
- export interface MemorySearchOptions {
83
- /** When true, read preferences.headroom.perTouchpoint.memorySearch and
84
- * compress joined match text via headroom-ai. Falls back silently to
85
- * the structured `matches` array when compression is unavailable. */
86
- readonly compressResults?: boolean;
87
- }
88
- /**
89
- * Run the search + optionally compress the joined match text via headroom.
90
- * The structured `matches` array is the canonical output. The
91
- * `compressedResults` is a derived view for LLM-side prompt assembly.
92
- */
93
- export declare function searchMemoryWithResults(input: MemorySearchInput, options?: MemorySearchOptions): Promise<MemorySearchWithResults>;
@@ -1,9 +1,6 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { fuzzyMatchWithKey } from '../fuzzy-matching/fuzzy-match-service.js';
4
- import { compressPrompt } from '../context/headroom-client.js';
5
- import { loadPreferences } from '../preferences/preferences-service.js';
6
- import { shouldCompressResults } from '../context/headroom-prefs.js';
7
4
  const DEFAULT_LIMIT = 6;
8
5
  /**
9
6
  * Read `.peaks/memory/index.json` and flatten the on-disk `hot[<kind>][]`
@@ -81,37 +78,3 @@ export function searchMemory(input) {
81
78
  };
82
79
  });
83
80
  }
84
- /**
85
- * Run the search + optionally compress the joined match text via headroom.
86
- * The structured `matches` array is the canonical output. The
87
- * `compressedResults` is a derived view for LLM-side prompt assembly.
88
- */
89
- export async function searchMemoryWithResults(input, options = {}) {
90
- const matches = searchMemory(input);
91
- if (options.compressResults !== true) {
92
- return { matches, compressedResults: null };
93
- }
94
- const projectRoot = input.projectRoot ?? process.cwd();
95
- const prefs = loadPreferences(projectRoot).headroom;
96
- const joinedText = matches.map((m) => `${m.name}: ${m.description}`).join('\n');
97
- const joinedBytes = Buffer.byteLength(joinedText, 'utf8');
98
- const decision = shouldCompressResults(prefs, joinedBytes, 'memorySearch');
99
- if (!decision.compress) {
100
- return { matches, compressedResults: null };
101
- }
102
- const result = await compressPrompt(joinedText, decision.mode);
103
- if (result.warning !== null || result.compressedPrompt === null) {
104
- return { matches, compressedResults: null };
105
- }
106
- return {
107
- matches,
108
- compressedResults: {
109
- mode: decision.mode,
110
- originalSize: result.originalSize,
111
- compressedSize: result.compressedSize,
112
- compressionRatio: result.compressionRatio,
113
- compressedText: result.compressedPrompt,
114
- warning: result.warning
115
- }
116
- };
117
- }
@@ -16,14 +16,11 @@ export declare function writeAtomic(filePath: string, prefs: ProjectPreferences)
16
16
  * current shape. Returns the migrated object + a list of changes
17
17
  * applied (for surfacing in the CLI envelope and the migration log).
18
18
  *
19
- * The v1 → v2 mapping fills in the `headroom.perTouchpoint` sub-keys
20
- * that v1 didn't track: each touchpoint gets the v1 `headroom.defaultMode`
21
- * (or 'balanced' if absent), and `compressMinBytes` is preserved
22
- * verbatim. v1's `agentShieldPrompt` and `loopAutonomousEnabled` were
23
- * already present, so they carry through unchanged. The `fanout` field
24
- * is new in v2 — it defaults to `{ defaultMode: 'fan-out' }` so the
25
- * pre-v2 behavior (peak-code SKILL instructed fan-out when ≥ 2 leaves)
26
- * is preserved.
19
+ * v1's `agentShieldPrompt` and `loopAutonomousEnabled` were already
20
+ * present, so they carry through unchanged. The `fanout` field is new
21
+ * in v2 — it defaults to `{ defaultMode: 'fan-out' }` so the pre-v2
22
+ * behavior (peak-code SKILL instructed fan-out when ≥ 2 leaves) is
23
+ * preserved.
27
24
  */
28
25
  export type MigrateResult = {
29
26
  readonly fromVersion: string;
@@ -135,25 +135,6 @@ export function migratePreferences(projectRoot, opts = {}) {
135
135
  };
136
136
  }
137
137
  const changes = [];
138
- // v1 → v2: headroom.perTouchpoint fill-in (v1 only had defaultMode).
139
- const headroomRaw = (raw.headroom ?? {});
140
- const defaultMode = isHeadroomModeString(headroomRaw.defaultMode)
141
- ? headroomRaw.defaultMode
142
- : 'balanced';
143
- const perTouchpoint = {
144
- subAgentDispatch: defaultMode,
145
- memorySearch: defaultMode,
146
- retrospectiveSearch: defaultMode,
147
- doctorScan: defaultMode,
148
- doctorRoute: 'conservative'
149
- };
150
- changes.push(`headroom.perTouchpoint filled in with defaultMode='${defaultMode}' (v1 lacked per-touchpoint overrides)`);
151
- if (typeof headroomRaw.compressMinBytes === 'number') {
152
- changes.push(`headroom.compressMinBytes preserved at ${headroomRaw.compressMinBytes}`);
153
- }
154
- else {
155
- changes.push(`headroom.compressMinBytes defaulted to 4096`);
156
- }
157
138
  // v1 → v2: fanout block was absent; v2 needs it. Default to the
158
139
  // pre-v2 behavior (fan-out when ≥ 2 leaves).
159
140
  if (raw.fanout === undefined) {
@@ -176,14 +157,6 @@ export function migratePreferences(projectRoot, opts = {}) {
176
157
  // fully-valid v2 ProjectPreferences.
177
158
  const migrated = mergePreferences(DEFAULT_PREFERENCES, {
178
159
  ...raw,
179
- headroom: {
180
- enabled: typeof headroomRaw.enabled === 'boolean' ? headroomRaw.enabled : true,
181
- defaultMode,
182
- perTouchpoint,
183
- compressMinBytes: typeof headroomRaw.compressMinBytes === 'number'
184
- ? headroomRaw.compressMinBytes
185
- : 4096
186
- },
187
160
  fanout: typeof raw.fanout === 'object' && raw.fanout !== null && !Array.isArray(raw.fanout)
188
161
  ? (raw.fanout.defaultMode === 'serial'
189
162
  ? { defaultMode: 'fan-out' }
@@ -203,6 +176,3 @@ export function migratePreferences(projectRoot, opts = {}) {
203
176
  written
204
177
  };
205
178
  }
206
- function isHeadroomModeString(value) {
207
- return value === 'balanced' || value === 'aggressive' || value === 'conservative';
208
- }
@@ -22,27 +22,6 @@ export type UaPromptDecision = 'unset' | 'skip-this-session' | 'skip-forever';
22
22
  * - 'lax' — always downgrade to previous level (faster, riskier)
23
23
  */
24
24
  export type ClassifyConservatism = 'default' | 'strict' | 'lax';
25
- /**
26
- * Per-touchpoint headroom-AI mode override.
27
- * Spec §7.4 — default 'balanced'.
28
- */
29
- export type HeadroomMode = 'balanced' | 'aggressive' | 'conservative';
30
- export interface HeadroomPreferences {
31
- /** Whether headroom integration is enabled globally. Default: true */
32
- readonly enabled: boolean;
33
- /** Default mode if a touchpoint doesn't override. Default: 'balanced' */
34
- readonly defaultMode: HeadroomMode;
35
- /** Per-touchpoint mode overrides */
36
- readonly perTouchpoint: {
37
- subAgentDispatch: HeadroomMode;
38
- memorySearch: HeadroomMode;
39
- retrospectiveSearch: HeadroomMode;
40
- doctorScan: HeadroomMode;
41
- doctorRoute: HeadroomMode;
42
- };
43
- /** Minimum joined-result byte count before search-touchpoint compression runs. Default: 4096. */
44
- readonly compressMinBytes: number;
45
- }
46
25
  export interface ClassifyRuleOverrides {
47
26
  /** File count threshold above which a task is promoted to 'feature' */
48
27
  readonly feature_threshold_files?: number;
@@ -101,7 +80,6 @@ export interface ProjectPreferences {
101
80
  readonly agentShieldPrompt: UaPromptDecision;
102
81
  readonly classifyConservatism: ClassifyConservatism;
103
82
  readonly classifyRules: ClassifyRuleOverrides;
104
- readonly headroom: HeadroomPreferences;
105
83
  readonly swarmSpeculative: SwarmSpeculativePreferences;
106
84
  /** Loop Autonomous (L4 14.5) toggle. Default: false — never auto-enable. */
107
85
  readonly loopAutonomousEnabled: boolean;
@@ -28,18 +28,6 @@ export const DEFAULT_PREFERENCES = {
28
28
  feature_threshold_lines: 100,
29
29
  runtime_clean_grace_hours: 24,
30
30
  },
31
- headroom: {
32
- enabled: true,
33
- defaultMode: 'balanced',
34
- perTouchpoint: {
35
- subAgentDispatch: 'balanced',
36
- memorySearch: 'balanced',
37
- retrospectiveSearch: 'balanced',
38
- doctorScan: 'balanced',
39
- doctorRoute: 'conservative',
40
- },
41
- compressMinBytes: 4096,
42
- },
43
31
  swarmSpeculative: {
44
32
  enabled: true,
45
33
  maxConcurrent: 3,
@@ -35,21 +35,3 @@ export interface RetrospectiveSearchResult {
35
35
  * runs (cheaper to filter, then fuzzy on a smaller set).
36
36
  */
37
37
  export declare function searchRetrospective(input: RetrospectiveSearchInput): RetrospectiveSearchResult[];
38
- export interface CompressedRetrospectiveResultsEnvelope {
39
- readonly mode: 'balanced' | 'aggressive' | 'conservative';
40
- readonly originalSize: number;
41
- readonly compressedSize: number;
42
- readonly compressionRatio: number;
43
- readonly compressedText: string;
44
- readonly warning: string | null;
45
- }
46
- export interface RetrospectiveSearchWithResults {
47
- readonly matches: RetrospectiveSearchResult[];
48
- readonly compressedResults: CompressedRetrospectiveResultsEnvelope | null;
49
- }
50
- export interface RetrospectiveSearchOptions {
51
- /** When true, compress joined match text via headroom-ai. Falls back
52
- * silently to the structured `matches` array on failure. */
53
- readonly compressResults?: boolean;
54
- }
55
- export declare function searchRetrospectiveWithResults(input: RetrospectiveSearchInput, options?: RetrospectiveSearchOptions): Promise<RetrospectiveSearchWithResults>;
@@ -73,35 +73,3 @@ export function searchRetrospective(input) {
73
73
  };
74
74
  });
75
75
  }
76
- import { compressPrompt as compressPromptForRetro } from '../context/headroom-client.js';
77
- import { loadPreferences as loadPreferencesForRetro } from '../preferences/preferences-service.js';
78
- import { shouldCompressResults as shouldCompressResultsForRetro } from '../context/headroom-prefs.js';
79
- export async function searchRetrospectiveWithResults(input, options = {}) {
80
- const matches = searchRetrospective(input);
81
- if (options.compressResults !== true) {
82
- return { matches, compressedResults: null };
83
- }
84
- const projectRoot = input.projectRoot ?? process.cwd();
85
- const prefs = loadPreferencesForRetro(projectRoot).headroom;
86
- const joinedText = matches.map((m) => `${m.title}: ${m.summary}`).join('\n');
87
- const joinedBytes = Buffer.byteLength(joinedText, 'utf8');
88
- const decision = shouldCompressResultsForRetro(prefs, joinedBytes, 'retrospectiveSearch');
89
- if (!decision.compress) {
90
- return { matches, compressedResults: null };
91
- }
92
- const result = await compressPromptForRetro(joinedText, decision.mode);
93
- if (result.warning !== null || result.compressedPrompt === null) {
94
- return { matches, compressedResults: null };
95
- }
96
- return {
97
- matches,
98
- compressedResults: {
99
- mode: decision.mode,
100
- originalSize: result.originalSize,
101
- compressedSize: result.compressedSize,
102
- compressionRatio: result.compressionRatio,
103
- compressedText: result.compressedPrompt,
104
- warning: result.warning
105
- }
106
- };
107
- }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Slice benchmark wrapper (slice 2026-06-14-fzf-headroom-rollout).
2
+ * Slice benchmark wrapper (slice 2026-06-14-fzf-rollout).
3
3
  *
4
4
  * Wraps `decomposeSlices` with a thin observability layer that records
5
5
  * total wall time, codegraph call count, confidence distribution, and
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Slice benchmark wrapper (slice 2026-06-14-fzf-headroom-rollout).
2
+ * Slice benchmark wrapper (slice 2026-06-14-fzf-rollout).
3
3
  *
4
4
  * Wraps `decomposeSlices` with a thin observability layer that records
5
5
  * total wall time, codegraph call count, confidence distribution, and
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Slice Pick Service — thin wrapper around the generic fzf picker.
3
3
  *
4
- * v2 (slice 2026-06-14-fzf-headroom-rollout): the actual fzf
4
+ * v2 (slice 2026-06-14-fzf-rollout): the actual fzf
5
5
  * integration is now in `src/services/fuzzy-matching/fzf-pick-service.ts`.
6
6
  * This file only knows how to format / parse SliceCandidate rows and
7
7
  * pick the output path. The algorithm itself (slice-decompose-service)
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Slice Pick Service — thin wrapper around the generic fzf picker.
3
3
  *
4
- * v2 (slice 2026-06-14-fzf-headroom-rollout): the actual fzf
4
+ * v2 (slice 2026-06-14-fzf-rollout): the actual fzf
5
5
  * integration is now in `src/services/fuzzy-matching/fzf-pick-service.ts`.
6
6
  * This file only knows how to format / parse SliceCandidate rows and
7
7
  * pick the output path. The algorithm itself (slice-decompose-service)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peaks-loop",
3
- "version": "4.0.25",
3
+ "version": "4.0.26",
4
4
  "description": "Loop Engineering CLI — workflow primitive / loop guards / evaluators / slice orchestration",
5
5
  "author": "SquabbyZ",
6
6
  "keywords": [
@@ -99,13 +99,12 @@
99
99
  "better-sqlite3": "^12.11.1",
100
100
  "commander": "^12.1.0",
101
101
  "fzf": "^0.5.2",
102
- "headroom-ai": "0.22.4",
103
102
  "yaml": "^2.9.0",
104
103
  "zod": "^4.4.3",
105
- "peaks-loop-internal-runtime": "0.0.10",
106
- "peaks-loop-mut": "0.1.23",
107
- "peaks-loop-shared-channel": "0.0.27",
108
- "peaks-loop-shared": "0.0.59"
104
+ "peaks-loop-internal-runtime": "0.0.11",
105
+ "peaks-loop-shared": "0.0.60",
106
+ "peaks-loop-shared-channel": "0.0.28",
107
+ "peaks-loop-mut": "0.1.24"
109
108
  },
110
109
  "devDependencies": {
111
110
  "@changesets/cli": "2.31.1",
@@ -21,4 +21,4 @@ PROTOCOL (mandatory):
21
21
 
22
22
  ## G9 — QA prompt size self-check
23
23
 
24
- Same as RD: 50% soft warn, 75% `CONTEXT_NEAR_LIMIT`, 80% hard reject unless `--force`. QA test plans can grow large; prefer `--use-headroom balanced` for plans > 75%.
24
+ Same as RD: 50% soft warn, 75% `CONTEXT_NEAR_LIMIT`, 80% hard reject unless `--force`. QA test plans can grow large; trim or split into multiple dispatches for plans > 75%.
@@ -235,9 +235,9 @@ The `karpathy-reviewer` sub-agent now reports its own runtime cost in the JSON e
235
235
 
236
236
  The main RD loop MUST call `peaks job karpathy-cost-check` after every `peaks request transition --state qa-handoff` and before the next-slice work begins. If the decision kind is `downgraded`, the LLM MUST honor the downgraded `warn` and proceed to the next slice; the `'block'` was an artifact of the reviewer's own cost, not the slice's quality. If the decision kind is `reported` (costRatio > 50, gate not `'block'`), the LLM MAY continue; the sediment will be appended by `peaks memory extract` at handoff time. The full design lives in `.peaks/memory/2026-07-30-karpathy-evaluation-cost-self-review-design.md` (sediment locked 2026-07-30).
237
237
 
238
- ## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
238
+ ## Sub-agent context governance (G7 + G8 + G9 — slice #010)
239
239
 
240
- RD sub-agent prompt template MUST include the G7 path convention + G8.6 share protocol. Detailed protocol: `skills/peaks-code/references/context-governance.md` + `skills/peaks-code/references/headroom-integration.md`.
240
+ RD sub-agent prompt template MUST include the G7 path convention + G8.6 share protocol. Detailed protocol: `skills/peaks-code/references/context-governance.md`.
241
241
 
242
242
  → see `references/rd-context-governance.md` for the full G7 / G8.6 / G9 protocol + RD sub-agent prompt template.
243
243
 
@@ -31,6 +31,6 @@ PROTOCOL (mandatory):
31
31
 
32
32
  Before dispatching a sub-agent, RD self-checks prompt size:
33
33
  - < 50%: pass through.
34
- - 50-75%: soft warn (consider `--use-headroom`).
35
- - 75-80%: soft warn + `warnings: ["CONTEXT_NEAR_LIMIT"]` (mandatory suggest `--use-headroom`).
34
+ - 50-75%: soft warn (consider trimming the prompt).
35
+ - 75-80%: soft warn + `warnings: ["CONTEXT_NEAR_LIMIT"]` (trim or split into multiple dispatches).
36
36
  - 80%+: reject (CLI 兜底 returns `code: "PROMPT_TOO_LARGE"`). Use `--force` at CLI only when overriding; hook layer will still reject (RL-30).
@@ -305,7 +305,7 @@ The TXT handoff summarizes the slice by listing the artifact metas + the share e
305
305
 
306
306
  ### G9 — TXT prompt size self-check
307
307
 
308
- Same G9 threshold table. TXT handoff messages can grow large when the slice has many batches; use `--use-headroom` proactively for handoff prompts > 50%.
308
+ Same G9 threshold table. TXT handoff messages can grow large when the slice has many batches; trim or split the handoff prompt proactively for prompts > 50%.
309
309
 
310
310
 
311
311
  ## L2 surface reference (post rid-l2-extended)
@@ -361,7 +361,7 @@ PROTOCOL (mandatory):
361
361
 
362
362
  ### G9 — UI prompt size self-check
363
363
 
364
- Same as RD/QA. Use `--use-headroom` proactively.
364
+ Same as RD/QA. Trim or split the prompt proactively.
365
365
 
366
366
 
367
367
  ## L2 surface reference (post rid-l2-extended)
@@ -302,7 +302,7 @@ After final validation, refresh project-local standards via `peaks standards ini
302
302
 
303
303
  `peaks codegraph affected` is an optional project-analysis enhancement (untrusted supporting evidence) for role handoff. Code must not treat codegraph output as approval for scope, design, or QA verdict. Never mutate agent settings / hooks from codegraph; do not commit `.codegraph/` artifacts. RD writes `.peaks/_runtime/<sessionId>/rd/codegraph-context.md`; QA / TXT consume the same envelope. → `references/codegraph-orchestration.md`.
304
304
 
305
- ## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
305
+ ## Sub-agent context governance (G7 + G8 + G9 — slice #010)
306
306
 
307
307
  Main LLM reducer sees metadata-only view (~200 chars/sub-agent); on-demand `Read` for full content. Threshold table: 50% soft warn, 75% `CONTEXT_NEAR_LIMIT`, 80% hard reject (CLI + hook double-guard). → `references/context-governance.md`.
308
308
 
@@ -1,7 +1,7 @@
1
- # Context Governance — G7 + G7.7 + G8 + G9 protocol details
1
+ # Context Governance — G7 + G8 + G9 protocol details
2
2
 
3
- > Slice #010 (G7 + G7.7 + G8 + G9 context-governance push).
4
- > See: `.peaks/memory/sub-agent-context-minimal-occupation.md` + `sub-agent-shared-channel-cross-completion.md` + `sub-agent-headroom-forced-compression-gate.md` for the red lines.
3
+ > Slice #010 (G7 + G8 + G9 context-governance push).
4
+ > See: `.peaks/memory/sub-agent-context-minimal-occupation.md` + `sub-agent-shared-channel-cross-completion.md` for the red lines.
5
5
 
6
6
  ## G7 — sub-agent context minimal-occupation (metadata-only + 按需 Read)
7
7
 
@@ -56,26 +56,6 @@ On completion:
56
56
 
57
57
  3000-5000× improvement. Main LLM full-slice context net increase: < 10KB for 5 batches × 6 sub-agents.
58
58
 
59
- ## G7.7 — headroom-ai integration (opt-in)
60
-
61
- ### `--use-headroom` flag
62
-
63
- Opt-in flag on `peaks sub-agent dispatch`. Default `false` (G7 metadata-only remains the default).
64
-
65
- ### Mode table
66
-
67
- | Mode | tokenBudget | Use case |
68
- |---|---|---|
69
- | `balanced` (default) | promptSize * 0.40 / 4 | General sub-agent dispatch |
70
- | `aggressive` | promptSize * 0.20 / 4 | Last-resort large prompt |
71
- | `conservative` | promptSize * 0.70 / 4 | Sensitive code analysis |
72
-
73
- ### Failure mode (RL-22d / RL-32)
74
-
75
- - headroom daemon dead / proxy unreachable / times out
76
- - → `code: "HEADROOM_UNAVAILABLE"` warning + G7 metadata-only fallback
77
- - → NOT blocking (warn, then continue dispatch)
78
-
79
59
  ## G8 — cross sub-agent shared channel
80
60
 
81
61
  ### Path convention
@@ -132,8 +112,8 @@ PROTOCOL (mandatory):
132
112
 
133
113
  | Threshold | Prompt size | Behavior |
134
114
  |---|---|---|
135
- | 50% (early warn) | ≥ 128KB | Soft warning, suggest `--use-headroom` |
136
- | **75% (user red line)** | ≥ 192KB | Soft warn + mandatory suggest `--use-headroom`; `warnings: ["CONTEXT_NEAR_LIMIT"]` |
115
+ | 50% (early warn) | ≥ 128KB | Soft warning, suggest trimming the prompt |
116
+ | **75% (user red line)** | ≥ 192KB | Soft warn + mandatory trim/split suggestion; `warnings: ["CONTEXT_NEAR_LIMIT"]` |
137
117
  | **80% (hard reject)** | ≥ 204KB | Hard reject `code: "PROMPT_TOO_LARGE"`; `--force` allowed at CLI |
138
118
  | **90% (emergency)** | ≥ 230KB | Hard reject `code: "PROMPT_EMERGENCY"`; `--force` STILL rejects at 90% (no override) |
139
119
 
@@ -149,7 +129,7 @@ PROTOCOL (mandatory):
149
129
 
150
130
  ## AC mapping
151
131
 
152
- - AC-38..AC-43 (G7) + AC-44..AC-46 (G7.7) + AC-47..AC-49 (G8) + AC-50..AC-65 (G9)
132
+ - AC-38..AC-43 (G7) + AC-47..AC-49 (G8) + AC-50..AC-65 (G9)
153
133
  - See PRD §Acceptance criteria.
154
134
 
155
135
  ---
@@ -171,13 +151,6 @@ Main LLM view format (G7.4.e):
171
151
  - qa-perf → .../artifacts/003-qa-perf-001.md (5KB, sha256:ghi789) summary: "p95 latency target ≤ 200ms"
172
152
  ```
173
153
 
174
- ### G7.7 — headroom-ai integration (opt-in compression)
175
-
176
- > Body of `### G7.7`. If a sub-agent prompt is too large even after G7 metadata-only (e.g. 1MB artifact description, 5MB mid-prompt analysis), use `--use-headroom`:
177
- - Default `false` (G7 remains default).
178
- - Modes: `balanced` (default) | `aggressive` | `conservative`.
179
- - Failure: `HEADROOM_UNAVAILABLE` warning + G7 metadata-only fallback (NOT blocking).
180
-
181
154
  ### G8 — cross sub-agent shared channel (dispatcher-mediated indirect signal)
182
155
 
183
156
  > Body of `### G8`. Sub-agent A's completion **immediately** writes a shared entry; sub-agent B (still in flight) can read shared entries from sibling sub-agents. **This is NOT peer-to-peer messaging.** The dispatcher stores, the sub-agents read/write; A and B never directly talk.
@@ -192,7 +165,7 @@ Main LLM view format (G7.4.e):
192
165
 
193
166
  | Threshold | Prompt size | Behavior |
194
167
  |---|---|---|
195
- | 50% (early warn) | ≥ 128KB | Soft warning, suggest `--use-headroom` |
168
+ | 50% (early warn) | ≥ 128KB | Soft warning, suggest trimming the prompt |
196
169
  | **75% (user red line)** | ≥ 192KB | Soft warn + `warnings: ["CONTEXT_NEAR_LIMIT"]` |
197
170
  | **80% (hard reject)** | ≥ 204KB | Hard reject `code: "PROMPT_TOO_LARGE"`; `--force` allowed at CLI |
198
171
  | 90% (emergency) | ≥ 230KB | Hard reject + `contextWarning: 'high'` |
@@ -33,19 +33,14 @@ Top-level fields (post-2.1.0):
33
33
  - `envelopeVersion: '2.1.0'`
34
34
  - `role: string` — sub-agent role string
35
35
  - `ide: string` — detected IDE label (`claude-code` etc.)
36
- - `originalPromptSize: number` — bytes of the un-compressed prompt
37
- - `promptSize: number` — bytes after headroom compression (or
38
- equal to `originalPromptSize` when `--use-headroom` is off or
39
- unavailable)
36
+ - `originalPromptSize: number` — bytes of the caller-supplied prompt
37
+ - `promptSize: number` — bytes of the composed dispatch prompt
40
38
  - `toolCall: { name: string; args: Record<string, unknown> }` —
41
39
  the per-IDE tool-call descriptor the LLM must execute
42
40
  - `dispatchRecordPath: string` — absolute path to the dispatch
43
41
  record on disk
44
42
  - `batchId: string` — uuid-like opaque token grouping one batch
45
43
  - `dispatchedInBatch: number` — current count after this dispatch
46
- - `headroomCompressed: boolean` — true if headroom-ai actually
47
- reduced the prompt
48
- - `headroomResult: { mode, compressed, compressionRatio, tokensSaved, warning } | null`
49
44
  - `forcedAt: string | null` — ISO8601 when `--force` overrode
50
45
  the G9 hard-reject tier
51
46
  - `contextImpact: { promptBytes, artifactBytes, totalBytes }`
@@ -51,8 +51,8 @@ peaks sub-agent dispatch <role> --prompt <text> [--request-id <rid>] [--session-
51
51
  > scrollback. The dispatch record on disk (gitignored under
52
52
  > `.peaks/_sub_agents/`) keeps the prompt for the sub-agent to read;
53
53
  > CLI stdout stays metadata-only. Surface `originalPromptSize` +
54
- > `promptSize` so the LLM-side runner can still reason about headroom
55
- > without seeing the content. The prompt content the LLM should pass
54
+ > `promptSize` so the LLM-side runner can still reason about the size
55
+ > delta without seeing the content. The prompt content the LLM should pass
56
56
  > through lives in `data.toolCall.args.prompt` (the IDE-arg the
57
57
  > consumer passes to the tool), NOT in the outer envelope.
58
58
 
@@ -77,8 +77,6 @@ peaks sub-agent dispatch <role> --prompt <text> [--request-id <rid>] [--session-
77
77
  "dispatchRecordPath": ".peaks/_sub_agents/2026-06-06-session-5b1095/dispatch-002-2026-06-07-...-...json",
78
78
  "batchId": "<uuid>",
79
79
  "dispatchedInBatch": 3,
80
- "headroomCompressed": false,
81
- "headroomResult": null,
82
80
  "forcedAt": null,
83
81
  "contextImpact": {
84
82
  "promptBytes": 4321,
@@ -1,34 +0,0 @@
1
- export type HeadroomMode = 'balanced' | 'aggressive' | 'conservative';
2
- export interface HeadroomResult {
3
- readonly compressed: boolean;
4
- readonly originalSize: number;
5
- readonly compressedSize: number;
6
- readonly compressionRatio: number;
7
- readonly mode: HeadroomMode;
8
- /** `'HEADROOM_UNAVAILABLE'` on fallback; `null` on success. */
9
- readonly warning: string | null;
10
- /** Compressed prompt body. `null` if no compression happened. */
11
- readonly compressedPrompt: string | null;
12
- /** Tokens saved (from the SDK). 0 on fallback. */
13
- readonly tokensSaved: number;
14
- }
15
- /**
16
- * Compress a prompt via headroom-ai. The `fallback: true` option is
17
- * non-negotiable: if the proxy daemon is unavailable, the SDK returns
18
- * `result.compressed = false` and the original messages; we surface
19
- * that as `HEADROOM_UNAVAILABLE` warning + G7 metadata-only fallback.
20
- */
21
- export declare function compressPrompt(prompt: string, mode?: HeadroomMode): Promise<HeadroomResult>;
22
- /**
23
- * Bridge interface: when `--use-headroom` is set, share entries written
24
- * via `peaks sub-agent share` MAY also flow through headroom's
25
- * `SharedContext`. Slice #010 implements a peak-internal shared channel
26
- * (see `shared-channel.ts`); the headroom-side `SharedContext` is a
27
- * separate concept that future slices can layer on. For now this
28
- * function is a stub that returns the peak-internal channel ID, which
29
- * is enough to demonstrate the bridge contract.
30
- */
31
- export declare function buildSharedContextBridge(batchId: string): {
32
- peakChannelId: string;
33
- headroomContextId: string;
34
- };