Workflow
The mandatory 7-step order Claude must follow every session. Hooks enforce this — skipping steps will cause tool denials.
Scroll inside the diagram to zoom · drag to pan · built with Excalidraw
| # | Step | Tool | When |
|---|---|---|---|
| 1 | Recall | c3_memory(action='recall') |
Before any multi-step or context-dependent task |
| 2 | Search | c3_search(action='code|files|semantic') |
Before ANY file discovery or content search |
| 3 | Map + Read | c3_compress(mode='map') → c3_read(symbols=…) |
Before reading any file content |
| 4 | Impact | c3_impact(target='symbol') |
Before editing shared symbols — check blast radius |
| 5 | Edit | c3_edit(file, old, new, summary) |
All file modifications |
| 6 | Filter | c3_filter(text=…) |
Terminal output >10 lines or log files |
| 7 | Validate | c3_validate(file_path) |
After every edit; type check auto-runs if pyright/tsc installed |
| 8 | Log | c3_session(action='log') |
After decisions; snapshot before /clear |
| + | Bitbucket | c3_bitbucket(action='list_prs') |
v2.30.0 — see/act on PRs, branches, builds, repo admin on enterprise Bitbucket Data Center. Full guide → |
| + | Cross-project | c3_project(action='list') |
v2.31.0 — discover and operate on OTHER c3-installed projects; reads run free, writes need allow_write=true. Tool card → |
The first thing Claude should do at the start of any non-trivial task. This loads relevant facts from the persistent memory store — architecture decisions, conventions, ongoing work, gotchas discovered in prior sessions.
c3_memory(action='recall', query='authentication system refactor')
When to recall
- Start of any multi-step task
- When the task touches a system you've worked on before
- When you suspect there are architecture decisions or gotchas to be aware of
When you can skip
- Trivial one-off tasks (rename a variable, fix a typo)
- Brand new projects with no prior sessions
| Action | Use case |
|---|---|
| code | TF-IDF code search — find functions, classes, patterns by content |
| files | File discovery — find files by name, extension, path pattern |
| semantic | Embedding-based similarity search — find conceptually related code |
| exact | Regex-based exact search — when you know the literal string |
# Never start with native tools
Grep(pattern='AuthMiddleware')
Glob(pattern='**/*.py')
c3_search(query='AuthMiddleware', action='code')
c3_search(query='*.py auth', action='files')
prefetch=True
Pass prefetch=True to auto-compress the top result files in parallel, saving a round-trip:
c3_search(query='session manager', action='code', prefetch=True)
Reading a whole file wastes tokens. The correct pattern is: compress to get the map, then read only the specific symbols or lines you need.
# Reading entire files
Read(file_path='services/session_manager.py')
# Map → targeted read
c3_compress(file_path='services/session_manager.py', mode='map')
c3_read(file_path='services/session_manager.py', symbols=['SessionManager.save'])
Compress modes
| Mode | Output | Best for |
|---|---|---|
| map | Line-range map of all symbols (functions, classes, constants) | Understanding file structure before reading |
| dense_map | Same as map but with docstrings included | When you need a bit more context per symbol |
| smart | Adaptive compression — keeps important sections | General-purpose read when map is insufficient |
| diff | Show what changed recently (git diff aware) | Reviewing recent changes |
| bug_scan | Highlight suspicious patterns | Quick bug-hunting pass |
Batch compress
# Compress multiple files in one call
c3_compress(file_path='services/memory.py,services/agents.py', mode='map')
Before renaming, removing, or changing the signature of any function or class used across files, run c3_impact to find every call site. A HIGH risk result means all those files need updating in the same edit pass — skipping this step is how silent breakages happen.
# Check blast radius before renaming a shared function
c3_impact(target='handle_memory', file_path='cli/tools/memory.py')
# Check what's affected AND has uncommitted changes
c3_impact(target='MemoryStore', mode='unstaged')
When to skip
Skip c3_impact when editing purely local symbols (private helpers, inner functions, one-off scripts). Use it for anything in a shared service, public API, or imported across files.
c3_edit does read + patch + write + edit ledger log in one step. It also validates the old_string match before writing. If the literal match fails but the strings differ only by unicode lookalikes (curly quotes, em/en-dashes, NBSP), c3_edit retries with a 1:1 normalized match and tags the response [unicode-normalized].
c3_edit(
file_path='services/auth.py',
old_string='return token.expiry > now',
new_string='return token.expiry > now + timedelta(seconds=CLOCK_SKEW)',
summary='Add clock skew buffer to token expiry check'
)
Batching edits to the same file
Use the edits=[] parameter to apply multiple patches to one file in one call:
c3_edit(
file_path='src/config.py',
edits=[
{"old_string": "DEBUG = True", "new_string": "DEBUG = False"},
{"old_string": "HOST = 'localhost'", "new_string": "HOST = '0.0.0.0'"}
],
summary='Production config hardening'
)
Parallel edits across files
# Call c3_edit for multiple files in parallel (same message, different files)
c3_edit(file_path='src/a.py', old_string='...', new_string='...', summary='...')
c3_edit(file_path='src/b.py', old_string='...', new_string='...', summary='...')
Any terminal output longer than ~10 lines should be passed through c3_filter to extract only the relevant signal before including it in context.
# Filter raw terminal output
c3_filter(text="<long test output here>")
# Filter a log file
c3_filter(file_path=".c3/sessions/session_001.json", pattern="error|warning")
Always call c3_validate after edits. Never report "done" without validation. A syntax error introduced silently is worse than no change at all. If pyright (Python) or tsc (TypeScript) is on your PATH, C3 also runs a deep type check automatically and surfaces type errors as advisory warnings alongside the PASS result.
# Single file
c3_validate(file_path='services/auth.py')
# Batch — comma-separated (runs in parallel internally)
c3_validate(file_path='services/auth.py,services/session.py,cli/c3.py')
Supported languages
Log a decision
c3_session(action='log', data='Chose JWT over session cookies — easier horizontal scaling')
Snapshot before /clear
Always snapshot before running /clear. This saves the full session state so the next session can restore it.
c3_session(action='snapshot')
# Then in Claude Code: /clear
Auto-snapshot on session end
C3 automatically captures a snapshot when a session ends — including Ctrl+C, natural stop, and max-turn exits. This is handled by a Stop hook (hook_auto_snapshot.py) that fires after Claude's last response.
POST /api/auto-snapshot which captures a full snapshot with live session state (decisions, files touched, memory facts, budget). If the server isn't running, it falls back to a lightweight file-based snapshot from persisted session data on disk.
Installation: Stop hooks are registered automatically by c3 install-mcp. For existing projects, re-run c3 install-mcp to add them. No manual configuration needed.
| Event | Auto-snapshot? | Notes |
|---|---|---|
| Natural session end | Yes | Stop hook fires reliably |
| Ctrl+C (graceful) | Yes | Stop hook fires before exit |
| Ctrl+C (hard kill) | Partial | May not fire if process killed instantly |
| /clear | Indirect | Session ends first, triggering the hook |
Manual snapshots are still recommended before /clear for maximum reliability, but the auto-snapshot serves as a safety net.
Restore in new session
c3_session(action='restore')
Compact (one-step restart)
# Snapshot + summary + restore instruction in one step
c3_session(action='compact')
These will cause hook denials or waste significant tokens:
/clear captures richer context (task description, working files). Don't rely solely on auto-snapshot.In plan mode, all c3_* read tools work normally: c3_search, c3_read, c3_compress, c3_filter, c3_validate, c3_status, c3_memory(recall/query). Skip edit and delegate steps in plan mode.
Option A — Compact (one step)
c3_session(action='compact')
# → Claude gives you a restore command to paste after /clear
# → Run /clear
# → Paste the restore command
Option B — Manual (two steps)
# Step 1: Before /clear
c3_session(action='snapshot')
# Step 2: After /clear, in new session
c3_session(action='restore')
What's preserved across restarts
- Memory facts (always persistent — not affected by /clear)
- Session decisions and context notes (from snapshot)
- Edit ledger (always persistent)
- Code index (always persistent)
What's lost on /clear
- Conversation history (by design)
- In-flight reasoning (must be re-derived)
- Unsnapshot session state
Installed by c3 install-mcp into ~/.claude/commands/terse.md. Available in every Claude Code project after C3 setup. Reduces output token usage by stripping prose verbosity while leaving all technical content (code, paths, commands, URLs) unchanged.
c3_compress, c3_filter). Those shrink what Claude reads; terse mode shrinks what Claude writes.
Intensity levels
| Level | Effect | Example output |
|---|---|---|
/terse lite |
Remove filler, keep grammar intact | "Auth middleware handles token expiry at auth.py:42." |
/terse (full) |
Drop articles, use fragments, cut transitions | "Auth middleware: token expiry. See auth.py:42." |
/terse ultra |
Telegraphic, maximum abbreviation | "Token expiry → auth.py:42" |
What gets suppressed
- Preamble: "Sure, I'll...", "I've completed..."
- Hedging: "I think", "it seems", "you might want to"
- Trailing summaries that restate the diff
- Filler conjunctions and transitional phrases
What stays exact
- All code blocks, inline code, file paths, commands, URLs
- Error messages and stack traces
- Variable names, function names, type signatures
Exceptions — do not compress these
Terse mode applies to conversational prose only. The following must remain complete and precise regardless of terse level:
- Memory saves (
c3_memory add/update) — facts must be self-contained and fully worded; abbreviated facts are unsearchable - Session logs (
c3_session log) — decisions need full reasoning to be useful in future sessions - CLAUDE.md / instructions files — rules must be unambiguous; never abbreviate directives
- Planning and architecture responses — user reviews for correctness; include all steps and trade-offs
- Error diagnosis — include full error text, file paths, line numbers, root cause
- Tool call arguments —
old_string,new_string,fact,summarymust be exact; never truncate
Deactivate
Say "normal mode" or start a new session.
Terse Advisor — automatic nudge
C3 installs a Stop hook (hook_terse_advisor.py) that fires after each response turn. When a verbose response is detected and /terse is not already active, it prints a one-time nudge per session:
────────────────────────────────────────────────────
[C3] Verbose response (~950 chars). /terse saves ~50% output tokens.
Type /terse to activate.
Silence: c3 terse dismiss | Snooze 24h: c3 terse later
────────────────────────────────────────────────────
The advisor checks the transcript for recent /terse activations and skips if terse mode is already in use. Nudge state is stored in ~/.c3/terse_advisor.json.
| Command | Effect |
|---|---|
c3 terse dismiss | Silence the advisor permanently |
c3 terse later | Snooze nudges for 24 hours |
c3 terse reset | Clear all advisor state |
c3 terse status | Show current advisor state |
Native tools (Read, Grep, Glob, Edit) are allowed only as fallback when a c3_* tool failed or returned insufficient scope:
Example: "c3_search returned no results for 'XYZ' — falling back to Grep for exact match."
| Situation | Permitted fallback |
|---|---|
| c3_search returned empty results | Grep with exact pattern |
| c3_compress failed (file too short / binary) | Read with limited lines |
| c3_edit failed (old_string not found after multiple retries) | Read to confirm exact content, then retry c3_edit |
| c3_validate doesn't support the file type | Run native syntax check via Bash |