cass — Cross Agent Session Search
Premise:
cassindexes your local AI coding-agent session files (~/.claude/projects,~/.codex/sessions, etc.) into SQLite + Tantivy. The CLI is robot-friendly: every command has a--json/--robotmode and a stable schema. Use the CLI; do not query the SQLite DB directly — the schema isn't a stable contract and you'll miss ranking, snippet generation, and the ergonomics that already exist.
When to reach for this skill (active-project use)
Agents should pull cass into the current task, not just retrospectively. The five high-value moments:
- Session prime — picking up a project after a gap (a day, a week, a context-compact). Run §Recipe #0 before doing anything else.
- "Have I solved this before?" — symptom matches something familiar; spend 10 seconds checking before re-deriving.
- Cross-project transfer — implementing X for the first time in this repo; you've done it elsewhere. Find the prior work and lift the pattern.
- Onboarding/handoff — explaining what was tried, what failed, what the trade-offs were. Sessions remember rationale that commits don't.
- Recurrence detection — "is this the third time I've hit this?" → file a real fix instead of patching again.
In all five, the answer to "should I search?" is yes, and the cost is one short command. The skill makes that command cheap and habitual.
TL;DR — fastest correct path
# 1. Preflight (1 line, <100ms)
cass health --json | jq -r '.recommended_action // "ready"'
# 2. Search — token-cheap, agent-friendly defaults
cass search "your query" --robot --limit 10 --fields summary --max-content-length 200
# 3. Drill in on a hit
cass view <source_path> -n <line> # 5 lines context
cass expand <source_path> --line <line> -C 5 # ±5 messages around the hit
If you only do those three, you'll be right 90% of the time.
Decision Tree
What does the user want?
│
├─ "Recall a past session / what did I do"
│ → Search recipe (§Recipes #1)
│
├─ "List recent sessions in this project"
│ → cass sessions --current --json (or --workspace <path> --limit N)
│
├─ "Overview / counts / breakdown"
│ → Aggregate recipe (§Recipes #2) — `--aggregate agent,workspace,date`
│
├─ "Show activity over time"
│ → cass timeline --since '-7d' --json
│
├─ "cass is broken / no results / index rebuilding"
│ → Health & repair recipe (§Troubleshooting)
│
└─ "Resume that conversation in <agent>"
→ cass resume <session-path> (returns the harness command)
Health Preflight — DO THIS FIRST
The index can be rebuilding, stale, missing, or healthy. Searching a broken index returns 0 results with a stderr warning that's easy to miss. Always check first:
cass health --json
# {"status":"rebuilding"|"healthy"|"unhealthy","healthy":bool,"recommended_action":"...",...}
Authoritative fields (per cass robot-docs guide):
recommended_action— if non-null, show it to the user and follow it before searching.status—healthy/rebuilding/unhealthy.state.index.rebuilding— true while a rebuild is in progress (search will be lexical-only or empty).
When status == "rebuilding":
- Don't bypass to SQLite. Don't loop and retry hard.
- Add
--mode lexicalto your search — it often still works because lexical assets are written incrementally. - Or wait:
cass status --json | jq '.rebuild.processed_conversations, .rebuild.total_conversations'(run twice to estimate ETA).
When status == "unhealthy" AND recommended_action mentions --fix:
cass doctor --fix # rebuilds derived data only; never deletes user sessions
Real Command Surface (verified against cass --version)
Run cass capabilities --json once to see what your local binary supports — feature names below match the features array.
Search & navigation
| Command | Use it for |
|---|---|
cass search "<q>" --robot |
Default: search everything, JSON output |
cass search "<q>" --robot --aggregate agent |
Counts by field — 99% token reduction vs full results |
cass search "<q>" --robot --fields summary |
path,line_number,agent,title,score only |
cass search "<q>" --robot --max-content-length 200 |
Cap each snippet (UTF-8 safe; adds _truncated indicator) |
cass search "<q>" --robot --robot-meta |
Adds elapsed_ms, mode used, fallback reason — use when results are surprising |
cass search "<q>" --robot --explain |
Show parsed query + cost estimate |
cass search "<q>" --robot --dry-run |
Validate without executing |
cass search "<q>" --robot --mode lexical |
Force BM25 (works while semantic/index is rebuilding) |
cass sessions --current --json |
Best match for current cwd |
cass sessions --workspace <path> --json --limit 20 |
Recent sessions for a project |
cass view <source_path> -n <line> [-C N] |
Read N lines around a search hit |
cass expand <source_path> --line <line> [-C N] |
Read N messages around a search hit (better for transcripts) |
cass timeline --since '-7d' --json |
Activity over a time range |
cass resume <source_path> |
Print the harness command to resume that session |
cass export <source_path> --format markdown |
Convert a session to markdown |
Filters that work on search and timeline
| Flag | Notes |
|---|---|
--agent <slug> |
repeatable (e.g. --agent codex --agent claude_code) |
--workspace <path> |
repeatable |
| `--source local | remote |
--today / --yesterday / --week |
shortcuts |
--days N |
last N days |
--since <when> / --until <when> |
ISO date YYYY-MM-DD, keyword (today/yesterday/now), or relative '-7d'/'-24h'/'-30m'/'-1w' (quote it) |
Output controls (search)
| Flag | Effect |
|---|---|
--limit N |
Default 0 = no cap (auto-clamped to RAM-proportional ceiling) — set this for token control |
--offset N / --cursor <c> |
Pagination |
--max-tokens N |
Soft token budget (≈ 4 chars / token) |
| `--robot-format json | jsonl |
| `--display table | lines |
--highlight |
**bold** markers around matched terms |
--fields <list> or minimal/summary preset |
Token control |
--request-id <id> |
Echoed in _meta for log correlation |
Health & maintenance
| Command | Use it for |
|---|---|
cass health --json |
<50ms readiness probe (preflight) |
cass status --json |
Full state: rebuild progress, semantic readiness, DB counts |
cass diag --json |
Versions, paths, platform |
cass doctor --json |
Diagnostic checks; safe by default |
cass doctor --fix |
Rebuild derived data (preserves source sessions) |
cass doctor --force-rebuild |
Force lexical rebuild |
cass index / cass index --full / cass index --watch |
Manual / full / live reindex |
cass stats --json |
Conversation/message counts |
cass sources agents list --json |
List indexing exclusions |
Robot docs (machine-readable instructions)
cass robot-docs <topic>
# topics: commands env paths schemas guide exit-codes examples contracts wrap sources analytics
When in doubt, cass robot-docs guide or cass robot-docs examples is the fastest unblock.
Recipes — paste & adapt
0. Session prime (run at the start of an active-project task)
When the user kicks off work in a project — especially after a gap — these three calls give you ~80% of the prior context for the cost of ~500 tokens:
# (a) Most recent session in this cwd — picks up where you left off
cass sessions --current --json --limit 1 | jq '.sessions[0] | {path, agent, modified, title, message_count}'
# (b) What's been touched in this project lately (counts, no content)
cass search "*" --robot --workspace "$(pwd)" --aggregate date --week | jq '.aggregations'
# (c) Pull recent activity around the topic you're about to work on
cass search "<topic from user's prompt>" --robot --workspace "$(pwd)" --week \
--limit 5 --fields summary --max-content-length 200 \
| jq '.hits[] | {agent, source_path, line_number, snippet: .snippet // .content[:200]}'
Then drill into the most relevant hit with cass view / cass expand (recipe #1). Don't summarize the prime back to the user — they know their own history; just use it to make better suggestions.
1. Recall a past session
cass search "auth bug retry logic" --robot --limit 10 --fields summary --max-content-length 200 \
| jq '.hits[] | {score, agent, source_path, line_number, snippet: .snippet // .content}'
Then drill into the top hit:
cass view "<source_path>" -n <line_number> -C 10
# or for transcripts (multi-message context):
cass expand "<source_path>" --line <line_number> -C 5
2. Overview without spending tokens (the aggregate trick)
# How many sessions touched X, broken down by project?
cass search "stripe webhook" --robot --aggregate workspace
# Multi-field
cass search "*" --robot --aggregate agent,date --week
Use this before a wide search so you know whether to scope or pivot.
3. Recent sessions in this repo
cass sessions --current --json --limit 20
# OR explicit:
cass sessions --workspace "$(pwd)" --json --limit 20
4. Time-window search
cass search "regression" --robot --since '-14d' --limit 10 --fields summary
cass search "fixed" --robot --today --agent codex
Quote relative offsets ('-7d') — without quotes the shell will mistake the dash for a flag in some pipelines.
5. Chained search (intersection)
# Sessions that mention "playwright", then within those, find "flaky"
cass search "playwright" --robot --robot-format sessions \
| cass search "flaky" --robot --sessions-from -
6. Two-phase exploration (cheap → focused)
# Phase 1 — counts only (tiny output)
cass search "deploy" --robot --aggregate agent,workspace --week
# Phase 2 — narrow + read
cass search "deploy" --robot --workspace /data/projects/scry --limit 5 --fields summary
7. Force lexical when semantic is unavailable
cass search "<q>" --robot --mode lexical --robot-meta
# Inspect _meta.search_mode and _meta.fallback_reason
8. Resume a prior session in another agent
sp=$(cass sessions --current --json --limit 1 | jq -r '.sessions[0].path')
cass resume "$sp" # prints the resume command for the source's native harness
Note on JSON shape:
cass sessions --jsonreturns{ "sessions": [ { "path", "workspace", "agent", "title", "modified", "size_bytes", "message_count", "human_turns", ... } ] }. The session file path is.path(not.source_path— that's whatcass searchuses for hits).
Anti-Patterns — DO NOT do these
These came from real session logs. The skill exists to keep them from happening again.
A1. Bypassing cass to query SQLite directly
Symptom: running sqlite3 ~/.local/share/coding-agent-search/agent_search.db "SELECT ..."
Why it's wrong: schema isn't a stable contract; you lose ranking, snippets, robot envelope, mode-aware fallback, and lose ability to roll forward when cass changes.
Correct: cass search with appropriate filters. If you genuinely need raw counts, use cass stats --json or cass search '*' --aggregate <field>.
A2. cass search robot "<query>"
Symptom: Could not parse arguments (exit 2).
Cause: robot is not a subcommand. The flag is --robot (alias of --json).
Correct: cass search "<query>" --robot.
A3. Ambiguous time arguments
Correct: prefer --days 7 (least ambiguous), --week, ISO --since 2026-04-01, or quoted --since '-7d'. Don't rely on bare --since=7d — it works on current cass but is brittle across wrappers/versions.
A4. Forgetting --limit and --max-content-length
Symptom: 50k-token search response that blows context. The default --limit 0 means "no limit" — clamped only by RAM.
Correct: always set --limit 10 (or smaller) and --max-content-length 200 for agent use.
A5. Reading 0 results as "nothing exists"
Symptom: "I checked cass and there are no past sessions about X."
Cause: index is rebuilding, semantic embedder is missing, or query too narrow. The stderr warning is easy to miss.
Correct: rerun with --robot-meta and inspect _meta.search_mode / _meta.fallback_reason / _meta.fallback_tier. If rebuilding, retry with --mode lexical or wait.
A6. Searching when the index is broken
Symptom: 0 hits, weird latencies, repeated stderr warnings about missing index.
Correct: cass health --json first. If recommended_action mentions cass doctor --fix or cass index --full, show it to the user and run it (with permission).
A7. Reading entire session JSONL files for context
Symptom: Read tool on a 10MB session file.
Correct: cass view <path> -n <line> -C 10 (file lines) or cass expand <path> --line <line> -C 5 (whole messages).
A8. Ignoring the --aggregate superpower
Symptom: Asking "how many times did agents hit X?" by paginating full hits.
Correct: cass search "X" --robot --aggregate agent,workspace,date. This is server-side and tiny.
A9. Calling cass tui from an agent
Symptom: session hangs.
Cause: cass tui is interactive (Bubble-Tea-style); non-TTY agents can't drive it.
Correct: never. Use cass search / cass sessions instead.
A10. Inventing flags / subcommands
Don't exist: cass robot search ..., cass --query ..., anything with a TUI in agent mode.
Verify what does exist: cass capabilities --json and cass robot-docs commands.
Troubleshooting
"Tantivy search index not found" warning on stderr
Index hasn't been built or was deleted. Run:
cass index --full
# Watch progress in another shell:
cass status --json | jq '.rebuild'
cass search returns 0 hits but you know there's data
cass health --json— index status?cass stats --json— conversations indexed > 0?cass search "<q>" --robot --robot-meta— read_meta.fallback_reason- Try
--mode lexicaland a broader query (e.g. shorter terms, no quotes) - Try
cass search "*" --aggregate workspaceto confirm data exists
Exit codes (per cass robot-docs exit-codes)
| Code | Meaning |
|---|---|
| 0 | OK |
| 1 | health-failed |
| 2 | usage error (you passed bad args) |
| 3 | missing index/db |
| 5 | data-corrupt |
| 7 | lock/busy (try again) |
| 15 | semantic/embedder unavailable (retry with --mode lexical) |
For codes ≥ 10, branch on err.kind (kebab-case string in JSON envelope), not the numeric code.
References
| File | When to open |
|---|---|
| RECIPES.md | More copy-paste recipes (chained, scoped, time-window, multi-source) |
| PITFALLS.md | Detailed pitfalls catalog with diagnose/fix |
| SELF-TEST.md | Failure-case tests tied to CASS session logs |
If you're ever stuck, run cass robot-docs examples and cass robot-docs guide — they're authoritative and current.
Provenance of this skill
Be honest with yourself about where each rule came from:
- Grounded in observed agent failures (CASS sessions 437/473/474/665/679/1270): A1 (sqlite bypass), A2 (
cass search robot "<q>"), A6/P6 (broken-index searches), A9/P7 (cass tuihangs), P10 (cass healthvsstatusconfusion). The historical CASS record is mostly agents fixing cass itself, not agents using cass; deep tool-debugging guidance has been intentionally left out — this skill is for using cass, not repairing it. - Grounded in this skill's own author's recent usage (the immediately prior CASS rewrite session): A1 (sqlite bypass — I did this), A4 (no
--limit/--max-content-length— I did this), A8 (skipping--aggregate— I did this), A7 (reading whole JSONL — I did this), the §"When to reach for this skill" framing. - Extrapolated from the binary +
cass robot-docs: the recipe specifics, JSON shapes, exit-code mappings, time-window semantics. Self-test verifies these against the live binary.
If you find a usage failure mode the skill doesn't catch, treat that as a contribution back, not a failure of the skill — add it to PITFALLS.md with a session ID or a reproducer, then add a check to scripts/self-test.sh.