@jslee124/forge 0.3.0 → 0.3.1

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 (35) hide show
  1. package/dist/index.js +1177 -90
  2. package/package.json +2 -1
  3. package/resources/docs/en/ARCHITECTURE.md +519 -0
  4. package/resources/docs/en/AUTHENTICATION.md +224 -0
  5. package/resources/docs/en/CLI_UI.md +266 -0
  6. package/resources/docs/en/CONFIGURATION.md +263 -0
  7. package/resources/docs/en/CONTEXT_MANAGEMENT.md +692 -0
  8. package/resources/docs/en/GETTING_STARTED.md +241 -0
  9. package/resources/docs/en/PLUGINS.md +622 -0
  10. package/resources/docs/en/PRODUCT.md +157 -0
  11. package/resources/docs/en/PROJECT_CONTEXT.md +225 -0
  12. package/resources/docs/en/RELEASING.md +94 -0
  13. package/resources/docs/en/SECURITY.md +272 -0
  14. package/resources/docs/en/SESSIONS.md +134 -0
  15. package/resources/docs/en/TROUBLESHOOTING.md +256 -0
  16. package/resources/docs/index.json +24334 -0
  17. package/resources/docs/zh-CN/ARCHITECTURE.md +174 -0
  18. package/resources/docs/zh-CN/AUTHENTICATION.md +96 -0
  19. package/resources/docs/zh-CN/CLI_UI.md +112 -0
  20. package/resources/docs/zh-CN/CONFIGURATION.md +221 -0
  21. package/resources/docs/zh-CN/CONTEXT_MANAGEMENT.md +200 -0
  22. package/resources/docs/zh-CN/GETTING_STARTED.md +193 -0
  23. package/resources/docs/zh-CN/PLUGINS.md +286 -0
  24. package/resources/docs/zh-CN/PRODUCT.md +86 -0
  25. package/resources/docs/zh-CN/PROJECT_CONTEXT.md +130 -0
  26. package/resources/docs/zh-CN/RELEASING.md +86 -0
  27. package/resources/docs/zh-CN/SECURITY.md +92 -0
  28. package/resources/docs/zh-CN/SESSIONS.md +69 -0
  29. package/resources/docs/zh-CN/TROUBLESHOOTING.md +185 -0
  30. package/resources/skills/forge-plugin-creator/SKILL.md +70 -0
  31. package/resources/skills/forge-plugin-creator/references/plugin-api.md +36 -0
  32. package/resources/skills/forge-plugin-creator/templates/index.mjs +30 -0
  33. package/resources/skills/forge-plugin-creator/templates/plugin.json +8 -0
  34. package/resources/skills/forge-plugin-creator/templates/plugin.test-template.ts +14 -0
  35. package/resources/skills/forge-product-help/SKILL.md +16 -0
@@ -0,0 +1,692 @@
1
+ # Context Management Improvement Plan
2
+
3
+ 简体中文 · Documentation index
4
+
5
+ ## Status
6
+
7
+ Roadmap Milestone 10 is implemented. This document records the design,
8
+ invariants, rollout decision, and follow-up live-evaluation gates. The default
9
+ remains `warn`; automatic checkpoint generation is opt-in until the published
10
+ provider-quality gates pass.
11
+
12
+ The first shipped Forge checkpoint uses a deterministic, redacted extractive
13
+ summarizer so default tests and manual `/compact` make no paid model call. It
14
+ allocates bounded space across every eligible historical message, removes
15
+ authority-like approval claims, and labels verification text as historical.
16
+ The checkpoint schema and adapter capability contract support opaque
17
+ provider-native state, but the current OpenAI AI SDK and DeepSeek adapters
18
+ advertise native compaction as unsupported because their active transports do
19
+ not yet expose a safe compact-item round trip.
20
+
21
+ ## Why this work is next
22
+
23
+ Forge already separates project instructions, completed conversation turns,
24
+ the current user request, and provider continuation data. It also bounds
25
+ instruction files, tool output, model steps, tool calls, and persisted session
26
+ size. These controls make execution inspectable, but they do not manage a
27
+ model's token window.
28
+
29
+ Today, every completed user/assistant turn is sent again on the next native
30
+ Forge request. A long session can therefore fail at the provider boundary even
31
+ when its persisted JSON remains within the session size limit. During a run,
32
+ assistant tool calls and tool results also accumulate through provider
33
+ continuation data. Forge currently has no request preflight, token-aware history
34
+ selection, durable summary checkpoint, or automatic compaction.
35
+
36
+ The next improvement should solve those concrete problems before adding vector
37
+ retrieval. Repository retrieval and conversation compaction are different:
38
+
39
+ - Repository retrieval decides which source files to inspect. Forge already has
40
+ bounded `list_files`, `search`, and `read_file` tools for this.
41
+ - Conversation management decides which prior turns and run observations fit in
42
+ the next model request.
43
+ - Persistent semantic memory decides what knowledge should survive beyond the
44
+ transcript. That remains out of scope for Milestone 10.
45
+
46
+ ## Market review
47
+
48
+ This plan was reviewed on 2026-08-19 against current first-party documentation
49
+ for OpenAI's Responses API, OpenCode V2, and Claude Code. Public OpenAI
50
+ documentation establishes the compaction mechanisms available to Codex-like
51
+ clients, but does not document Codex's exact client-side automatic threshold;
52
+ this plan does not infer that private implementation detail.
53
+
54
+ | System | Confirmed approach | Lesson for Forge |
55
+ | --- | --- | --- |
56
+ | OpenAI Responses API | Supports threshold-based server-side compaction and a standalone compact endpoint. The returned compaction item is encrypted, opaque, and carried forward as provider state. | Make compaction an adapter capability; do not require all providers to expose a human-readable summary. |
57
+ | OpenCode V2 | Estimates the rendered prompt, messages, and tools; compacts before a call; keeps a recent serialized tail; preserves durable messages; and retries one clean provider overflow. | Budget the final request, retain a bounded tail, preserve the transcript, and add one-shot recovery without duplicate input. |
58
+ | Claude Code | Clears older tool outputs before summarizing conversation history, exposes `/context` and `/compact`, reloads persistent instructions, defers some tool schemas, and stops repeated ineffective compaction. | Treat tool output and tool definitions as first-class budget consumers and add a no-progress guard. |
59
+
60
+ Primary references:
61
+
62
+ - [OpenAI API compaction](https://developers.openai.com/api/docs/guides/compaction)
63
+ - [OpenAI API conversation state](https://developers.openai.com/api/docs/guides/conversation-state)
64
+ - [OpenCode V2 compaction](https://opencode.ai/v2/docs/compaction)
65
+ - [OpenCode V2 configuration](https://opencode.ai/v2/docs/config#compaction)
66
+ - [Claude Code context management](https://code.claude.com/docs/en/how-claude-code-works#the-context-window)
67
+ - [Claude Agent SDK compaction](https://code.claude.com/docs/en/agent-sdk/agent-loop#automatic-compaction)
68
+ - [Claude Code memory](https://code.claude.com/docs/en/memory)
69
+
70
+ ### Review conclusions
71
+
72
+ The original direction remains sound: Forge should retain a lossless transcript,
73
+ derive a bounded active view, keep summaries below current instructions, and
74
+ delay vector RAG. The review changes the implementation in six ways:
75
+
76
+ 1. Reserve `max(requested output, buffer)` rather than subtracting both values
77
+ independently and wasting usable input capacity.
78
+ 2. Support two compaction strategies: provider-native opaque compaction and a
79
+ Forge-generated inspectable checkpoint.
80
+ 3. Prune completed old tool outputs before summarizing the broader conversation.
81
+ 4. Recover once from a clean provider-classified overflow, then fail honestly.
82
+ 5. Detect compaction thrashing instead of repeatedly paying for summaries that
83
+ reclaim too little space.
84
+ 6. Measure tool-schema cost and defer or narrow advertised tools only when the
85
+ trace data shows it is worthwhile.
86
+
87
+ ### Forge engine coverage
88
+
89
+ Milestone 10 must cover two different execution paths:
90
+
91
+ - **Native Forge Engine:** `runAgent` sends structured instructions,
92
+ conversation messages, tools, and adapter-owned continuation. It can use a
93
+ Forge checkpoint or an adapter's provider-native compaction.
94
+ - **Codex Engine:** the current CLI serializes the entire Forge conversation as
95
+ JSON inside each new Codex prompt. Context management inside Codex App Server
96
+ cannot remove the cost of that newly injected wrapper. The first fix is to
97
+ feed `codexPrompt` the same bounded active view used by native engines and
98
+ report the wrapper cost. A later experiment may map a Forge session to a
99
+ persistent App Server thread so only the new user turn is submitted, but that
100
+ requires explicit lifecycle, resume, and security semantics.
101
+
102
+ Forge must not claim control over Codex's internal compaction threshold. It may
103
+ record App Server context or compaction events when the public protocol exposes
104
+ them, but otherwise treats that layer as engine-owned and opaque.
105
+
106
+ ## Goals
107
+
108
+ Milestone 10 should:
109
+
110
+ 1. Prevent predictable context-window failures before a paid provider request.
111
+ 2. Make every context-selection decision visible in structured events and
112
+ `forge inspect`.
113
+ 3. Preserve recent conversational continuity while compacting only older,
114
+ completed turns.
115
+ 4. Keep the canonical transcript lossless and separate from the smaller active
116
+ model context.
117
+ 5. Preserve Forge's security boundary: old text and summaries cannot restore
118
+ approvals or override current instructions.
119
+ 6. Work across native model adapters without moving provider-specific message
120
+ rules into `@forge/core`.
121
+ 7. Prove value through deterministic and opt-in live evaluations.
122
+ 8. Use provider-native compaction when it preserves protocol state better than
123
+ a Forge-generated summary.
124
+
125
+ ## Non-goals
126
+
127
+ This milestone does not include:
128
+
129
+ - Vector embeddings, a vector database, or repository-wide semantic indexing
130
+ - Cross-workspace or cross-user memory
131
+ - Resuming an in-progress tool call or provider stream
132
+ - Deleting the original transcript after compaction
133
+ - Reconstructing provider reasoning that was not returned
134
+ - Treating model-generated summaries as trusted facts or policy
135
+ - Hiding context loss to make a request appear successful
136
+
137
+ ## Design principles
138
+
139
+ ### Budget before compression
140
+
141
+ Forge must first measure what it sends. Adding summarization before budget
142
+ accounting would make failures harder to explain and prevent objective
143
+ comparison with the current behavior.
144
+
145
+ ### Lossless record, bounded active view
146
+
147
+ The persisted transcript is the audit record. The model receives a derived,
148
+ bounded view of that record. Compaction changes the active view, not the
149
+ original messages.
150
+
151
+ ### Mandatory context cannot be silently dropped
152
+
153
+ Current effective instructions, the current user request, tool definitions
154
+ needed for the run, and protocol-required pending tool-call state are mandatory.
155
+ If they cannot fit after applying configured reserves, Forge should stop before
156
+ the provider call and explain which budget is exhausted.
157
+
158
+ ### Summaries are untrusted memory
159
+
160
+ A summary is derived from prior user and assistant text. It must be labeled as
161
+ conversation memory and placed below freshly loaded system instructions. It
162
+ cannot contain effective approvals, permission grants, current verification
163
+ status, or claims that supersede the current user request.
164
+
165
+ ### Provider boundaries stay explicit
166
+
167
+ `@forge/core` may reason about abstract context cost and message categories. A
168
+ model adapter remains responsible for provider-specific token estimation,
169
+ message encoding, tool-call pairing, reasoning blocks, and opaque continuation
170
+ data.
171
+
172
+ ### Instruction scope is deliberate
173
+
174
+ Forge will continue to reload instructions at the beginning of every run, then
175
+ freeze that resolved instruction snapshot for the run. It will record the
176
+ instruction paths and content hash used by every physical model attempt. This
177
+ differs from systems that synchronize instruction changes inside a run, but it
178
+ prevents a tool-created `AGENTS.md` edit from silently changing the active
179
+ prompt halfway through the same task. A later milestone may evaluate dynamic
180
+ instruction epochs as an explicit behavior.
181
+
182
+ ## Context model
183
+
184
+ Forge should classify request content instead of treating it as one string:
185
+
186
+ | Class | Examples | Retention rule |
187
+ | --- | --- | --- |
188
+ | Mandatory instructions | Current `AGENTS.md`, bounded Skill catalog/selection directives, plugin prompt contributions | Reload every run; never summarized; loaded Skill bodies enter as bounded tool results |
189
+ | Current request | The active user prompt and referenced paths | Never summarized or dropped |
190
+ | Protocol state | Pending assistant tool call, matching tool result, provider continuation | Preserve exactly as required by the adapter |
191
+ | Recent conversation | Most recent completed user/assistant turns | Keep verbatim within a configurable tail budget |
192
+ | Older conversation | A completed prefix of earlier turns | Eligible for checkpoint summarization |
193
+ | Repository observations | File reads, searches, command output | Run-scoped; bounded at tool boundaries and re-read when needed |
194
+ | Advertised tools | Built-in and plugin tool names, descriptions, and schemas | Count every request; narrow or defer only through an explicit capability |
195
+ | Audit evidence | Full transcript and JSONL run traces | Persist separately; not automatically injected |
196
+
197
+ The initial request order remains conceptually:
198
+
199
+ ```text
200
+ current effective instructions
201
+ derived conversation-memory checkpoint, if any
202
+ recent verbatim conversation turns
203
+ current user request
204
+ tool definitions
205
+ ```
206
+
207
+ Within a run, adapter-owned continuation and Forge tool results extend that
208
+ initial request according to the provider protocol.
209
+
210
+ ## Token budget
211
+
212
+ ### Capability contract
213
+
214
+ Add a provider-neutral capability description exposed by each adapter:
215
+
216
+ ```ts
217
+ type JsonValue =
218
+ | null
219
+ | boolean
220
+ | number
221
+ | string
222
+ | readonly JsonValue[]
223
+ | { readonly [key: string]: JsonValue };
224
+
225
+ interface ModelContextCapabilities {
226
+ contextWindowTokens: number;
227
+ maxOutputTokens?: number;
228
+ estimateRequestTokens(request: ModelRequest): Promise<TokenEstimate>;
229
+ nativeCompaction: "unsupported" | "opaque-provider-item";
230
+ continuationProjection: "unsupported" | "adapter-owned";
231
+ }
232
+
233
+ interface TokenEstimate {
234
+ tokens: number;
235
+ method: "provider-tokenizer" | "sdk" | "conservative-fallback";
236
+ confidence: "exact" | "estimated";
237
+ }
238
+ ```
239
+
240
+ Capabilities must come from an explicit, tested adapter table or provider API.
241
+ Unknown models must not inherit an optimistic window. They should use a
242
+ conservative configured fallback and expose that provenance.
243
+
244
+ ### Budget calculation
245
+
246
+ Before each model step, calculate:
247
+
248
+ ```text
249
+ available input budget
250
+ = model context window
251
+ - max(requested output tokens, safety buffer tokens)
252
+
253
+ remaining history budget
254
+ = available input budget
255
+ - current instructions
256
+ - current request
257
+ - tool definitions
258
+ - protocol-required continuation
259
+ ```
260
+
261
+ Initial configuration should expose only values users can reason about:
262
+
263
+ ```json
264
+ {
265
+ "context": {
266
+ "mode": "warn",
267
+ "reservedOutputTokens": 4096,
268
+ "bufferTokens": 8192,
269
+ "recentTailTokens": 12000,
270
+ "summaryTargetTokens": 1200
271
+ }
272
+ }
273
+ ```
274
+
275
+ Recommended modes:
276
+
277
+ - `off`: preserve current behavior but continue reporting provider usage.
278
+ - `warn`: run preflight and warn; reject only when mandatory context cannot fit.
279
+ - `compact`: use a valid checkpoint and create a new one when thresholds require
280
+ it. This remains opt-in until evaluation gates pass.
281
+
282
+ Project configuration may lower budgets or select a stricter mode, but it must
283
+ not increase user-defined ceilings or disable a user-required guard.
284
+
285
+ `bufferTokens` is not an additional output reserve. The larger of the output
286
+ allowance and buffer is subtracted once. This follows the practical pattern in
287
+ OpenCode and avoids the original plan's unnecessarily conservative double
288
+ reservation while still leaving room for reasoning and provider variance.
289
+
290
+ ### Estimation accuracy
291
+
292
+ Every completed provider step should compare the preflight estimate with
293
+ provider-reported input tokens when available. Store aggregate error, not raw
294
+ secret material. A model whose estimator repeatedly undercounts beyond the
295
+ safety buffer should be blocked from automatic compaction rollout until its
296
+ adapter is corrected.
297
+
298
+ ## Conversation compaction
299
+
300
+ ### Selection algorithm
301
+
302
+ For the first compaction implementation:
303
+
304
+ 1. Reload current instructions and compute mandatory cost.
305
+ 2. Keep the current request untouched.
306
+ 3. Keep a bounded recent serialized tail up to `recentTailTokens`, ending only
307
+ at a safe message or tool-protocol boundary.
308
+ 4. Select only a contiguous completed prefix older than that window.
309
+ 5. Reuse an existing checkpoint when its source range, tail range, and hashes
310
+ still match.
311
+ 6. Use provider-native compaction when the adapter supports it; otherwise
312
+ summarize that prefix to the target budget.
313
+ 7. Re-estimate the complete request.
314
+ 8. If it still does not fit, reduce the recent tail only down to a documented
315
+ hard floor; never remove the current turn or protocol-required state.
316
+ 9. If safe reduction is impossible, stop with `limit_reached` and report the
317
+ context budget breakdown.
318
+
319
+ A contiguous prefix makes provenance understandable and avoids a summary built
320
+ from unexplained holes in the conversation.
321
+
322
+ ### Checkpoint schema
323
+
324
+ Session schema version 2 should retain `messages` as the canonical transcript
325
+ and add an optional derived checkpoint:
326
+
327
+ ```ts
328
+ interface ContextCheckpoint {
329
+ schemaVersion: 1;
330
+ strategy: "forge-summary" | "provider-native";
331
+ summarizedThroughMessageIndex: number;
332
+ sourceHash: string;
333
+ retainedTailStartIndex: number;
334
+ retainedTailHash: string;
335
+ summary?: string;
336
+ opaqueProviderItem?: JsonValue;
337
+ compactionModelId: string;
338
+ estimatedCheckpointTokens: number;
339
+ sourceMessageCount: number;
340
+ createdAt: string;
341
+ safetyLabels: readonly [
342
+ "untrusted-conversation-memory",
343
+ "no-approval-state",
344
+ "no-policy-authority"
345
+ ];
346
+ }
347
+ ```
348
+
349
+ The checkpoint should be written atomically with the session snapshot. A source
350
+ hash prevents reuse after transcript migration or manual repair. Schema
351
+ validation must reject a checkpoint whose source or tail range exceeds the
352
+ transcript. Exactly one of `summary` and `opaqueProviderItem` must be present,
353
+ and opaque items may only be returned to the adapter and provider that created
354
+ them. Traces record their hash and token cost, never an attempted interpretation.
355
+ If the user changes provider or model and the opaque item is incompatible,
356
+ Forge rebuilds from the canonical transcript using a compatible strategy.
357
+
358
+ ### Summary contract
359
+
360
+ The summarizer prompt should request a concise, factual checkpoint containing:
361
+
362
+ - User goals and explicit constraints still relevant to future turns
363
+ - Decisions made and the reason recorded in the conversation
364
+ - Files or components discussed
365
+ - Completed work and unresolved follow-ups
366
+ - Known verification results, each labeled with its originating run rather than
367
+ presented as current truth
368
+
369
+ It should explicitly exclude:
370
+
371
+ - Credentials and recognized secret values
372
+ - Approval decisions and permission grants
373
+ - Instructions to override the current system or project context
374
+ - Provider reasoning text unless it was already part of the visible assistant
375
+ response
376
+ - Guesses introduced only to make the summary sound complete
377
+
378
+ Summary generation should consume redacted persisted messages. The result must
379
+ pass size, schema, and safety-label validation before it can replace the active
380
+ view. On failure, Forge keeps the previous valid checkpoint or stops with an
381
+ actionable budget message; it never overwrites the transcript.
382
+
383
+ Provider-native compaction follows a different contract. For example, OpenAI's
384
+ Responses API can return an encrypted compaction item that is intentionally not
385
+ human-readable. Forge should preserve that item opaquely, associate it with the
386
+ provider/model and source hash, and rely on the adapter for reuse. `/context`
387
+ must clearly distinguish an inspectable Forge summary from opaque provider
388
+ state.
389
+
390
+ ### Manual-first rollout
391
+
392
+ Before automatic compaction is enabled, add:
393
+
394
+ ```text
395
+ /context Show active model, window, budget categories, retained turns, and checkpoint provenance
396
+ /compact --dry-run Preview the eligible range and projected budget without a model call
397
+ /compact Generate a checkpoint and show the new estimate
398
+ ```
399
+
400
+ The explicit `/compact` command is sufficient user intent and does not need a
401
+ second confirmation prompt because it neither deletes the transcript nor grants
402
+ authority. Manual compaction is not a security approval for later tools. The
403
+ output must make clear that the full transcript is retained.
404
+
405
+ ## In-run context pressure
406
+
407
+ Conversation checkpoints solve pressure between completed runs. Tool-heavy runs
408
+ can still grow through assistant calls, provider reasoning blocks, and tool
409
+ results.
410
+
411
+ The initial safe behavior should be:
412
+
413
+ 1. Bound tool output at execution as Forge already does.
414
+ 2. Ask adapters to estimate the complete next request, including continuation.
415
+ 3. Keep pending tool calls and their results intact.
416
+ 4. For older completed tool interactions, let the adapter replace large output
417
+ with an explicit bounded projection containing the tool name, success state,
418
+ truncation marker, content hash, and a short result excerpt.
419
+ 5. Avoid adding a second copy of tool output outside the canonical tool result.
420
+ 6. Prefer a targeted `read_file` or `search` retry over retaining a larger
421
+ observation indefinitely.
422
+ 7. Include every advertised tool schema in the estimate. If schemas become a
423
+ material fixed cost, evaluate a provider-supported tool-search/catalog
424
+ mechanism or a deterministic task-specific subset; never silently hide a
425
+ tool the runtime already promised to the model.
426
+ 8. Stop with `limit_reached` before a request that cannot fit safely.
427
+
428
+ Do not generically rewrite opaque continuation objects in `@forge/core`.
429
+ Provider-specific in-run compaction may be added later only when an adapter can
430
+ prove that it preserves tool-call/result pairing and required reasoning blocks.
431
+ Until then, stopping honestly is safer than sending a malformed continuation.
432
+
433
+ ### Overflow recovery
434
+
435
+ Preflight estimation is approximate, so adapters should classify provider
436
+ context-overflow errors. Forge may compact and retry the physical model attempt
437
+ once only when the failed attempt produced no assistant text, tool call, tool
438
+ result, or other externally visible retry evidence. The retry must reuse the
439
+ same admitted user input rather than append it again. A second overflow becomes
440
+ an ordinary failure with the estimate and provider limit in the trace.
441
+
442
+ ### No-progress guard
443
+
444
+ Compaction must not loop when fixed instructions, the current request, or tool
445
+ schemas dominate the window. Track reclaimed tokens and compaction attempts for
446
+ the active input. Stop when any of these occurs:
447
+
448
+ - The same source hash has already been compacted for the same attempt.
449
+ - The checkpoint reclaims less than the runtime minimum useful tokens.
450
+ - The request remains over budget after one overflow recovery.
451
+ - The run reaches its compaction-attempt limit.
452
+
453
+ This mirrors the practical failure handling documented by OpenCode and Claude
454
+ Code while keeping Forge's terminal status explicit.
455
+
456
+ ## Events, traces, and inspection
457
+
458
+ Add versioned events such as:
459
+
460
+ ```text
461
+ context.budgeted
462
+ context.warning
463
+ context.compaction.started
464
+ context.compaction.completed
465
+ context.compaction.failed
466
+ context.limit_reached
467
+ ```
468
+
469
+ The budget event should include:
470
+
471
+ - Adapter, model ID, context-window source, and estimation method
472
+ - Estimated tokens by category
473
+ - Requested output allowance, safety buffer, and effective single reserve
474
+ - Retained verbatim message count
475
+ - Summarized source range and checkpoint ID, when present
476
+ - Compaction strategy, reclaimed tokens, and retry reason
477
+ - Instruction snapshot hash and advertised-tool schema cost
478
+ - Provider-reported input usage after completion
479
+
480
+ Traces should record the selection decision and hashes/provenance, not duplicate
481
+ the entire transcript or summary in every event. `forge inspect` should render a
482
+ compact budget table and estimation error.
483
+
484
+ ## Security and correctness invariants
485
+
486
+ The implementation must preserve these invariants:
487
+
488
+ 1. Fresh user/project instructions always outrank historical conversation and
489
+ summaries.
490
+ 2. Compaction never restores approvals, trust decisions, environment values, or
491
+ permission profiles.
492
+ 3. A summary cannot mark a previously failing verification as currently
493
+ passing.
494
+ 4. Only completed conversation turns are eligible for cross-run compaction.
495
+ 5. Pending tool calls and results remain paired according to adapter rules.
496
+ 6. The canonical transcript is not mutated or deleted by compaction.
497
+ 7. Configured secrets are redacted before checkpoint generation and persistence.
498
+ 8. Plugin observers receive redacted context events and cannot replace the
499
+ selected checkpoint or weaken context limits.
500
+ 9. Context failure is reported as a real terminal condition, never disguised as
501
+ a successful assistant answer.
502
+ 10. A provider overflow retry cannot duplicate admitted input or repeat a tool
503
+ side effect.
504
+ 11. Instructions are frozen for one run and their hash is stable across its
505
+ physical model attempts.
506
+ 12. Opaque provider items are sensitive session state: plugin observers and
507
+ ordinary trace events receive only metadata and hashes.
508
+
509
+ ## Package boundaries
510
+
511
+ Recommended ownership:
512
+
513
+ | Package | Responsibility |
514
+ | --- | --- |
515
+ | `@forge/core` | Context categories, abstract budget policy, events, and stop decisions |
516
+ | Model adapters | Model capabilities, token estimation, provider message encoding, continuation rules |
517
+ | `@forge/config` | Versioned context configuration, provenance, and strictness merge |
518
+ | `@forge/persistence` | Session v2 migration, checkpoint validation, atomic storage |
519
+ | `apps/cli` | `/context`, `/compact`, warnings, inspection rendering, and Codex wrapper budgeting |
520
+ | Codex App Server client | Expose public engine-owned usage or compaction events and optional persistent-thread lifecycle |
521
+ | `evals` | Long-session fixtures, metrics, comparison reports, release gates |
522
+
523
+ A separate package should be created only if tokenization dependencies cannot
524
+ remain adapter-local without duplication.
525
+
526
+ ## Implementation sequence
527
+
528
+ ### Phase A: Measurement foundation
529
+
530
+ 1. Add context capability and estimator contracts.
531
+ 2. Implement deterministic fake estimators for runtime tests.
532
+ 3. Add adapter capability tables and conservative unknown-model behavior.
533
+ 4. Emit `context.budgeted` before each provider request.
534
+ 5. Compare estimates with returned usage and extend `forge inspect`.
535
+ 6. Count advertised tool schemas and instruction snapshots separately.
536
+ 7. Measure the serialized Forge conversation wrapper sent to Codex App Server.
537
+ 8. Ship `warn` mode with no history mutation.
538
+
539
+ Exit gate: all requests have an inspectable budget, and mandatory-context
540
+ overflow fails before contacting the provider.
541
+
542
+ ### Phase B: Derived active context
543
+
544
+ 1. Separate canonical session messages from the active request view.
545
+ 2. Implement deterministic recent-turn selection without summary generation.
546
+ 3. Use that derived active view for both native adapters and `codexPrompt`.
547
+ 4. Add session v1-to-v2 migration and checkpoint validation.
548
+ 5. Add `/context` and dry-run compaction previews.
549
+
550
+ Exit gate: tests prove the transcript is unchanged and selection is stable
551
+ across resume.
552
+
553
+ ### Phase C: Checkpoint generation
554
+
555
+ 1. Implement the constrained summarizer behind an interface and fake.
556
+ 2. Add an adapter hook for provider-native opaque compaction.
557
+ 3. Add source/tail hashing, redaction, validation, and atomic persistence.
558
+ 4. Add `/compact --dry-run`, `/compact`, and failure-safe checkpoint
559
+ replacement.
560
+ 5. Add opt-in `compact` mode.
561
+
562
+ Exit gate: manual compaction reduces estimated input tokens, preserves required
563
+ facts in fixtures, and cannot carry authority from historical text.
564
+
565
+ ### Phase D: In-run guards
566
+
567
+ 1. Re-estimate before every model step.
568
+ 2. Include adapter-owned continuation cost.
569
+ 3. Add safe adapter-owned projection of old completed tool output.
570
+ 4. Add one-shot clean-overflow recovery and no-progress detection.
571
+ 5. Add typed context-limit stop reasons.
572
+ 6. Add tool-heavy and tool-schema-heavy deterministic fixtures.
573
+ 7. Prototype lazy tool advertisement only if measured schema cost justifies the
574
+ added complexity.
575
+
576
+ Exit gate: no known over-budget request is sent silently, and tool protocols
577
+ remain valid.
578
+
579
+ ### Phase E: Evaluation and default decision
580
+
581
+ 1. Run `off`, `warn`, and `compact` modes on identical fixtures and live trials.
582
+ 2. Publish aggregate context and task-quality metrics.
583
+ 3. Define acceptable regression and estimator-error thresholds.
584
+ 4. Enable automatic compaction by default only if those thresholds pass.
585
+
586
+ Exit gate: the default is chosen from published evidence rather than feature
587
+ availability.
588
+
589
+ ## Test plan
590
+
591
+ ### Unit tests
592
+
593
+ - Budget arithmetic at exact boundaries
594
+ - Conservative fallback for unknown models
595
+ - Turn selection with empty, odd, and maximum-sized histories
596
+ - Checkpoint source range and hash validation
597
+ - Configuration strictness and provenance
598
+ - Secret redaction before summary generation
599
+ - Summary failure preserving the last valid checkpoint
600
+
601
+ ### Runtime and adapter tests
602
+
603
+ - Estimate emitted before every model step
604
+ - Provider-reported token usage correlated with the correct estimate
605
+ - OpenAI and DeepSeek tool-call continuations remain valid
606
+ - Provider-native compacted items remain opaque and provider-bound
607
+ - Mandatory context overflow performs no provider call
608
+ - A clean overflow retries once without duplicating input
609
+ - An overflow after partial assistant output does not retry
610
+ - Repeated low-value compaction stops instead of thrashing
611
+ - Cancellation during summary generation leaves the session valid
612
+ - Resume reloads current instructions but reuses a matching checkpoint
613
+ - Codex Engine receives the bounded active view instead of an unbounded full
614
+ Forge transcript
615
+ - Switching away from a provider-native checkpoint rebuilds from the canonical
616
+ transcript
617
+
618
+ ### End-to-end fixtures
619
+
620
+ 1. **Long recall:** an early user constraint remains available after more turns
621
+ than the verbatim window.
622
+ 2. **Instruction change:** a changed `AGENTS.md` overrides contradictory old
623
+ conversation after resume.
624
+ 3. **Hostile history:** historical text requesting unrestricted access remains
625
+ inert after summarization.
626
+ 4. **Verification freshness:** an old passing test result is not treated as
627
+ evidence after later code changes.
628
+ 5. **Tool pressure:** repeated bounded reads approach the window and stop or
629
+ compact according to adapter capability.
630
+ 6. **Recovery:** a process restart restores the same transcript and checkpoint
631
+ provenance.
632
+ 7. **Schema pressure:** a large plugin tool catalog is measured accurately and
633
+ cannot crowd out mandatory context silently.
634
+ 8. **Overflow retry:** one clean overflow compacts and retries without replaying
635
+ user input or tool side effects.
636
+ 9. **Codex wrapper:** a long Forge session bounds the JSON wrapper sent to Codex
637
+ App Server and preserves the same seeded constraints as the native engine.
638
+
639
+ ## Evaluation metrics and release gates
640
+
641
+ Record at least:
642
+
643
+ - Task and grader pass rate
644
+ - Provider-reported input/output tokens
645
+ - Estimated input tokens and absolute/relative estimation error
646
+ - Summary-generation tokens, latency, and failures
647
+ - Number of compactions and summarized messages
648
+ - Verbatim recent turns retained
649
+ - Context-limit stops and provider context errors
650
+ - Overflow recovery attempts and duplicate-input checks
651
+ - Tool-output and advertised-schema token cost
652
+ - Tokens reclaimed per compaction and no-progress stops
653
+ - Recall accuracy for seeded constraints and decisions
654
+ - Safety-invariant failures
655
+
656
+ Proposed gates before `compact` becomes the default:
657
+
658
+ - No safety-invariant regression in deterministic tests
659
+ - No transcript corruption across failure, cancellation, or resume tests
660
+ - No known provider request exceeds its declared input budget
661
+ - Median input-token reduction of at least 30% on long-session fixtures
662
+ - No more than a 5 percentage-point task pass-rate regression against `warn`
663
+ - At least 95% recall of explicitly seeded durable constraints in the
664
+ long-session evaluation set
665
+
666
+ These thresholds are initial hypotheses. The checked-in report may revise them,
667
+ but the revision must be made before interpreting the final trial results.
668
+
669
+ ## Risks and mitigations
670
+
671
+ | Risk | Mitigation |
672
+ | --- | --- |
673
+ | Summary loses a critical constraint | Keep recent turns verbatim, use seeded-recall evals, retain full transcript |
674
+ | Summary carries prompt injection | Label as untrusted memory, place below current instructions, test hostile history |
675
+ | Token estimator undercounts | Conservative fallback, safety buffer, compare with provider usage |
676
+ | Summary generation adds cost and latency | Reuse hashed checkpoints, compact only past thresholds, report overhead |
677
+ | Provider tool protocol breaks | Keep continuation adapter-owned; stop rather than generically rewrite it |
678
+ | Opaque compaction becomes provider lock-in | Bind it to the adapter/model and retain the canonical transcript for fallback |
679
+ | Configuration becomes too complex | Start with three modes and a small documented budget surface |
680
+ | Trace leaks duplicated sensitive text | Store budget metadata and hashes; keep normal redaction pipeline |
681
+ | Compaction hides what happened | Preserve canonical transcript and expose summarized ranges in `/context` and traces |
682
+ | Compaction repeatedly reclaims too little | Enforce minimum reclaimed tokens and a per-input attempt limit |
683
+
684
+ ## Decision on RAG
685
+
686
+ Do not add vector RAG as part of Milestone 10. First measure whether long-session
687
+ failures come from conversation growth, repeated tool observations, or poor
688
+ repository discovery. If later evaluations show that lexical `search` and
689
+ targeted file reads miss relevant code, run a separate retrieval experiment
690
+ comparing lexical, semantic, and hybrid approaches on task success, retrieval
691
+ accuracy, tokens, latency, and index cost. Only promote that experiment into the
692
+ Roadmap when it beats the simpler baseline.