Background
ContextManager is today an opaque internal implementation detail of Agent. It holds the conversation history, activated skill bodies, and system instruction, but exposes them only through mutating methods. There is no way to snapshot, export, import, fork, or inspect the context from outside the agent.
Problems this causes
1. Session resumption is reconstructed, not restored — src/state/session.ts re-parses a JSONL log to reconstruct Message[] on resume. This is inherently fragile (see issue #58) because the session log format is not the same as the context format — there is a lossy transformation in both directions.
2. Context compaction (issue #26) is architecturally awkward — compaction requires replacing a window of messages with a summary. With context as opaque internal state, compaction must be implemented inside ContextManager itself, making it a god object responsible for both history management and compression strategy.
3. Multi-agent is blocked — a parent agent cannot pass its context to a child agent, or receive a sub-agent's context back, because context is not a transferable value.
4. Forking/branching is impossible — exploratory branches (e.g. "try approach A, if it fails, revert to here and try approach B") require context snapshots.
5. Debugging is opaque — users cannot inspect "what context does the agent have right now?" without reading raw session files.
Proposed design
Make context a plain serializable value type:
// src/core/context.ts
export interface AgentContext {
messages: Message[];
activatedSkills: Record<string, string>; // name → injected body
systemInstruction: string;
metadata: {
cwd: string;
sessionId: string;
gitSnapshot: string;
tmpDir?: string;
};
}
The agent is a processor: (AgentContext, userInput) → (AgentContext, AsyncIterable<AgentEvent>). Context is passed in and a new context is returned (or the old one mutated with a clear snapshot API).
// Fork for exploratory branching
const snapshot = agent.snapshotContext();
await agent.run("try approach A");
if (failed) {
agent.restoreContext(snapshot);
await agent.run("try approach B");
}
Session persistence becomes trivial: serialize the AgentContext directly to JSON rather than reconstructing it from an event log.
Acceptance criteria
Location
src/agent/context.ts — ContextManager class
src/state/session.ts — reconstructMessages() can be replaced
src/agent/core.ts — Agent class interface
Background
ContextManageris today an opaque internal implementation detail ofAgent. It holds the conversation history, activated skill bodies, and system instruction, but exposes them only through mutating methods. There is no way to snapshot, export, import, fork, or inspect the context from outside the agent.Problems this causes
1. Session resumption is reconstructed, not restored —
src/state/session.tsre-parses a JSONL log to reconstructMessage[]on resume. This is inherently fragile (see issue #58) because the session log format is not the same as the context format — there is a lossy transformation in both directions.2. Context compaction (issue #26) is architecturally awkward — compaction requires replacing a window of messages with a summary. With context as opaque internal state, compaction must be implemented inside
ContextManageritself, making it a god object responsible for both history management and compression strategy.3. Multi-agent is blocked — a parent agent cannot pass its context to a child agent, or receive a sub-agent's context back, because context is not a transferable value.
4. Forking/branching is impossible — exploratory branches (e.g. "try approach A, if it fails, revert to here and try approach B") require context snapshots.
5. Debugging is opaque — users cannot inspect "what context does the agent have right now?" without reading raw session files.
Proposed design
Make context a plain serializable value type:
The agent is a processor:
(AgentContext, userInput) → (AgentContext, AsyncIterable<AgentEvent>). Context is passed in and a new context is returned (or the old one mutated with a clear snapshot API).Session persistence becomes trivial: serialize the
AgentContextdirectly to JSON rather than reconstructing it from an event log.Acceptance criteria
AgentContextis a plain, JSON-serializable interface (no class, no private fields)AgentexposessnapshotContext(): AgentContextandrestoreContext(ctx: AgentContext): voidAgentContextserialization directly, replacingreconstructMessages()compact(ctx: AgentContext): AgentContextwithout touchingAgentinternalsLocation
src/agent/context.ts—ContextManagerclasssrc/state/session.ts—reconstructMessages()can be replacedsrc/agent/core.ts—Agentclass interface