v2.x

Workflow

The mandatory 7-step order Claude must follow every session. Hooks enforce this — skipping steps will cause tool denials.

📊 Visual Overview

Scroll inside the diagram to zoom · drag to pan · built with Excalidraw

Loading diagram… requires internet connection (CDN)

🗺️ Overview
⚠️
Enforced by hooks Native tools (Read, Grep, Glob, Edit, Write) are blocked by PreToolUse hooks unless a c3_* tool was called first. Violating the workflow order causes immediate tool denials — not warnings.
#StepToolWhen
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 →

1
Recall Memory
Recover context from previous sessions before doing anything
c3_memory

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
💡
Use a specific query matching your task — "recall" pulls the top-k most relevant facts by semantic similarity. A vague query returns less useful results.
2
Search First
Always discover files and code via c3_search — never Grep/Glob directly
c3_search
ActionUse 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
❌ Wrong
# Never start with native tools
Grep(pattern='AuthMiddleware')
Glob(pattern='**/*.py')
✅ Correct
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)
3
Map then Read
Get a structural overview first, then read only what you need
c3_compress + c3_read

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.

❌ Wrong
# Reading entire files
Read(file_path='services/session_manager.py')
✅ Correct
# 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

ModeOutputBest 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')
4
Impact Check
Know the blast radius before editing shared symbols
c3_impact

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.

⚠️
A HIGH risk result (7+ files) means the edit isn't isolated — plan to update all call sites in the same session before reporting done.
5
Edit via C3
Atomic read-patch-write-log — always c3_edit, never native Edit
c3_edit

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='...')
6
Filter Output
Extract signal from noisy terminal output and log files
c3_filter

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")
💡
c3_filter is especially useful after running tests, build commands, or any operation that produces verbose output. It strips noise and returns structured signal.
7
Validate
Syntax + type check every edited file before reporting done
c3_validate

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

Python (.py) JavaScript (.js .mjs) TypeScript (.ts .tsx) HTML (.html) CSS (.css) JSON (.json) TOML (.toml) YAML (.yml .yaml) Bash (.sh)
8
Log & Snapshot
Persist decisions and context so the next session starts informed
c3_session

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.

How it works: The Stop hook checks if the C3 UI server is running. If so, it calls 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.

EventAuto-snapshot?Notes
Natural session endYesStop hook fires reliably
Ctrl+C (graceful)YesStop hook fires before exit
Ctrl+C (hard kill)PartialMay not fire if process killed instantly
/clearIndirectSession 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')

🚫 Anti-patterns

These will cause hook denials or waste significant tokens:

Starting with native file search/read — always use c3_search or c3_compress first, even for "quick" lookups.
Using native Edit when c3_edit is available — c3_edit validates, logs to ledger, and is atomic. Native Edit does none of this.
Reading entire files with native Read — always compress first, then read only the symbols you need.
Skipping c3_validate after edits — you will silently introduce syntax errors that break the next session.
Running /clear without a snapshot — the auto-snapshot Stop hook provides a safety net, but a manual snapshot before /clear captures richer context (task description, working files). Don't rely solely on auto-snapshot.
Dumping long terminal output directly into context — always filter first with c3_filter.
Skipping recall at session start — you'll rediscover decisions and conventions already documented in memory.

📐 Plan Mode
Plan Mode — Read-only tools only

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.


🔄 Session Restart Cycle
Loading diagram…

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

/terse — Terse Output Mode

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.

💡
Complements C3's input-token compression (c3_compress, c3_filter). Those shrink what Claude reads; terse mode shrinks what Claude writes.

Intensity levels

LevelEffectExample 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 argumentsold_string, new_string, fact, summary must 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.

CommandEffect
c3 terse dismissSilence the advisor permanently
c3 terse laterSnooze nudges for 24 hours
c3 terse resetClear all advisor state
c3 terse statusShow current advisor state

⚠️ When Native Tools Are Permitted

Native tools (Read, Grep, Glob, Edit) are allowed only as fallback when a c3_* tool failed or returned insufficient scope:

⚠️
State which c3_* tool was attempted and why it failed
Example: "c3_search returned no results for 'XYZ' — falling back to Grep for exact match."
SituationPermitted 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