# v1.12 Update: Session Checkpoint Persistence & Legacy Tool Removal
Release Date: 2026-01-31
---
## Background
During AVITO project, `/code` session exhausted context during READY phase (Step 13).
CLI termination → MCP server process termination → `SessionState` lost.
Issues occurred in continuation session:
1. **Verification Skip**: POST_IMPL_VERIFY sent `passed: true` without actual work (LLM lost project context)
2. **Old Tool Calls**: LLM called `record_outcome` which doesn't exist in v1.11 flow (tools that should have been removed remained)
### Root Cause
```
LLM Conversation ← Subject to compaction
↕ MCP Protocol
MCP Server ← In-memory (lost on process termination)
```
v1.11's "compaction resilience" is only effective **within the same CLI session**.
CLI termination → new CLI startup also restarts MCP server, losing `SessionState`.
| Scenario | MCP Process | SessionState | v1.11 Resilience |
|----------|------------|--------------|------------------|
| Auto-compaction (same session) | Alive | Retained | **Effective** |
| `/clear` (same CLI) | Alive | Retained | **Effective** |
| CLI termination → `--continue` | Restarted | **Lost** | Ineffective |
| Context exhaustion → new conversation | Restarted | **Lost** | Ineffective |
---
## Design Principles
1. **Checkpoint Persistence**: Save session state to disk on each `submit_phase`. Recovery via `get_session_status` possible after CLI restart.
2. **Tool Context Reduction**: Remove 18 unused legacy tools. Compress LLM tool list from 39 → 21.
3. **Backward Compatibility**: Maintain `SessionState` methods (`submit_exploration()`, etc.) for internal use. Only remove MCP tool registration.
4. **Explicit Resume**: Start checkpoint recovery with `/code --resume`. Ensures both code.md + CLAUDE.md context and server state.
5. **Response Defense**: 256KB limit on all tool responses. Prevent instant context death in single turn.
---
## Feature ①: Session Checkpoint Persistence
### Overview
```
submit_phase success
→ Serialize with SessionState.to_dict()
→ Save to .code-intel/sessions/{session_id}.json
CLI restart → get_session_status
→ Detect checkpoint file
→ Restore with SessionState.from_dict()
→ Return current phase + instruction + expected_payload to LLM
```
### Save Location
```
.code-intel/sessions/{session_id}.json
```
Added to `.gitignore`. Auto-deleted on MERGE (SESSION_COMPLETE) success.
### Constraints
Checkpoint persistence restores **server-side state** (phase, task progress, exploration results, etc.).
However, **project-specific work procedures** needed by LLM (build methods, verification methods, etc.) are provided from `/code` skill and CLAUDE.md.
v1.12 ensures both with `/code --resume`:
```
New session → /code --resume
→ Load code.md (secure LLM-side context)
→ get_session_status → Restore checkpoint (secure server-side state)
→ Resume work following instruction + expected_payload
```
> **Note**: If calling `get_session_status` directly without `/code --resume`, server state is restored but LLM lacks project context like verification procedures, potentially causing "verification skip" like AVITO again.
### SessionState.to_dict() Completion
Add missing fields to current `to_dict()`:
| Category | Added Fields |
|----------|--------------|
| Identity | `repo_path` |
| Phase state | `ready_substep`, `gate_level` |
| v1.11 Tasks | `tasks` (TaskModel list) |
| v1.11 Flags | `no_verify`, `no_quality`, `fast_mode`, `quick_mode`, `no_doc`, `no_intervention`, `only_explore`, `only_verify` |
| v1.10 | `phase_assessments` |
| Semantic | `map_results`, `forest_results`, `map_hit` |
| v1.5 Quality | `quality_revert_count`, `quality_review_enabled`, `quality_review_max_revert`, `quality_review_completed` |
| v1.8 Commit | `commit_prepared`, `prepared_commit_message`, `prepared_kept_files`, `prepared_discarded_files` |
| v1.8 | `skip_implementation` |
| v1.7 Cache | `definitions_cache` (tuple key → JSON array conversion) |
| Metadata | `checkpoint_version`, `checkpoint_at` |
### SessionState.from_dict() New Addition
Restore from checkpoint. Prepare helper functions for each nested dataclass:
| Helper Function | Restore Target |
|-----------------|----------------|
| `_restore_query_frame(data)` | QueryFrame + MappedSymbol + SlotSource + SlotEvidence |
| `_restore_exploration(data)` | ExplorationResult |
| `_restore_semantic(data)` | SemanticResult + Hypothesis |
| `_restore_verification(data)` | VerificationResult + VerifiedHypothesis + VerificationEvidence |
| `_restore_impact_analysis(data)` | ImpactAnalysisResult + VerifiedFile |
| `_restore_pre_commit_review(data)` | PreCommitReviewResult + ReviewedFile |
Missing fields filled with defaults (partial checkpoint support).
### SessionManager Checkpoint Operations
```python
class SessionManager:
def save_checkpoint(self, session_id: str, base_path: str) -> bool:
"""Save session state to .code-intel/sessions/ (atomic write)"""
def load_checkpoint(self, session_id: str, base_path: str) -> SessionState | None:
"""Restore session state from checkpoint"""
def list_checkpoints(self, base_path: str) -> list[dict]:
"""List available checkpoints"""
@staticmethod
def delete_checkpoints(base_path: str) -> int:
"""Delete all checkpoints (for --clean)"""
```
### Server Integration (code_intel_server.py)
| Timing | Action |
|--------|--------|
| After `submit_phase` success | `save_checkpoint()` |
| After `start_session` complete | `save_checkpoint()` + return `recovery_available` if existing checkpoint exists |
| `get_session_status` (no active session) | Find checkpoint and auto-restore, `recovered_from_checkpoint: true` |
| MERGE (SESSION_COMPLETE) | Delete checkpoint file |
| `cleanup_stale_branches` | Also execute `delete_checkpoints()` |
### definitions_cache Serialization
Tuple key `(str, str, str | None, bool)` not JSON-compatible. Convert to JSON array:
```python
# Serialize
def _serialize_cache_key(key: tuple) -> str:
return json.dumps([key[0], key[1], key[2], key[3]])
# Deserialize
def _deserialize_cache_key(key_str: str) -> tuple | None:
parts = json.loads(key_str)
return (parts[0], parts[1], parts[2], parts[3])
```
---
## Feature ②: Legacy Tool Removal
### Overview
v1.11 unified to `submit_phase`, but old tools remained in MCP server.
LLM discovered via ToolSearch and called tools not in v1.11 flow.
### Removal Targets (18 Tools)
**MCP tool registrations corresponding to v1.11_ja.md deprecated APIs (14):**
| # | Tool Name | Replacement |
|---|-----------|-------------|
| 1 | `check_phase_necessity` | submit_phase (Q1/Q2/Q3) |
| 2 | `set_query_frame` | submit_phase (QUERY_FRAME) |
| 3 | `begin_phase_gate` | submit_phase (BRANCH_INTERVENTION) |
| 4 | `submit_for_review` | submit_phase (READY completion) |
| 5 | `submit_exploration` | submit_phase (EXPLORATION) |
| 6 | `submit_semantic` | submit_phase (SEMANTIC) |
| 7 | `submit_verification` | submit_phase (VERIFICATION) |
| 8 | `submit_impact_analysis` | submit_phase (IMPACT_ANALYSIS) |
| 9 | `submit_quality_review` | submit_phase (QUALITY_REVIEW) |
| 10 | `finalize_changes` | submit_phase (PRE_COMMIT) |
| 11 | `merge_to_base` | submit_phase (MERGE) |
| 12 | `record_verification_failure` | submit_phase (POST_IMPL_VERIFY: passed=false) |
| 13 | `record_intervention_used` | submit_phase (VERIFY_INTERVENTION) |
| 14 | `get_intervention_status` | Server internal management |
Note: `complete_task` in v1.11_ja.md deprecated list is not registered as MCP tool (method only in `SessionState`). No removal needed.
**Not in v1.11 Tool Overview (4):**
| # | Tool Name | Reason |
|---|-----------|--------|
| 15 | `record_outcome` | Outside workflow. LLM miscalled in AVITO |
| 16 | `get_outcome_stats` | Accompanying tool for record_outcome |
| 17 | `validate_symbol_relevance` | Not in v1.11 flow |
| 18 | `confirm_symbol_relevance` | Not in v1.11 flow |
### Retained Tools (21)
| # | Tool Name | Purpose |
|---|-----------|---------|
| 1 | `start_session` | Session start |
| 2 | `submit_phase` | Unified exit for all phases |
| 3 | `get_session_status` | State recovery (+ v1.12 checkpoint restore) |
| 4 | `search_text` | Text search |
| 5 | `search_files` | File search |
| 6 | `find_definitions` | Symbol definitions |
| 7 | `find_references` | Symbol references |
| 8 | `analyze_structure` | Code structure analysis |
| 9 | `get_symbols` | Symbol list |
| 10 | `get_function_at_line` | Get function at line |
| 11 | `query` | Intelligent search |
| 12 | `fetch_chunk_detail` | ChromaDB chunk retrieval |
| 13 | `semantic_search` | Vector search |
| 14 | `check_write_target` | Write target verification |
| 15 | `add_explored_files` | Add explored files |
| 16 | `revert_to_exploration` | Revert to exploration phase |
| 17 | `review_changes` | Change review |
| 18 | `analyze_impact` | Impact analysis |
| 19 | `cleanup_stale_branches` | Branch + session deletion (v1.12 extended) |
| 20 | `sync_index` | ChromaDB sync |
| 21 | `update_context` | Context update |
### Removal Procedure
1. Remove 18 `Tool(name=...)` entries from `list_tools()`
2. Remove corresponding `elif name == "..."` handler blocks from `call_tool()`
3. **Do not remove** `SessionState` methods (`submit_exploration()`, etc.) (used internally by v1.11 `_submit_*` handlers)
4. Clean up unnecessary imports
---
## Feature ③: `/code --resume` Option
### Overview
Flag for explicitly resuming session from checkpoint.
`/code --resume` performs both code.md + CLAUDE.md context loading and server state restoration.
### Flag Definition
| Flag | Short | Effect |
|------|-------|--------|
| `--resume` | `-r` | Resume session from checkpoint (skip Steps 1-2) |
> **Short option reassignment**: `-r` was assigned to `--rebuild` in v1.11. Reassigned to `--resume` in v1.12. `--rebuild` short option abolished.
### Flow
```
/code --resume
→ Step -1: Flag Check — --resume detected
→ Step 1 (Intent Classification) — Skip
→ Step 2: Call get_session_status directly instead of start_session
→ Server: Detect checkpoint → Restore → recovered_from_checkpoint: true
→ LLM: Resume work following instruction + expected_payload
```
When checkpoint doesn't exist:
```
get_session_status → "no active session, no checkpoint found"
→ LLM notifies user: "No session available for recovery"
→ Processing ends
```
### Flag Combination Constraints
`--resume` cannot be combined with other flags. Flags saved in checkpoint (`no_verify`, `fast_mode`, etc.) are restored.
```
/code --resume ← OK
/code --resume --no-verify ← Error: --resume must be used alone
```
### Checkpoint Detection During Normal Execution
When old checkpoint exists during `/code` (without `--resume`), present choice to user:
```
/code fix the bug
→ start_session → recovery_available: true (old checkpoint detected)
→ LLM: Present choice to user via AskUserQuestion
"Previous session found (READY Step 13: 'CSS fix task')"
→ [Restore] → get_session_status → Restore checkpoint → Resume from interruption point
→ [Discard and start new] → Continue normal flow. Old checkpoint auto-deleted on next save_checkpoint
```
Checkpoint info included in `start_session` response:
```json
{
"recovery_available": true,
"checkpoint_info": {
"session_id": "...",
"phase": "READY",
"step": 13,
"query": "CSS fix task",
"checkpoint_at": "2026-01-31T12:34:56"
}
}
```
### code.md Changes
**Flag Check table update**:
| Change | Content |
|--------|---------|
| Add | `--resume` / `-r` / Resume from checkpoint (skip Steps 1-2) |
| Change | `--rebuild` short `-r` removed → `--rebuild` / — / Force re-index and exit |
**CRITICAL RULES addition**:
```
10. **--resume is standalone**: --resume cannot be combined with other flags. Flags saved in checkpoint are restored.
```
**recovery_available handling addition**:
When `start_session` returns `recovery_available: true`, have user choose "Restore / Discard and start new" via AskUserQuestion. On restore selection, recover with `get_session_status`.
**Compaction Recovery section update**:
- Same-session compaction recovery: Existing `get_session_status` flow (no change)
- Cross-session recovery after CLI restart: Start with `/code --resume`
---
## Feature ④: Tool Response Size Limit
### Background
In AVITO project, `search_text` with partial match pattern `["<nav", "aria-label", "breadcrumb", "dashboard-menu"]` matched 7,644 items + submatch position info. Response size **120.8MB** instantly killed context in single turn.
Compaction can only process up to previous turn, so defense impossible when current turn's tool response exceeds context.
### Design
Set **256KB** (262,144 bytes) hard limit on all tool responses.
| Setting | Value |
|---------|-------|
| Limit | 256KB (262,144 bytes) |
| ≈ tokens | ~64K |
| Context ratio | ~32% |
### Behavior When Exceeded
```
When response size > 256KB:
→ Truncate result to 256KB
→ Append warning:
"truncated": true,
"total_matches": 7644,
"returned_matches": 342,
"message": "Response exceeded 256KB and was truncated. Please refine your pattern."
```
### Implementation Location
Size check in `code_intel_server.py` `call_tool()` after serializing each handler's return value. Centralize common truncation logic in one place:
```python
MAX_RESPONSE_BYTES = 262_144 # 256KB
def _truncate_response(content: str, max_bytes: int = MAX_RESPONSE_BYTES) -> tuple[str, bool]:
"""Truncate and add warning when response exceeds limit"""
```
Applied uniformly to all tools (not just search-related). No individual tool modifications needed.
---
## Files Changed
| File | Changes | Impact |
|------|---------|--------|
| `tools/session.py` | `to_dict()` completion, `from_dict()` addition, restore helpers, `SessionManager` checkpoint operations | High |
| `code_intel_server.py` | Checkpoint save/restore wiring, 18 tool removal, response size limit | High |
| `.claude/commands/code.md` | `--resume` flag addition, `--rebuild` short abolished, CRITICAL RULES addition | Medium |
| `.gitignore` | `.code-intel/sessions/` addition | Low |
---
## Implementation Order
1. `tools/session.py` — `to_dict()` completion + `from_dict()` + restore helpers + checkpoint operations
2. `code_intel_server.py` — Checkpoint save/restore wiring
3. `code_intel_server.py` — 18 tool registration + handler removal
4. `cleanup_stale_branches` extension + `.gitignore` update
5. `code_intel_server.py` — `_truncate_response()` + size check in `call_tool()`
6. `.claude/commands/code.md` — `--resume` flag addition + `--rebuild` short abolished
7. `tests/test_v1_12_features.py` — Test creation
8. Document finalization
---
## Test Plan
```python
class TestCheckpointSerialization:
"""to_dict/from_dict round-trip tests"""
def test_round_trip_all_fields(self):
"""All fields preserved"""
def test_definitions_cache_tuple_keys(self):
"""Tuple key → JSON → Tuple key"""
def test_phase_enum_round_trip(self):
"""Round-trip for all Phase values"""
def test_partial_checkpoint_defaults(self):
"""Missing fields filled with defaults"""
def test_nested_dataclass_restore(self):
"""Restore QueryFrame, ExplorationResult, etc."""
def test_task_model_round_trip(self):
"""TaskModel serialize/deserialize"""
class TestCheckpointIO:
"""File I/O tests"""
def test_save_and_load(self):
"""save → load → content matches"""
def test_atomic_write(self):
"""Atomic write (tmp → rename)"""
def test_list_checkpoints(self):
"""List checkpoints"""
def test_delete_checkpoints(self):
"""Delete all"""
def test_merge_deletes_checkpoint(self):
"""Checkpoint deleted on MERGE success"""
class TestCheckpointRecovery:
"""Recovery flow tests"""
def test_get_session_status_recovers_from_checkpoint(self):
"""Clear _sessions → get_session_status → auto-restore"""
def test_start_session_shows_recovery_available(self):
"""Return recovery_available + checkpoint_info if existing checkpoint"""
def test_recovered_session_has_correct_phase(self):
"""Restored session is in correct phase"""
class TestLegacyToolRemoval:
"""Legacy tool removal tests"""
def test_tool_count(self):
"""list_tools() returns 21 tools"""
def test_removed_tools_return_error(self):
"""18 removed tools return Unknown tool error"""
def test_submit_phase_still_works(self):
"""Unified tool submit_phase works correctly"""
class TestCleanupExtension:
"""--clean extension tests"""
def test_clean_deletes_session_files(self):
"""cleanup_stale_branches also deletes session files"""
class TestResumeFlag:
"""--resume flag tests"""
def test_resume_skips_start_session(self):
"""--resume doesn't call start_session, restores with get_session_status"""
def test_resume_no_checkpoint_returns_error(self):
"""Error message when no checkpoint exists"""
def test_resume_rejects_other_flags(self):
"""--resume combined with other flags returns error"""
def test_resume_restores_saved_flags(self):
"""Restored session has saved flags"""
class TestRecoveryPrompt:
"""Checkpoint detection during normal execution tests"""
def test_start_session_returns_checkpoint_info(self):
"""Return recovery_available + checkpoint_info when old checkpoint exists"""
def test_discard_deletes_old_checkpoint(self):
"""Old checkpoint deleted on next save_checkpoint after new selection"""
class TestResponseTruncation:
"""Response size limit tests"""
def test_small_response_unchanged(self):
"""Response under 256KB returned unchanged"""
def test_large_response_truncated(self):
"""Response over 256KB is truncated"""
def test_truncation_includes_warning(self):
"""Truncation includes truncated + total_matches + message"""
def test_truncation_applies_to_all_tools(self):
"""Limit applies to tools other than search_text"""
```
---
## Risks
| Risk | Mitigation |
|------|------------|
| Crash during checkpoint write | Atomic write (tmp → rename) |
| Old skill files reference removed tools | Grep all `.claude/commands/*.md` before implementation |
| QueryFrame etc. restoration is complex | Dedicated helper functions + round-trip tests |
| Checkpoint file accumulation | Auto-delete on MERGE success + `--clean` deletes all |
| definitions_cache tuple keys | Convert to JSON array (more robust than pipe delimiter) |
| `-r` short option reassignment | `--rebuild -r` → `--rebuild` (short abolished). Low impact for infrequent command |
| 256KB limit cuts legitimate large results | Warning on truncation + return total_matches, prompt LLM to refine pattern |
---
## Implementation Status
All 8 steps complete. 28 tests all passing.
| Step | Content | Status |
|------|---------|--------|
| 1 | `tools/session.py` — `to_dict()` completion + `from_dict()` + restore helpers + checkpoint operations | ✅ |
| 2 | `code_intel_server.py` — Checkpoint save/restore wiring | ✅ |
| 3 | `code_intel_server.py` — 18 tool removal (39 → 21 tools) | ✅ |
| 4 | `cleanup_stale_branches` extension + `.gitignore` confirmation | ✅ |
| 5 | `code_intel_server.py` — `_truncate_response()` 256KB limit | ✅ |
| 6 | `.claude/commands/code.md` — `--resume` flag + `--rebuild` short abolished | ✅ |
| 7 | `tests/test_v1_12_features.py` — 8 classes 28 tests | ✅ |
| 8 | Document finalization | ✅ |