Files
claude-mem/.plan/endless-mode-rebase.md
T
Alex Newman cd05b626a7
Publish to npm / publish (push) Has been cancelled
chore: bump version to 10.4.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 19:32:51 -05:00

215 lines
9.6 KiB
Markdown

# Plan: Endless Mode Re-implementation on Current Main
## Context
Endless mode was implemented on `beta/endless-mode` branch (diverged at v7.0.0). Main is now at v10.4.1 — **902 commits ahead**. Rebasing is impractical. This plan re-implements endless mode on top of current main, using the old branch as a reference for concepts only.
### What Endless Mode Does
When enabled, after each tool execution:
1. The PostToolUse hook waits for the SDK agent to process the observation
2. The processed observation (title, narrative, facts) is injected back into Claude's context via `additionalContext`
3. Large tool inputs are cleared from the transcript to save tokens
4. Net effect: Claude sees compressed observations instead of raw tool data → extends effective context window
### Key Problem from Previous Attempt
The save-hook blocked for 60-90s waiting for SDK processing, making sessions unusably slow. The fundamental tension: AI-processed observations require time, but hooks have a 120s hard limit.
### Branch Strategy
Create a new branch `feature/endless-mode-v2` from current main. Do NOT touch the old `beta/endless-mode` branch.
---
## Phase 0: Documentation Discovery (Reference Gathering)
### 0.1 — Read old branch implementation for reference patterns
- `git show beta/endless-mode:src/hooks/save-hook.ts` — synchronous wait pattern
- `git show beta/endless-mode:src/hooks/context-injection.ts` — observation formatting
- `git show beta/endless-mode:src/hooks/pre-tool-use-hook.ts` — tool_use_id tracking
- `git show beta/endless-mode:src/services/worker/SessionManager.ts``waitForNextObservation()`
- `git show beta/endless-mode:docs/context/state-of-endless.md` — architecture doc
### 0.2 — Read current main integration points
- `src/hooks/hook-response.ts:1-15` — current hook response format
- `src/services/worker/SessionManager.ts:21-100` — current session management
- `src/services/worker/SDKAgent.ts:43-150` — current SDK agent flow, event emission
- `src/services/worker/http/routes/SessionRoutes.ts:498-573` — current observation endpoint
- `src/services/sqlite/SessionStore.ts:1503-1560` — current storeObservation
- `src/shared/SettingsDefaultsManager.ts:77-133` — current settings defaults
### 0.3 — Identify Claude Code hook contract
- `plugin/plugin.json` — current hook configuration (which hooks exist, their types)
- Check if `PreToolUse` hook type is available in Claude Code plugin spec
- Check `additionalContext` field availability in hook response contract
### Deliverable
List of exact APIs, file locations, and patterns available for each integration point. Anti-pattern list of methods that existed on the old branch but don't exist on current main.
---
## Phase 1: Database Schema — Add `tool_use_id` Column
### What to implement
- Add migration 20 to `src/services/sqlite/SessionStore.ts` (after migration 19 at ~line 53)
- Add nullable `tool_use_id TEXT` column to observations table
- Add index: `CREATE INDEX idx_observations_tool_use_id ON observations(tool_use_id)`
- Add `getObservationsByToolUseId(toolUseId: string)` method to SessionStore
- Update `storeObservation()` signature to accept optional `tool_use_id?: string`
### Files to modify
- `src/services/sqlite/SessionStore.ts` — migration + store method
- `src/services/sqlite/observations/types.ts` — add tool_use_id to StoreObservationResult
- `src/types/transcript.ts` — verify ToolResultContent.tool_use_id matches Claude's format
### Verification
- `npm run build` succeeds
- Worker starts without errors
- New column appears in observations table: `sqlite3 ~/.claude-mem/claude-mem.db ".schema observations"`
### Anti-patterns
- Do NOT make tool_use_id NOT NULL — old observations won't have it
- Do NOT modify existing migrations — only append new ones
---
## Phase 2: Settings — Add Endless Mode Configuration
### What to implement
- Add to `SettingsDefaultsManager.ts` DEFAULTS (~line 77):
- `CLAUDE_MEM_ENDLESS_MODE`: `'false'` (disabled by default)
- `CLAUDE_MEM_ENDLESS_WAIT_TIMEOUT_MS`: `'90000'` (90 second timeout)
- Add helper method `isEndlessModeEnabled(): boolean`
### Files to modify
- `src/shared/SettingsDefaultsManager.ts`
### Verification
- Settings load correctly with defaults
- Can override via `~/.claude-mem/settings.json`
- Can override via environment variable
### Anti-patterns
- Do NOT add UI for toggling yet — settings.json is sufficient for beta
---
## Phase 3: Worker-Side — Event-Based Observation Completion Signaling
### What to implement
- In `SessionManager.ts`: Add `waitForNextObservation(sessionDbId, toolUseId, timeoutMs)` method
- Uses existing `sessionQueues` EventEmitter infrastructure
- Waits for `observation_saved` event matching toolUseId
- Returns the observation or null on timeout
- In `SDKAgent.ts`: After `storeObservation()` call, emit `observation_saved` event with observation data and toolUseId
- In `SessionRoutes.ts`:
- Accept `tool_use_id` in observation POST body
- Accept `wait_until_observation_is_saved=true` query parameter
- When waiting: call `SessionManager.waitForNextObservation()` before responding
- When not waiting (default): existing fire-and-forget behavior
### Files to modify
- `src/services/worker/SessionManager.ts`
- `src/services/worker/SDKAgent.ts`
- `src/services/worker/http/routes/SessionRoutes.ts`
### Verification
- Worker builds and starts
- Default (non-endless) observation flow is unaffected
- Can POST with `wait_until_observation_is_saved=true` and get observation back in response
### Anti-patterns
- Do NOT add SSE/streaming — simple HTTP request/response with await is sufficient
- Do NOT modify the existing fire-and-forget path — only add the new waiting path
- Do NOT add a pre-tool-use endpoint yet — tool_use_id comes from the hook, not a separate call
---
## Phase 4: Hook-Side — PostToolUse Synchronous Injection
### What to implement
- Modify the PostToolUse hook (save-hook) to:
1. Check if endless mode is enabled via settings
2. Extract `tool_use_id` from the hook input (Claude Code provides this)
3. If endless mode ON: POST observation with `wait_until_observation_is_saved=true` and `tool_use_id`
4. Receive processed observation in HTTP response
5. Format observation as markdown (copy pattern from old `context-injection.ts`)
6. Return hook response with `additionalContext` field containing formatted observation
7. If endless mode OFF: existing fire-and-forget behavior (unchanged)
- Create `src/hooks/observation-formatter.ts` utility for markdown formatting
### Files to modify
- `src/hooks/save-hook.ts` (or whatever the current PostToolUse hook source is)
- `src/hooks/observation-formatter.ts` (NEW)
- `src/hooks/hook-response.ts` — add `additionalContext` support to response type
### Verification
- With endless mode OFF: behavior identical to current
- With endless mode ON: observations appear in Claude's context after tool use
- Hook respects 120s Claude Code timeout (90s observation wait + buffer)
### Anti-patterns
- Do NOT add transcript clearing in this phase — that's a separate optimization
- Do NOT block indefinitely — always use timeout with graceful fallback
- Do NOT swallow errors in the wait path — if it fails, fall back to fire-and-forget
---
## Phase 5: Build, Test, and Validate
### What to implement
- `npm run build-and-sync` — full build
- Manual testing:
1. Enable endless mode in settings.json
2. Start a Claude Code session
3. Execute tool uses and verify observations appear in context
4. Verify non-endless mode is unaffected
- Add basic unit tests in `tests/endless-mode/`
### Verification checklist
- [ ] `npm run build` succeeds with zero errors
- [ ] Worker starts without errors
- [ ] Non-endless mode behavior unchanged (regression check)
- [ ] With endless mode ON: observation appears in Claude's context after tool use
- [ ] Timeout fallback works (kill worker mid-processing, verify graceful degradation)
- [ ] Settings toggle works (on/off without restart)
- [ ] Database migration applies cleanly on fresh and existing databases
### Anti-patterns
- Do NOT ship to npm/release yet — this is beta
- Do NOT add documentation updates yet — feature must be validated first
- Do NOT add telemetry or analytics in initial implementation
---
## Phase 6: Transcript Clearing Optimization (Optional, After Validation)
### What to implement
- After observation injection is working, add transcript clearing:
- After successful observation injection, clear the large `tool_input` from Claude's transcript JSONL
- This is the actual token savings mechanism — compressed observation replaces raw tool data
- Read from old branch: `git show beta/endless-mode:src/hooks/context-injection.ts` for `clearToolInputInTranscript()`
### Files to modify
- `src/hooks/save-hook.ts` — add transcript clearing after successful injection
- `src/hooks/transcript-clearer.ts` (NEW) — utility for JSONL manipulation
### Verification
- Token count decreases after observation injection
- Transcript JSONL remains valid after clearing
- Claude Code doesn't break when transcript entries are modified
### Anti-patterns
- Do NOT clear transcript if observation injection failed — leave raw data intact
- Do NOT modify transcript entries other than the current tool use
- Do NOT implement until Phase 5 validation is complete
---
## Decisions Needed from User
1. **Branch name**: `feature/endless-mode-v2` (proposed) — acceptable?
2. **Scope**: Phases 1-5 are core. Phase 6 is optional. Should Phase 6 be included?
3. **Pre-tool-use hook**: The old branch had a separate PreToolUse hook to send tool_use_id before execution. The PostToolUse hook already receives tool_use_id from Claude Code. Do we need PreToolUse, or is PostToolUse sufficient?