cctx-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cctx_cli-0.1.0/.github/workflows/ci.yml +38 -0
- cctx_cli-0.1.0/.github/workflows/publish.yml +48 -0
- cctx_cli-0.1.0/.gitignore +36 -0
- cctx_cli-0.1.0/CLAUDE.md +176 -0
- cctx_cli-0.1.0/DESIGN.md +54 -0
- cctx_cli-0.1.0/PKG-INFO +159 -0
- cctx_cli-0.1.0/PRODUCT.md +109 -0
- cctx_cli-0.1.0/README.md +139 -0
- cctx_cli-0.1.0/cctx/__init__.py +3 -0
- cctx_cli-0.1.0/cctx/cli.py +375 -0
- cctx_cli-0.1.0/cctx/diagnostician/__init__.py +81 -0
- cctx_cli-0.1.0/cctx/diagnostician/aggregate.py +40 -0
- cctx_cli-0.1.0/cctx/diagnostician/inflection.py +19 -0
- cctx_cli-0.1.0/cctx/diagnostician/patterns/__init__.py +1 -0
- cctx_cli-0.1.0/cctx/diagnostician/patterns/retry_loop.py +145 -0
- cctx_cli-0.1.0/cctx/diagnostician/patterns/scope_creep.py +87 -0
- cctx_cli-0.1.0/cctx/diagnostician/patterns/stale_context.py +147 -0
- cctx_cli-0.1.0/cctx/discovery.py +185 -0
- cctx_cli-0.1.0/cctx/exporters/__init__.py +0 -0
- cctx_cli-0.1.0/cctx/exporters/csv.py +64 -0
- cctx_cli-0.1.0/cctx/exporters/jsonl.py +64 -0
- cctx_cli-0.1.0/cctx/harvest.py +173 -0
- cctx_cli-0.1.0/cctx/models.py +269 -0
- cctx_cli-0.1.0/cctx/parsers/__init__.py +1 -0
- cctx_cli-0.1.0/cctx/parsers/claude_code.py +690 -0
- cctx_cli-0.1.0/cctx/pricing.py +18 -0
- cctx_cli-0.1.0/cctx/recommender/__init__.py +0 -0
- cctx_cli-0.1.0/cctx/recommender/claude_md.py +131 -0
- cctx_cli-0.1.0/cctx/recommender/evidence.py +46 -0
- cctx_cli-0.1.0/cctx/renderers/__init__.py +0 -0
- cctx_cli-0.1.0/cctx/renderers/report.py +58 -0
- cctx_cli-0.1.0/cctx/renderers/templates/autopsy.html.j2 +249 -0
- cctx_cli-0.1.0/cctx/renderers/terminal.py +251 -0
- cctx_cli-0.1.0/cctx/renderers/trace_tui.py +291 -0
- cctx_cli-0.1.0/cctx/tokenizer.py +77 -0
- cctx_cli-0.1.0/cctx-project-brief.md +372 -0
- cctx_cli-0.1.0/demo.gif +0 -0
- cctx_cli-0.1.0/demo.tape +14 -0
- cctx_cli-0.1.0/docs/health-reviews/2026-05-15-deep-review-summary.md +226 -0
- cctx_cli-0.1.0/docs/health-reviews/2026-05-15-health-review.md +149 -0
- cctx_cli-0.1.0/docs/product-reviews/2026-05-15-product-review.md +315 -0
- cctx_cli-0.1.0/docs/superpowers/plans/2026-05-12-claude-code-parser.md +3635 -0
- cctx_cli-0.1.0/docs/superpowers/plans/2026-05-14-autopsy-v0.md +2940 -0
- cctx_cli-0.1.0/docs/superpowers/plans/2026-05-16-readme-pypi-release.md +345 -0
- cctx_cli-0.1.0/docs/superpowers/specs/2026-05-12-claude-code-parser-design.md +433 -0
- cctx_cli-0.1.0/docs/superpowers/specs/2026-05-14-autopsy-design.md +618 -0
- cctx_cli-0.1.0/docs/superpowers/specs/2026-05-14-harvest-design.md +392 -0
- cctx_cli-0.1.0/docs/superpowers/specs/2026-05-14-trace-tui-design.md +733 -0
- cctx_cli-0.1.0/docs/superpowers/specs/2026-05-16-readme-pypi-release-design.md +178 -0
- cctx_cli-0.1.0/pyproject.toml +72 -0
- cctx_cli-0.1.0/tests/__init__.py +0 -0
- cctx_cli-0.1.0/tests/conftest.py +168 -0
- cctx_cli-0.1.0/tests/diagnostician/__init__.py +1 -0
- cctx_cli-0.1.0/tests/diagnostician/conftest.py +109 -0
- cctx_cli-0.1.0/tests/diagnostician/test_inflection.py +47 -0
- cctx_cli-0.1.0/tests/diagnostician/test_orchestrator.py +215 -0
- cctx_cli-0.1.0/tests/diagnostician/test_retry_loop.py +159 -0
- cctx_cli-0.1.0/tests/diagnostician/test_scope_creep.py +114 -0
- cctx_cli-0.1.0/tests/diagnostician/test_stale_context.py +165 -0
- cctx_cli-0.1.0/tests/exporters/__init__.py +0 -0
- cctx_cli-0.1.0/tests/exporters/test_csv.py +333 -0
- cctx_cli-0.1.0/tests/exporters/test_jsonl.py +251 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/README.md +28 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/short-clean/short-clean.jsonl +7 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a0b4c2cf1dde0ca56.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a116ae34b1b09c332.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a1c4c417b35658c9e.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a1e41a901de38f1b5.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a338f8d0c74612a24.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a34f6f3c0e7094186.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a5a5a0cff4d13308b.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a6b0a3da6a0484db5.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a7f73f1790b02cde5.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a7f7c17c38a9d8788.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a853259e2cd7bbe8a.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a8d9aedb0d0c6e12d.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aa778bc1d59e4a441.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aba869dedee4a12ba.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-ada2746d9774b94db.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aea0132068c64d2dd.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aea215eff50874d5f.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-afee21f2b3852a4a0.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-attachments/with-attachments.jsonl +500 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a051d9c9a6b2f5cc3.jsonl +75 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a051d9c9a6b2f5cc3.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a171f16f4e65cfe75.jsonl +41 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a171f16f4e65cfe75.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a1b77fea2c0a2269b.jsonl +15 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a1b77fea2c0a2269b.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a20da4c01a54acca8.jsonl +16 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a20da4c01a54acca8.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a3c82739b1383fb14.jsonl +113 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a3c82739b1383fb14.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a49e8539611c5fe12.jsonl +7 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a49e8539611c5fe12.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a7bb58f3fff2b3e8d.jsonl +10 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a7bb58f3fff2b3e8d.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a92b48c0331195aac.jsonl +92 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a92b48c0331195aac.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ab96c4264099694a9.jsonl +8 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ab96c4264099694a9.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-acb2895c5e34ffec0.jsonl +41 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-acb2895c5e34ffec0.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-adb2302769938fb3f.jsonl +62 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-adb2302769938fb3f.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ae585eca15cb93b9c.jsonl +35 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ae585eca15cb93b9c.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-aec9c917feb903d67.jsonl +77 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-aec9c917feb903d67.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-compaction/with-compaction.jsonl +580 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-a1a3a21aeb76bb0a9.jsonl +10 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-a1a3a21aeb76bb0a9.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-aaa1d6ecc05a78442.jsonl +9 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-aaa1d6ecc05a78442.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-af3c545ccd30036d2.jsonl +7 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-af3c545ccd30036d2.meta.json +1 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/tool-results/btwp2bzro.txt +34 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents/tool-results/byqjbgy4b.txt +17 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-subagents/with-subagents.jsonl +2218 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-tool-results/with-tool-results/tool-results/bosbkda0h.txt +13 -0
- cctx_cli-0.1.0/tests/fixtures/claude_code/with-tool-results/with-tool-results.jsonl +71 -0
- cctx_cli-0.1.0/tests/fixtures/scrub.py +167 -0
- cctx_cli-0.1.0/tests/fixtures/synthetic/bookkeeping_only.jsonl +3 -0
- cctx_cli-0.1.0/tests/fixtures/synthetic/malformed_middle.jsonl +3 -0
- cctx_cli-0.1.0/tests/fixtures/synthetic/truncated_final_line.jsonl +2 -0
- cctx_cli-0.1.0/tests/fixtures/synthetic/unknown_attachment_shape.jsonl +1 -0
- cctx_cli-0.1.0/tests/fixtures/synthetic/unknown_type.jsonl +2 -0
- cctx_cli-0.1.0/tests/parsers/__init__.py +0 -0
- cctx_cli-0.1.0/tests/parsers/test_claude_code.py +879 -0
- cctx_cli-0.1.0/tests/parsers/test_claude_code_integration.py +44 -0
- cctx_cli-0.1.0/tests/recommender/__init__.py +0 -0
- cctx_cli-0.1.0/tests/recommender/test_claude_md.py +353 -0
- cctx_cli-0.1.0/tests/recommender/test_evidence.py +139 -0
- cctx_cli-0.1.0/tests/renderers/__init__.py +0 -0
- cctx_cli-0.1.0/tests/renderers/test_report.py +283 -0
- cctx_cli-0.1.0/tests/renderers/test_terminal_renderer_full.py +310 -0
- cctx_cli-0.1.0/tests/test_aggregate.py +69 -0
- cctx_cli-0.1.0/tests/test_cli.py +102 -0
- cctx_cli-0.1.0/tests/test_cli_export.py +157 -0
- cctx_cli-0.1.0/tests/test_discovery.py +288 -0
- cctx_cli-0.1.0/tests/test_harvest.py +316 -0
- cctx_cli-0.1.0/tests/test_models.py +647 -0
- cctx_cli-0.1.0/tests/test_smoke.py +36 -0
- cctx_cli-0.1.0/tests/test_terminal_renderer.py +106 -0
- cctx_cli-0.1.0/tests/test_tokenizer.py +136 -0
- cctx_cli-0.1.0/tests/test_trace_tui.py +274 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: test (py${{ matrix.python-version }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
cache: pip
|
|
27
|
+
cache-dependency-path: pyproject.toml
|
|
28
|
+
|
|
29
|
+
- name: Install
|
|
30
|
+
run: pip install -e ".[dev]"
|
|
31
|
+
|
|
32
|
+
- name: Ruff check
|
|
33
|
+
run: ruff check cctx tests
|
|
34
|
+
|
|
35
|
+
- name: Pytest
|
|
36
|
+
env:
|
|
37
|
+
CCTX_OFFLINE: "1"
|
|
38
|
+
run: pytest -v
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
name: Test before publish
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
|
|
18
|
+
- name: Install
|
|
19
|
+
run: pip install -e ".[dev]"
|
|
20
|
+
|
|
21
|
+
- name: Pytest
|
|
22
|
+
env:
|
|
23
|
+
CCTX_OFFLINE: "1"
|
|
24
|
+
run: pytest -v
|
|
25
|
+
|
|
26
|
+
publish:
|
|
27
|
+
name: Publish to PyPI
|
|
28
|
+
needs: [test]
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
environment: pypi
|
|
31
|
+
permissions:
|
|
32
|
+
id-token: write
|
|
33
|
+
contents: read
|
|
34
|
+
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.12"
|
|
41
|
+
|
|
42
|
+
- name: Build
|
|
43
|
+
run: |
|
|
44
|
+
pip install build
|
|
45
|
+
python -m build
|
|
46
|
+
|
|
47
|
+
- name: Publish
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# macOS
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
*.egg-info/
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
.eggs/
|
|
12
|
+
pip-log.txt
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
|
|
19
|
+
# Test / coverage / type-check caches
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.tox/
|
|
24
|
+
.coverage
|
|
25
|
+
.coverage.*
|
|
26
|
+
htmlcov/
|
|
27
|
+
coverage.xml
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
|
|
35
|
+
# Local Claude Code settings (machine-specific permissions)
|
|
36
|
+
.claude/settings.local.json
|
cctx_cli-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# cctx
|
|
2
|
+
|
|
3
|
+
Open-source Python CLI that diagnoses individual Claude Code sessions: when they went wrong, why they went wrong, what they cost, and what to add to your `CLAUDE.md` so it doesn't happen again. Reads the JSONL session logs Claude Code writes to `~/.claude/projects/` and produces actionable autopsy reports.
|
|
4
|
+
|
|
5
|
+
The complete product pitch, example outputs, growth staircase, and positioning vs. adjacent tools are in [`cctx-project-brief.md`](cctx-project-brief.md). Read it once.
|
|
6
|
+
|
|
7
|
+
## Tech stack
|
|
8
|
+
|
|
9
|
+
- **Python 3.10+**
|
|
10
|
+
- **click** — CLI argument parsing and subcommand routing
|
|
11
|
+
- **rich-click** — re-skins click's `--help` through rich (drop-in: `import rich_click as click`). Pure shininess win on the `--help` surface, no behavioral cost
|
|
12
|
+
- **rich** — terminal output: tables, banners, severity badges, diff blocks
|
|
13
|
+
- **textual** — the TUI for `cctx trace`
|
|
14
|
+
- **anthropic** — token counting only, via `anthropic.messages.count_tokens` in the tokenizer module. **Not imported anywhere else.**
|
|
15
|
+
- **pandas** — optional, only inside the cross-session aggregator if/when row-level work justifies it. Stdlib-first.
|
|
16
|
+
- **Jinja2** — HTML report templates for `cctx autopsy --html`
|
|
17
|
+
|
|
18
|
+
Explicitly not used: web frameworks, databases, ORMs, async runtimes, cloud SDKs. cctx is a local CLI.
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Session log (Claude Code JSONL on disk)
|
|
24
|
+
↓
|
|
25
|
+
Parser ← dependency-free; takes a path, returns SessionTrace
|
|
26
|
+
↓
|
|
27
|
+
Tokenizer ← only place that imports anthropic; offline-mode safe for CI
|
|
28
|
+
↓
|
|
29
|
+
Diagnostician ← per-turn investigation: inflection detection + pattern
|
|
30
|
+
classifiers (retry loop, scope creep, stale context).
|
|
31
|
+
Produces a Diagnosis.
|
|
32
|
+
↓
|
|
33
|
+
Recommender ← turns Findings into Patches: copy-pasteable CLAUDE.md /
|
|
34
|
+
rule / skill diffs, evidence-backed when cross-session.
|
|
35
|
+
↓
|
|
36
|
+
Renderers ← rich (terminal), Jinja2 (HTML report), textual (trace
|
|
37
|
+
TUI overlay).
|
|
38
|
+
↓
|
|
39
|
+
Exporters ← jsonl, csv.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Project layout
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
cctx/
|
|
46
|
+
├── cli.py # click + rich-click; routes to autopsy / trace / export
|
|
47
|
+
├── parsers/
|
|
48
|
+
│ └── claude_code.py # SHIPPED. Parse ~/.claude JSONL logs.
|
|
49
|
+
│ # Spec: docs/superpowers/specs/2026-05-12-claude-code-parser-design.md
|
|
50
|
+
├── tokenizer.py # SHIPPED. anthropic.count_tokens wrapper; CCTX_OFFLINE heuristic.
|
|
51
|
+
├── models.py # SHIPPED. Turn, ToolUse, ToolResult, Usage, Attachment,
|
|
52
|
+
│ # RawToolResultFile, SessionTrace + group_into_exchanges().
|
|
53
|
+
│ # M2 extends with Finding, Patch, Diagnosis.
|
|
54
|
+
├── diagnostician/
|
|
55
|
+
│ ├── __init__.py # public: run(trace) -> Diagnosis
|
|
56
|
+
│ ├── inflection.py # detect the turn where the session diverged
|
|
57
|
+
│ ├── patterns/
|
|
58
|
+
│ │ ├── retry_loop.py
|
|
59
|
+
│ │ ├── scope_creep.py
|
|
60
|
+
│ │ └── stale_context.py
|
|
61
|
+
│ └── aggregate.py # cross-session pattern aggregator (--since mode)
|
|
62
|
+
├── recommender/
|
|
63
|
+
│ ├── claude_md.py # Finding -> Patch (CLAUDE.md diff proposals)
|
|
64
|
+
│ └── evidence.py # session-count + dollar evidence accumulation
|
|
65
|
+
├── harvest.py # SHIPPED. apply_patch, preview_patches, apply_patches —
|
|
66
|
+
│ # append-only, idempotent CLAUDE.md patching with
|
|
67
|
+
│ # fingerprint-based deduplication.
|
|
68
|
+
├── renderers/
|
|
69
|
+
│ ├── terminal.py # rich rendering of a Diagnosis
|
|
70
|
+
│ ├── report.py # Jinja2 HTML report (cctx autopsy --html)
|
|
71
|
+
│ └── trace_tui.py # textual TUI with autopsy findings overlaid
|
|
72
|
+
└── exporters/
|
|
73
|
+
├── jsonl.py
|
|
74
|
+
└── csv.py
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Layering rules (enforced by convention)
|
|
78
|
+
|
|
79
|
+
These keep the dependency graph clean so modules stay independently testable and refactorable:
|
|
80
|
+
|
|
81
|
+
- **Parsers never import the tokenizer, the anthropic SDK, or any analyzer.** A parser takes a path and returns a `SessionTrace` with `token_count: int = 0` placeholders.
|
|
82
|
+
- **Tokenizer is the only module that imports `anthropic`.** Everyone else gets token counts pre-populated on the dataclasses.
|
|
83
|
+
- **Analyzers (diagnostician, recommender, aggregate) never import each other across boundary lines.** Inside the diagnostician package, helpers can compose freely. The recommender takes a Diagnosis and emits Patches without reaching back into the diagnostician's internals.
|
|
84
|
+
- **Renderers never compute analysis.** They take an analyzer's output and render it. Swapping `terminal.py` for `report.py` should not change a single number or finding.
|
|
85
|
+
- **Only `cli.py` imports `click` and `rich_click`.** Everything else uses plain `rich.Console` if it needs to output. Analyzers and parsers return data; the CLI decides how to display it.
|
|
86
|
+
|
|
87
|
+
## Core design decisions
|
|
88
|
+
|
|
89
|
+
These came out of the brief, the parser brainstorming session, and the autopsy pivot. They apply across the entire codebase:
|
|
90
|
+
|
|
91
|
+
- **Diagnose the specific session, not the aggregate.** cctx is forensic. CodeBurn covers daily cost tracking; cctx is "what went sideways here, and what do I add to CLAUDE.md so it doesn't happen again."
|
|
92
|
+
- **Token-turns is a useful metric for stale-content attribution.** `tokens × turns_present`, compaction-aware. A 22K grep result sitting in context for 14 turns after its last reference costs ~310K token-turns of waste. This is how stale-context findings attribute their dollar cost.
|
|
93
|
+
- **Approximate decomposition is fine.** Reconstructing the API request from the JSONL gets you ~85–95% of the actual `input_tokens`. The remainder is internal framing you can't observe. The system internals slice is honest; don't pretend to be exact.
|
|
94
|
+
- **Binary waste detection only in v1.** "Loaded but never called" is high-confidence. "Partially used" is fragile. Ship the binary version.
|
|
95
|
+
- **Patches must be copy-pasteable.** Every Patch carries a unified diff against a target file (CLAUDE.md, rules, skill, ADR). Lower the barrier to action to zero.
|
|
96
|
+
- **Single-session AND cross-session, same diagnostician.** `cctx autopsy <session>` and `cctx autopsy <project> --since <window>` go through the same per-session pipeline; the aggregator runs after.
|
|
97
|
+
- **Group up, never down.** Parse at the finest granularity the source provides (per JSONL line). Aggregate in the view layer. (Originated in the parser design — applies everywhere.)
|
|
98
|
+
- **Empirical evidence collapses speculative complexity.** Before designing for a hypothetical case, scan real data. The parser spec's tool-result handling was simplified by 80% after one 30-line empirical scan.
|
|
99
|
+
- **Deterministic over LLM-assisted in v0.** Pattern classifiers use heuristics, not LLM calls. (Future v1+ harvest may invoke an LLM for summarization, opt-in with API key.) The deterministic core has predictable cost and is testable on fixtures.
|
|
100
|
+
|
|
101
|
+
## Build order (post-pivot)
|
|
102
|
+
|
|
103
|
+
1. **M0 — Project setup.** SHIPPED. (#1)
|
|
104
|
+
2. **M1 — Foundation.** SHIPPED — parser, tokenizer, models, fixtures, CI. (#2–#6, plus PR #38)
|
|
105
|
+
3. **M2 — Autopsy v0.** SHIPPED — single-session diagnosis + cross-session pattern detection. The wedge product. (#9, #10, #40–#49)
|
|
106
|
+
4. **M3 — Trace TUI** with autopsy overlay. SHIPPED. (PR #57)
|
|
107
|
+
5. **M4 — Export.** SHIPPED — jsonl + csv exporters (html moved to autopsy --html; json deferred). (PR #54)
|
|
108
|
+
6. **M5 — Harvest v1.** SHIPPED — CLAUDE.md target only in v0; promote autopsy findings to durable CLAUDE.md diffs. (PR #56)
|
|
109
|
+
7. **M6 — Release v0.1.0.** Release prep underway — README, PRODUCT.md, DESIGN.md, version bump, PyPI publish. (#31, #32)
|
|
110
|
+
|
|
111
|
+
Future, not yet milestoned:
|
|
112
|
+
- **Memory hygiene** (`cctx harvest --check`) — audit existing CLAUDE.md and memory files for staleness / contradictions / dead skills.
|
|
113
|
+
- **Live mode** (`cctx watch`) — filesystem watcher on `~/.claude/projects` to surface waste signals during a session.
|
|
114
|
+
- **Cross-agent layer** — emit the same captured knowledge as `.cursorrules`, `AGENTS.md`, `.windsurfrules`, GitHub Copilot instructions.
|
|
115
|
+
|
|
116
|
+
## Design docs
|
|
117
|
+
|
|
118
|
+
Feature designs live in `docs/superpowers/specs/`, dated and committed before implementation begins. Each implementation plan in `docs/superpowers/plans/` references its spec. Don't start a feature without one.
|
|
119
|
+
|
|
120
|
+
Current specs landed on main:
|
|
121
|
+
- `docs/superpowers/specs/2026-05-12-claude-code-parser-design.md` — the Claude Code JSONL parser.
|
|
122
|
+
|
|
123
|
+
In progress / pending:
|
|
124
|
+
- `docs/superpowers/specs/<date>-autopsy-design.md` — autopsy v0 design (#40). The next spec to be brainstormed.
|
|
125
|
+
|
|
126
|
+
## GitHub issue structure
|
|
127
|
+
|
|
128
|
+
The post-pivot board is anchored to autopsy. New work should follow the same conventions so the board stays coherent.
|
|
129
|
+
|
|
130
|
+
**Granularity.** One issue = one PR. If a ticket can't reasonably land in a single PR, split it. Cross-cutting infrastructure gets its own ticket rather than being buried inside the first consumer. Test fixtures that block a feature get their own ticket. High-polish or novel surfaces (e.g. the TUI) split into spec + implementation.
|
|
131
|
+
|
|
132
|
+
**Milestones.** Phases get milestones (`M0 — Project setup` through `M6 — Release v0.1.0`). Every issue belongs to exactly one milestone. Add a new milestone if a phase is genuinely new; don't reuse an existing milestone for unrelated work.
|
|
133
|
+
|
|
134
|
+
**Labels.** Use `area:*` labels only (parser, analyzer, cli, renderer, exporter, tokenizer, tui, models, infra, docs). An issue can have multiple `area:` labels if it touches multiple layers. Don't invent new label taxonomies (priority, type, status) — milestones + the issue board cover that.
|
|
135
|
+
|
|
136
|
+
**Body template.** Every issue has these sections, in this order:
|
|
137
|
+
|
|
138
|
+
```markdown
|
|
139
|
+
**Phase:** Mn — <phase name>
|
|
140
|
+
**Module:** `path/to/file.py` (or files plural)
|
|
141
|
+
|
|
142
|
+
## Goal
|
|
143
|
+
One paragraph: what this delivers and why.
|
|
144
|
+
|
|
145
|
+
## Acceptance criteria
|
|
146
|
+
- [ ] Spec at `docs/superpowers/specs/<date>-<slug>.md` reviewed first (if a spec is warranted — see below)
|
|
147
|
+
- [ ] Concrete, testable items
|
|
148
|
+
- [ ] Tests that prove the behavior
|
|
149
|
+
- [ ] Layering invariants honored (e.g. "no imports from `anthropic`")
|
|
150
|
+
|
|
151
|
+
## Files
|
|
152
|
+
- Exact paths the PR touches
|
|
153
|
+
|
|
154
|
+
## References
|
|
155
|
+
- Brief sections, prior spec sections, CLAUDE.md sections
|
|
156
|
+
|
|
157
|
+
## Blocked by
|
|
158
|
+
- (Posted as a comment with `#N` references after all related issues are filed — GitHub auto-links and surfaces the dependency graph.)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Spec gate inside the ticket.** CLAUDE.md requires specs before implementation. The default is **the spec is the first acceptance-criteria checkbox in the implementation ticket**, not a separate ticket. Exceptions: surfaces big enough that the spec is itself a meaningful deliverable (the autopsy v0 design is #40 — separate from the implementation tickets that consume it).
|
|
162
|
+
|
|
163
|
+
**Dependencies.** After filing a batch of issues, post a comment on each blocked ticket: `Blocked by #N, #M`. GitHub auto-links and shows the parent/child relationship in the timeline. Don't try to encode the dep graph in the issue body — it goes stale and is painful to maintain.
|
|
164
|
+
|
|
165
|
+
**Granularity smell tests** (use these when proposing a new ticket):
|
|
166
|
+
- *Too thick* — needs two specs, two reviewers, or PRs in two different areas (`area:parser` + `area:cli`). Split along the layering boundary.
|
|
167
|
+
- *Too thin* — the entire ticket fits in a 5-line PR with no tests. Combine with its sibling.
|
|
168
|
+
- *Hidden dependency* — the work assumes something exists that isn't filed yet. File that first or note it as blocked-by.
|
|
169
|
+
|
|
170
|
+
## Working in this repo
|
|
171
|
+
|
|
172
|
+
- The brief is authoritative for product scope. Don't rewrite it during implementation; if scope needs to change, amend the brief deliberately.
|
|
173
|
+
- Specs are authoritative for module design. Don't deviate during implementation without updating the spec.
|
|
174
|
+
- When implementing a feature: write the spec, get it reviewed, then write the plan (via the superpowers `writing-plans` skill), then implement.
|
|
175
|
+
- The parser is dependency-free by design. If you find yourself adding `import anthropic` or `import click` inside `parsers/`, stop — that work belongs in `tokenizer.py` or `cli.py`.
|
|
176
|
+
- The tokenizer's offline mode (`CCTX_OFFLINE=1`) is the default for CI and tests. Live tokenization happens only when the CLI explicitly opts in and `ANTHROPIC_API_KEY` is set.
|
cctx_cli-0.1.0/DESIGN.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# cctx Design System
|
|
2
|
+
|
|
3
|
+
Reference for the three output surfaces: Rich terminal, Textual TUI, Jinja2 HTML report.
|
|
4
|
+
|
|
5
|
+
## Color palette (terminal/TUI)
|
|
6
|
+
|
|
7
|
+
| State | Rich style |
|
|
8
|
+
|---|---|
|
|
9
|
+
| HIGH severity | `bold red` |
|
|
10
|
+
| MEDIUM severity | `bold yellow` |
|
|
11
|
+
| LOW severity | `bold green` |
|
|
12
|
+
| Applied/success | `green` |
|
|
13
|
+
| Error/failure | `red` |
|
|
14
|
+
| Skipped/neutral | `dim` |
|
|
15
|
+
|
|
16
|
+
## Cost formatting
|
|
17
|
+
|
|
18
|
+
| Context | Format | Example |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| User-facing summary (verdict, totals) | `:.2f` | `$1.42` |
|
|
21
|
+
| Per-finding detail | `:.4f` | `$0.0082` |
|
|
22
|
+
|
|
23
|
+
## Finding kind labels
|
|
24
|
+
|
|
25
|
+
Canonical display form is space-separated uppercase. Never use the raw enum value in user-facing output.
|
|
26
|
+
|
|
27
|
+
| Enum value | Display label |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `retry_loop` | `RETRY LOOP` |
|
|
30
|
+
| `scope_creep` | `SCOPE CREEP` |
|
|
31
|
+
| `stale_context` | `STALE CONTEXT` |
|
|
32
|
+
|
|
33
|
+
Use `_KIND_LABEL` dict in `renderers/terminal.py` as the source of truth. The HTML template currently uses `.replace("_", " ").upper()` inline — this is equivalent for the three current kinds but will diverge if a new kind uses a non-underscore separator.
|
|
34
|
+
|
|
35
|
+
## Verdict string
|
|
36
|
+
|
|
37
|
+
Format across all surfaces: `"Clean session"` (no findings) or `"{n} finding(s) · ${waste:.2f} waste"` (with findings).
|
|
38
|
+
|
|
39
|
+
The brief examples use `"⚠ retry loop + scope creep"` (kind-based) — that is a future format, not yet implemented.
|
|
40
|
+
|
|
41
|
+
## Evidence rendering
|
|
42
|
+
|
|
43
|
+
| Surface | Rendering |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Terminal | `finding.summary` inline text |
|
|
46
|
+
| HTML report | Per-finding `<details>` with evidence as formatted JSON (TODO: structured per-kind in v0.2) |
|
|
47
|
+
| TUI FindingModal | Summary + raw evidence (TODO: structured per-kind in v0.2) |
|
|
48
|
+
|
|
49
|
+
## Anti-patterns
|
|
50
|
+
|
|
51
|
+
- **Never** use `red` style for success states (APPLIED patch = success = green)
|
|
52
|
+
- **Never** render evidence dicts as raw `json.dumps` in the primary user-facing path (HTML verdict area is OK for v0; structured per-kind in v0.2)
|
|
53
|
+
- **Never** define CSS syntax-highlighting classes without corresponding template markup to apply them
|
|
54
|
+
- **Never** import `click` or `rich_click` outside `cli.py`
|
cctx_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cctx-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Diagnose Claude Code sessions — find what went wrong, what it cost, and what to add to CLAUDE.md
|
|
5
|
+
Author: Jacquard Labs
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: anthropic>=0.25
|
|
9
|
+
Requires-Dist: click>=8.0
|
|
10
|
+
Requires-Dist: jinja2>=3.0
|
|
11
|
+
Requires-Dist: rich-click>=1.8
|
|
12
|
+
Requires-Dist: rich>=13.0
|
|
13
|
+
Requires-Dist: textual>=0.59
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: anyio[trio]; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
17
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
18
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# cctx
|
|
22
|
+
|
|
23
|
+
Diagnose your Claude Code sessions — find out when they went wrong, why they cost what they did, and what to add to your `CLAUDE.md` so it doesn't happen again.
|
|
24
|
+
|
|
25
|
+
[](https://github.com/jacquardlabs/cctx/actions/workflows/ci.yml)
|
|
26
|
+
[](https://pypi.org/project/cctx-cli/)
|
|
27
|
+
[](https://pypi.org/project/cctx-cli/)
|
|
28
|
+
[](LICENSE)
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pipx install cctx-cli
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or with pip:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install cctx-cli
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`pipx` is recommended — it installs cctx in an isolated environment so its dependencies don't conflict with your projects.
|
|
45
|
+
|
|
46
|
+
## Quick start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cctx ls # find your sessions
|
|
50
|
+
cctx autopsy --latest # diagnose the most recent one
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
cctx is a forensic tool. You reach for it after a session — when something felt off, when the cost was higher than expected, or on a weekly review pass. It reads the JSONL logs Claude Code writes to `~/.claude/projects/` and produces findings with attributed cost and copy-pasteable `CLAUDE.md` patches.
|
|
54
|
+
|
|
55
|
+
## Commands
|
|
56
|
+
|
|
57
|
+
### `cctx ls` — list projects and sessions
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cctx ls # list all Claude Code projects
|
|
61
|
+
cctx ls ~/Projects/myapp # list sessions for a specific project
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `cctx autopsy` — diagnose a session
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Most recent session in the current directory
|
|
68
|
+
cctx autopsy --latest
|
|
69
|
+
|
|
70
|
+
# Specific session file
|
|
71
|
+
cctx autopsy ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl
|
|
72
|
+
|
|
73
|
+
# All sessions from the last 7 days
|
|
74
|
+
cctx autopsy ~/Projects/myapp --since 7
|
|
75
|
+
|
|
76
|
+
# Write a self-contained HTML report
|
|
77
|
+
cctx autopsy ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --html report.html
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Runs three pattern classifiers (retry loop, scope creep, stale context) and prints findings with attributed cost. Use `--since N` to aggregate patterns across multiple sessions in a project.
|
|
81
|
+
|
|
82
|
+
### `cctx harvest` — apply patches to CLAUDE.md
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Interactive: preview then confirm
|
|
86
|
+
cctx harvest ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl
|
|
87
|
+
|
|
88
|
+
# Preview only — don't write anything
|
|
89
|
+
cctx harvest ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --dry-run
|
|
90
|
+
|
|
91
|
+
# Apply without confirmation
|
|
92
|
+
cctx harvest ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --apply
|
|
93
|
+
|
|
94
|
+
# Cross-session: patches from the last 7 days of sessions
|
|
95
|
+
cctx harvest ~/Projects/myapp --since 7
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Turns autopsy findings into copy-pasteable `CLAUDE.md` additions. Patches are idempotent — running harvest twice on the same session won't duplicate entries. Use `--target-dir DIR` to specify which directory's `CLAUDE.md` to patch (default: current working directory).
|
|
99
|
+
|
|
100
|
+
### `cctx export` — export session data
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# CSV to file
|
|
104
|
+
cctx export ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --format csv --out session.csv
|
|
105
|
+
|
|
106
|
+
# JSONL to stdout
|
|
107
|
+
cctx export ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --format jsonl
|
|
108
|
+
|
|
109
|
+
# Omit patch text and finding summaries (smaller output for scripted use)
|
|
110
|
+
cctx export ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --format jsonl --no-content
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Dumps session analysis as JSONL (one object per session) or CSV (one row per turn) for use in external tools.
|
|
114
|
+
|
|
115
|
+
### `cctx trace` — interactive TUI
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
cctx trace ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Steps through a session turn by turn in a terminal UI with autopsy findings overlaid. Press `q` to quit.
|
|
122
|
+
|
|
123
|
+
## What cctx detects
|
|
124
|
+
|
|
125
|
+
| Pattern | What it means | How it wastes money |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| **Retry loop** | The same tool call failing 2+ times with no successful fix | Repeated identical API calls burn input tokens |
|
|
128
|
+
| **Scope creep** | Assistant expanding scope mid-task without being asked | Unnecessary extra turns and tool calls |
|
|
129
|
+
| **Stale context** | Large tool results sitting in context long after their last reference | `content_tokens × billed_turns_stale` — a 22K grep result still present 14 turns later costs ~308K token-turns |
|
|
130
|
+
|
|
131
|
+
## Cost attribution
|
|
132
|
+
|
|
133
|
+
cctx estimates session cost using Anthropic's published billing rates:
|
|
134
|
+
|
|
135
|
+
- Input tokens: standard rate
|
|
136
|
+
- Cache reads: 10% of the input rate
|
|
137
|
+
- Cache writes: 125% of the input rate
|
|
138
|
+
|
|
139
|
+
Stale-context waste is attributed turn by turn: every turn a large result stays in context after its last reference counts against waste.
|
|
140
|
+
|
|
141
|
+
These are **approximations** (~85–95% of actual API billing). The gap is internal prompt framing that isn't observable in the JSONL logs. cctx shows estimated costs, not billing-exact figures.
|
|
142
|
+
|
|
143
|
+
## Requirements
|
|
144
|
+
|
|
145
|
+
- Python 3.10+
|
|
146
|
+
- Claude Code session logs at `~/.claude/projects/` (written automatically by Claude Code)
|
|
147
|
+
- No API key required for analysis
|
|
148
|
+
|
|
149
|
+
An `ANTHROPIC_API_KEY` is optional. When set, cctx can call the Anthropic API for exact token counts. Without it, cctx uses the token counts already recorded in the JSONL logs (the default and recommended mode for most users).
|
|
150
|
+
|
|
151
|
+
## Session log location
|
|
152
|
+
|
|
153
|
+
Claude Code writes logs to `~/.claude/projects/<encoded-path>/<session-id>.jsonl`. The project path is URL-encoded with `-` replacing `/`, so `/Users/you/Projects/myapp` becomes `-Users-you-Projects-myapp`.
|
|
154
|
+
|
|
155
|
+
`cctx ls` handles discovery automatically — you don't need to navigate the encoded directory structure by hand.
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# PRODUCT.md — cctx
|
|
2
|
+
|
|
3
|
+
## What is this
|
|
4
|
+
|
|
5
|
+
cctx is a local Python CLI that reads Claude Code session logs and tells you what went wrong, why it cost what it did, and what to add to your CLAUDE.md so it doesn't happen again.
|
|
6
|
+
|
|
7
|
+
It is a forensic tool, not a monitoring tool. You reach for it after a session — when something felt off, when the bill was higher than expected, or on a weekly review pass.
|
|
8
|
+
|
|
9
|
+
## Primary persona
|
|
10
|
+
|
|
11
|
+
**The regular Claude Code user** who:
|
|
12
|
+
- Runs multiple Claude Code sessions per day across one or more projects
|
|
13
|
+
- Maintains a CLAUDE.md and wants it to get smarter over time
|
|
14
|
+
- Is willing to read a terminal report and act on its suggestions
|
|
15
|
+
- Cares about cost and session quality but does not need a dashboard
|
|
16
|
+
- Is comfortable with the command line and with `~/.claude/projects/` on disk
|
|
17
|
+
|
|
18
|
+
This persona is already the target; everything shipped to date serves them directly.
|
|
19
|
+
|
|
20
|
+
## What cctx is NOT for
|
|
21
|
+
|
|
22
|
+
- Teams or organizations (no shared reports, no access control, no multi-user state)
|
|
23
|
+
- Real-time monitoring (completed sessions only in v0 and v1)
|
|
24
|
+
- General cost dashboards (CodeBurn covers that; cctx is forensic)
|
|
25
|
+
- Multi-provider support (Claude Code only in v0/v1)
|
|
26
|
+
- Users who do not read session transcripts or maintain CLAUDE.md
|
|
27
|
+
|
|
28
|
+
## Product principles
|
|
29
|
+
|
|
30
|
+
**1. Forensic, not ambient.**
|
|
31
|
+
cctx is used after something goes wrong, not as background infrastructure. Every feature should be justified by this use case: "I just ran a session, something went sideways, I want to know what."
|
|
32
|
+
|
|
33
|
+
**2. Output must be actionable.**
|
|
34
|
+
Every report should produce at least one thing the user can do immediately. Findings without patches are incomplete. Patches must be copy-pasteable or auto-applicable.
|
|
35
|
+
|
|
36
|
+
**3. Honest about uncertainty.**
|
|
37
|
+
Costs are approximated (85–95% of actual). Pattern classifiers fire only on high-confidence signals. Low-confidence signals are shown with explicit confidence labels. "System internals" token budget is never hidden or misattributed.
|
|
38
|
+
|
|
39
|
+
**4. Local and stateless.**
|
|
40
|
+
No network calls in the core analysis path (tokenizer may call the API for token counting; that is opt-in). No persistent database. No telemetry. No account. Users own their data.
|
|
41
|
+
|
|
42
|
+
**5. Deterministic.**
|
|
43
|
+
Pattern classifiers are heuristics, not LLM calls. The same session file produces the same output every time. Testable on fixtures. Predictable cost to run.
|
|
44
|
+
|
|
45
|
+
**6. Small surface, deep on each command.**
|
|
46
|
+
Four commands. No command is shallow. Users should be able to learn the product in an afternoon and trust what it tells them.
|
|
47
|
+
|
|
48
|
+
## Feature map (v0.1.0)
|
|
49
|
+
|
|
50
|
+
### Shipped
|
|
51
|
+
|
|
52
|
+
| Feature | Command | Status |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| Single-session diagnosis | `cctx autopsy <session>` | Shipped (M2) |
|
|
55
|
+
| Cross-session pattern detection | `cctx autopsy <project> --since N` | Shipped (M2) |
|
|
56
|
+
| HTML report | `cctx autopsy <session> --html FILE` | Shipped (M2/PR#59) |
|
|
57
|
+
| Session trace TUI | `cctx trace <session>` | Shipped (M3) |
|
|
58
|
+
| JSONL export | `cctx export <session> --format jsonl` | Shipped (M4) |
|
|
59
|
+
| CSV export | `cctx export <session> --format csv` | Shipped (M4) |
|
|
60
|
+
| Harvest (CLAUDE.md patcher) | `cctx harvest <session>` | Shipped (M5) |
|
|
61
|
+
| Cross-session harvest | `cctx harvest <project> --since N` | Shipped (M5) |
|
|
62
|
+
|
|
63
|
+
### Pattern classifiers (v0.1.0)
|
|
64
|
+
|
|
65
|
+
| Pattern | Status |
|
|
66
|
+
|---|---|
|
|
67
|
+
| Retry loop | Shipped |
|
|
68
|
+
| Scope creep | Shipped |
|
|
69
|
+
| Stale context | Shipped |
|
|
70
|
+
| Dead-end exploration | Not shipped in v0 |
|
|
71
|
+
| Tool thrashing | Not shipped in v0 |
|
|
72
|
+
|
|
73
|
+
### NOT in v0.1.0
|
|
74
|
+
|
|
75
|
+
- `--format json` and `--format html` on `export` (html moved to `autopsy --html`; json not scheduled)
|
|
76
|
+
- `--since` string formats (`7d`, `2w`, date ranges, `--until`, `--top N`) — accepts integer days only
|
|
77
|
+
- Patch targets other than `CLAUDE.md` (rules, skills, ADR — v1+)
|
|
78
|
+
- Interactive aggregate drill-down ("press N to inspect pattern") — read-only in v0
|
|
79
|
+
- `cctx ls` / session discovery helper
|
|
80
|
+
- Dead-end and tool-thrash classifiers
|
|
81
|
+
|
|
82
|
+
## What we are NOT building
|
|
83
|
+
|
|
84
|
+
- A SaaS or cloud product
|
|
85
|
+
- An agent (cctx reads logs; it does not call the Anthropic API except optionally for token counting)
|
|
86
|
+
- A real-time watcher (v2+ roadmap item)
|
|
87
|
+
- Multi-provider support (v3+ roadmap item)
|
|
88
|
+
- A fork-and-replay debugger
|
|
89
|
+
- A general eval or testing framework
|
|
90
|
+
|
|
91
|
+
## Known problems (as of 2026-05-15)
|
|
92
|
+
|
|
93
|
+
**Release blockers for v0.1.0 (M6):**
|
|
94
|
+
|
|
95
|
+
1. **No README.md.** `pyproject.toml` uses `cctx-project-brief.md` as the readme. The brief contains architecture diagrams and an internal "First session prompt" that should not be on PyPI. A user-facing README.md is required before publish.
|
|
96
|
+
|
|
97
|
+
2. **`pyproject.toml` description is inaccurate.** Current: "Profile, debug, and optimize Claude Code and Agent SDK sessions." Accurate: "Diagnose Claude Code sessions — find what went wrong, what it cost, and what to add to CLAUDE.md."
|
|
98
|
+
|
|
99
|
+
3. **Version is `0.0.1`.** M6 requires bumping to `0.1.0`.
|
|
100
|
+
|
|
101
|
+
4. **Brief example outputs show unshipped features.** The `cctx-project-brief.md` (which currently IS the readme) shows 5 pattern classifiers, 4 export formats, string `--since` arguments, a `Verdict` headline, and interactive aggregate output. None of these are accurate for the shipped CLI. Before PyPI publish, either ship them or update the brief.
|
|
102
|
+
|
|
103
|
+
**Active gaps (non-blocking for v0.1.0 but worth tracking):**
|
|
104
|
+
|
|
105
|
+
5. **Cost approximation honesty not surfaced in output.** The terminal renderer shows `$X.XX` total cost with no confidence annotation. The brief says "The system internals slice is honest; don't pretend to be exact" — this is a principle not yet expressed to users in output.
|
|
106
|
+
|
|
107
|
+
6. **No session discovery helper.** Users must manually navigate URL-encoded project directories in `~/.claude/projects/` to find session files. First-run friction.
|
|
108
|
+
|
|
109
|
+
7. **Aggregate output is read-only.** The brief's example shows an interactive aggregate view. Shipped aggregate is a static table. The interactive drill-down is a meaningful UX gap that the brief implicitly promises.
|