cctx-cli 1.12.1__tar.gz → 1.13.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.
Files changed (189) hide show
  1. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/CHANGELOG.md +15 -0
  2. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/PKG-INFO +9 -2
  3. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/README.md +8 -1
  4. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/__init__.py +1 -1
  5. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/__init__.py +2 -0
  6. cctx_cli-1.13.0/cctx/diagnostician/patterns/cache_hygiene.py +125 -0
  7. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/models.py +3 -0
  8. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/recommender/claude_md.py +11 -0
  9. cctx_cli-1.12.1/docs/quickstart-openai-agents.md → cctx_cli-1.13.0/docs/quickstart-otel.md +77 -8
  10. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/pyproject.toml +1 -1
  11. cctx_cli-1.13.0/tests/test_cache_hygiene_classifier.py +280 -0
  12. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_harvest_emit.py +2 -1
  13. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/.github/workflows/ci.yml +0 -0
  14. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/.github/workflows/publish.yml +0 -0
  15. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/.github/workflows/release.yml +0 -0
  16. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/.gitignore +0 -0
  17. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/CLAUDE.md +0 -0
  18. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/DESIGN.md +0 -0
  19. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/PRODUCT.md +0 -0
  20. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/action.yml +0 -0
  21. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/agents.py +0 -0
  22. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/cli.py +0 -0
  23. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/aggregate.py +0 -0
  24. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/inflection.py +0 -0
  25. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/__init__.py +0 -0
  26. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/dead_end.py +0 -0
  27. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/fan_out.py +0 -0
  28. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/project_specific.py +0 -0
  29. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/retry_loop.py +0 -0
  30. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/scope_creep.py +0 -0
  31. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/stale_context.py +0 -0
  32. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/diagnostician/patterns/tool_thrash.py +0 -0
  33. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/discovery.py +0 -0
  34. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/exporters/__init__.py +0 -0
  35. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/exporters/csv.py +0 -0
  36. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/exporters/json.py +0 -0
  37. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/exporters/jsonl.py +0 -0
  38. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/harvest.py +0 -0
  39. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/hook_installer.py +0 -0
  40. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/parsers/__init__.py +0 -0
  41. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/parsers/claude_code.py +0 -0
  42. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/parsers/otel.py +0 -0
  43. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/pricing.py +0 -0
  44. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/recommender/__init__.py +0 -0
  45. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/recommender/evidence.py +0 -0
  46. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/renderers/__init__.py +0 -0
  47. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/renderers/github.py +0 -0
  48. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/renderers/report.py +0 -0
  49. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/renderers/templates/autopsy.html.j2 +0 -0
  50. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/renderers/terminal.py +0 -0
  51. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/renderers/trace_tui.py +0 -0
  52. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/tokenizer.py +0 -0
  53. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx/watcher.py +0 -0
  54. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/cctx-project-brief.md +0 -0
  55. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/demo.gif +0 -0
  56. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/demo.tape +0 -0
  57. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/health-reviews/2026-05-15-deep-review-summary.md +0 -0
  58. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/health-reviews/2026-05-15-health-review.md +0 -0
  59. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/product-reviews/2026-05-15-product-review.md +0 -0
  60. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/product-reviews/2026-06-09-product-review.md +0 -0
  61. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/plans/2026-05-12-claude-code-parser.md +0 -0
  62. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/plans/2026-05-14-autopsy-v0.md +0 -0
  63. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/plans/2026-05-16-readme-pypi-release.md +0 -0
  64. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/plans/2026-05-17-harvest-check-depth.md +0 -0
  65. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/plans/2026-05-17-project-pattern-detection.md +0 -0
  66. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/plans/2026-05-19-claude-agents-live-integration.md +0 -0
  67. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/plans/2026-06-19-otel-parser.md +0 -0
  68. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-12-claude-code-parser-design.md +0 -0
  69. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-14-autopsy-design.md +0 -0
  70. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-14-harvest-design.md +0 -0
  71. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-14-trace-tui-design.md +0 -0
  72. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-16-readme-pypi-release-design.md +0 -0
  73. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-17-harvest-check-depth-design.md +0 -0
  74. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-17-project-pattern-detection-design.md +0 -0
  75. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-05-19-claude-agents-live-integration-design.md +0 -0
  76. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-06-09-cross-agent-emit-design.md +0 -0
  77. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/docs/superpowers/specs/2026-06-19-otel-parser-design.md +0 -0
  78. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/__init__.py +0 -0
  79. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/conftest.py +0 -0
  80. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/__init__.py +0 -0
  81. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/conftest.py +0 -0
  82. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_dead_end.py +0 -0
  83. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_inflection.py +0 -0
  84. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_orchestrator.py +0 -0
  85. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_project_specific.py +0 -0
  86. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_retry_loop.py +0 -0
  87. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_scope_creep.py +0 -0
  88. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_stale_context.py +0 -0
  89. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/diagnostician/test_tool_thrash.py +0 -0
  90. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/exporters/__init__.py +0 -0
  91. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/exporters/test_csv.py +0 -0
  92. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/exporters/test_jsonl.py +0 -0
  93. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/README.md +0 -0
  94. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/short-clean/short-clean.jsonl +0 -0
  95. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a0b4c2cf1dde0ca56.meta.json +0 -0
  96. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a116ae34b1b09c332.meta.json +0 -0
  97. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a1c4c417b35658c9e.meta.json +0 -0
  98. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a1e41a901de38f1b5.meta.json +0 -0
  99. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a338f8d0c74612a24.meta.json +0 -0
  100. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a34f6f3c0e7094186.meta.json +0 -0
  101. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a5a5a0cff4d13308b.meta.json +0 -0
  102. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a6b0a3da6a0484db5.meta.json +0 -0
  103. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a7f73f1790b02cde5.meta.json +0 -0
  104. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a7f7c17c38a9d8788.meta.json +0 -0
  105. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a853259e2cd7bbe8a.meta.json +0 -0
  106. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-a8d9aedb0d0c6e12d.meta.json +0 -0
  107. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aa778bc1d59e4a441.meta.json +0 -0
  108. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aba869dedee4a12ba.meta.json +0 -0
  109. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-ada2746d9774b94db.meta.json +0 -0
  110. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aea0132068c64d2dd.meta.json +0 -0
  111. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-aea215eff50874d5f.meta.json +0 -0
  112. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments/subagents/agent-afee21f2b3852a4a0.meta.json +0 -0
  113. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-attachments/with-attachments.jsonl +0 -0
  114. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a051d9c9a6b2f5cc3.jsonl +0 -0
  115. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a051d9c9a6b2f5cc3.meta.json +0 -0
  116. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a171f16f4e65cfe75.jsonl +0 -0
  117. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a171f16f4e65cfe75.meta.json +0 -0
  118. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a1b77fea2c0a2269b.jsonl +0 -0
  119. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a1b77fea2c0a2269b.meta.json +0 -0
  120. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a20da4c01a54acca8.jsonl +0 -0
  121. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a20da4c01a54acca8.meta.json +0 -0
  122. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a3c82739b1383fb14.jsonl +0 -0
  123. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a3c82739b1383fb14.meta.json +0 -0
  124. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a49e8539611c5fe12.jsonl +0 -0
  125. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a49e8539611c5fe12.meta.json +0 -0
  126. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a7bb58f3fff2b3e8d.jsonl +0 -0
  127. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a7bb58f3fff2b3e8d.meta.json +0 -0
  128. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a92b48c0331195aac.jsonl +0 -0
  129. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-a92b48c0331195aac.meta.json +0 -0
  130. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ab96c4264099694a9.jsonl +0 -0
  131. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ab96c4264099694a9.meta.json +0 -0
  132. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-acb2895c5e34ffec0.jsonl +0 -0
  133. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-acb2895c5e34ffec0.meta.json +0 -0
  134. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-adb2302769938fb3f.jsonl +0 -0
  135. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-adb2302769938fb3f.meta.json +0 -0
  136. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ae585eca15cb93b9c.jsonl +0 -0
  137. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-ae585eca15cb93b9c.meta.json +0 -0
  138. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-aec9c917feb903d67.jsonl +0 -0
  139. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction/subagents/agent-aec9c917feb903d67.meta.json +0 -0
  140. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-compaction/with-compaction.jsonl +0 -0
  141. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-a1a3a21aeb76bb0a9.jsonl +0 -0
  142. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-a1a3a21aeb76bb0a9.meta.json +0 -0
  143. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-aaa1d6ecc05a78442.jsonl +0 -0
  144. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-aaa1d6ecc05a78442.meta.json +0 -0
  145. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-af3c545ccd30036d2.jsonl +0 -0
  146. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/subagents/agent-af3c545ccd30036d2.meta.json +0 -0
  147. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/tool-results/btwp2bzro.txt +0 -0
  148. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents/tool-results/byqjbgy4b.txt +0 -0
  149. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-subagents/with-subagents.jsonl +0 -0
  150. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-tool-results/with-tool-results/tool-results/bosbkda0h.txt +0 -0
  151. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/claude_code/with-tool-results/with-tool-results.jsonl +0 -0
  152. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/otel_fanout.jsonl +0 -0
  153. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/otel_handoff.jsonl +0 -0
  154. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/scrub.py +0 -0
  155. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/synthetic/bookkeeping_only.jsonl +0 -0
  156. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/synthetic/malformed_middle.jsonl +0 -0
  157. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/synthetic/truncated_final_line.jsonl +0 -0
  158. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/synthetic/unknown_attachment_shape.jsonl +0 -0
  159. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/fixtures/synthetic/unknown_type.jsonl +0 -0
  160. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/parsers/__init__.py +0 -0
  161. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/parsers/test_claude_code.py +0 -0
  162. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/parsers/test_claude_code_integration.py +0 -0
  163. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/recommender/__init__.py +0 -0
  164. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/recommender/test_claude_md.py +0 -0
  165. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/recommender/test_evidence.py +0 -0
  166. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/renderers/__init__.py +0 -0
  167. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/renderers/test_report.py +0 -0
  168. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/renderers/test_terminal_renderer_full.py +0 -0
  169. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_agents.py +0 -0
  170. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_aggregate.py +0 -0
  171. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_cli.py +0 -0
  172. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_cli_export.py +0 -0
  173. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_diagnostician_subagents.py +0 -0
  174. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_discovery.py +0 -0
  175. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_efficacy.py +0 -0
  176. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_fanout_classifier.py +0 -0
  177. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_github_summary.py +0 -0
  178. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_harvest.py +0 -0
  179. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_harvest_check.py +0 -0
  180. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_init.py +0 -0
  181. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_models.py +0 -0
  182. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_models_project_pattern.py +0 -0
  183. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_otel_parser.py +0 -0
  184. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_recommender.py +0 -0
  185. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_smoke.py +0 -0
  186. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_terminal_renderer.py +0 -0
  187. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_tokenizer.py +0 -0
  188. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_trace_tui.py +0 -0
  189. {cctx_cli-1.12.1 → cctx_cli-1.13.0}/tests/test_watcher.py +0 -0
@@ -2,6 +2,21 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.13.0 (2026-06-20)
6
+
7
+ ### Documentation
8
+
9
+ - OTEL quickstart for LangGraph + README multi-framework callout
10
+ ([#119](https://github.com/jacquardlabs/cctx/pull/119),
11
+ [`98d89d9`](https://github.com/jacquardlabs/cctx/commit/98d89d9fbf882021f0f54eb7f6676ceb3fbc8ca0))
12
+
13
+ ### Features
14
+
15
+ - KV-cache hygiene diagnosis — hit rate + cause (#96)
16
+ ([#121](https://github.com/jacquardlabs/cctx/pull/121),
17
+ [`2a3f49c`](https://github.com/jacquardlabs/cctx/commit/2a3f49cc253d3aacda1cde987138f19518537b89))
18
+
19
+
5
20
  ## v1.12.1 (2026-06-20)
6
21
 
7
22
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cctx-cli
3
- Version: 1.12.1
3
+ Version: 1.13.0
4
4
  Summary: Diagnose Claude Code sessions — find what went wrong, what it cost, and what to add to CLAUDE.md
5
5
  Author: Jacquard Labs
6
6
  License-Expression: MIT
@@ -20,7 +20,7 @@ Description-Content-Type: text/markdown
20
20
 
21
21
  # cctx
22
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.
23
+ Diagnose your Claude Code sessions and OpenTelemetry agent traces — 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
24
 
25
25
  [![CI](https://github.com/jacquardlabs/cctx/actions/workflows/ci.yml/badge.svg)](https://github.com/jacquardlabs/cctx/actions/workflows/ci.yml)
26
26
  [![PyPI](https://img.shields.io/pypi/v/cctx-cli)](https://pypi.org/project/cctx-cli/)
@@ -53,6 +53,8 @@ cctx watch # live signals during an active session
53
53
 
54
54
  cctx is primarily 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. `cctx watch` runs during a session and surfaces patterns as they happen. It reads the JSONL logs Claude Code writes to `~/.claude/projects/` and produces findings with attributed cost and copy-pasteable `CLAUDE.md` patches.
55
55
 
56
+ cctx also diagnoses OTEL traces from the OpenAI Agents SDK, LangGraph, and any framework that emits `gen_ai.*` semantic convention spans — auto-detected, no flags needed. See [Diagnosing other agent frameworks](docs/quickstart-otel.md).
57
+
56
58
  ## Commands
57
59
 
58
60
  ### `cctx ls` — list projects and sessions
@@ -76,10 +78,15 @@ cctx autopsy ~/Projects/myapp --since 7
76
78
 
77
79
  # Write a self-contained HTML report
78
80
  cctx autopsy ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --html report.html
81
+
82
+ # OTEL trace from OpenAI Agents SDK, LangGraph, or any gen_ai.*-instrumented framework
83
+ cctx autopsy agent_trace.jsonl
79
84
  ```
80
85
 
81
86
  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.
82
87
 
88
+ OTEL traces are auto-detected — cctx sniffs the file format and routes to the right parser. See [docs/quickstart-otel.md](docs/quickstart-otel.md) for how to wire the OTEL exporter in each framework.
89
+
83
90
  ### `cctx harvest` — apply patches to CLAUDE.md
84
91
 
85
92
  ```bash
@@ -1,6 +1,6 @@
1
1
  # cctx
2
2
 
3
- 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.
3
+ Diagnose your Claude Code sessions and OpenTelemetry agent traces — 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.
4
4
 
5
5
  [![CI](https://github.com/jacquardlabs/cctx/actions/workflows/ci.yml/badge.svg)](https://github.com/jacquardlabs/cctx/actions/workflows/ci.yml)
6
6
  [![PyPI](https://img.shields.io/pypi/v/cctx-cli)](https://pypi.org/project/cctx-cli/)
@@ -33,6 +33,8 @@ cctx watch # live signals during an active session
33
33
 
34
34
  cctx is primarily 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. `cctx watch` runs during a session and surfaces patterns as they happen. It reads the JSONL logs Claude Code writes to `~/.claude/projects/` and produces findings with attributed cost and copy-pasteable `CLAUDE.md` patches.
35
35
 
36
+ cctx also diagnoses OTEL traces from the OpenAI Agents SDK, LangGraph, and any framework that emits `gen_ai.*` semantic convention spans — auto-detected, no flags needed. See [Diagnosing other agent frameworks](docs/quickstart-otel.md).
37
+
36
38
  ## Commands
37
39
 
38
40
  ### `cctx ls` — list projects and sessions
@@ -56,10 +58,15 @@ cctx autopsy ~/Projects/myapp --since 7
56
58
 
57
59
  # Write a self-contained HTML report
58
60
  cctx autopsy ~/.claude/projects/-Users-you-Projects-myapp/abc123.jsonl --html report.html
61
+
62
+ # OTEL trace from OpenAI Agents SDK, LangGraph, or any gen_ai.*-instrumented framework
63
+ cctx autopsy agent_trace.jsonl
59
64
  ```
60
65
 
61
66
  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.
62
67
 
68
+ OTEL traces are auto-detected — cctx sniffs the file format and routes to the right parser. See [docs/quickstart-otel.md](docs/quickstart-otel.md) for how to wire the OTEL exporter in each framework.
69
+
63
70
  ### `cctx harvest` — apply patches to CLAUDE.md
64
71
 
65
72
  ```bash
@@ -1,3 +1,3 @@
1
1
  """cctx: profile, debug, and optimize Claude Code and Agent SDK sessions."""
2
2
 
3
- __version__ = "1.12.1"
3
+ __version__ = "1.13.0"
@@ -15,6 +15,7 @@ from typing import TYPE_CHECKING
15
15
 
16
16
  from cctx.diagnostician import inflection
17
17
  from cctx.diagnostician.patterns import (
18
+ cache_hygiene,
18
19
  dead_end,
19
20
  fan_out,
20
21
  retry_loop,
@@ -152,6 +153,7 @@ def run(trace: SessionTrace) -> Diagnosis:
152
153
  *tool_thrash.classify(trace),
153
154
  *dead_end.classify(trace),
154
155
  *fan_out.classify(trace),
156
+ *cache_hygiene.classify(trace),
155
157
  ]
156
158
  findings.sort(key=lambda f: f.first_turn)
157
159
 
@@ -0,0 +1,125 @@
1
+ """Cache-hygiene classifier.
2
+
3
+ Detects sessions with low KV-cache hit rates and identifies the likely cause
4
+ of the miss. A cache miss costs ~10× more than a cache hit on Sonnet
5
+ ($3/MTok vs $0.30/MTok), making this one of the highest-value findings.
6
+
7
+ Thresholds:
8
+ MIN_TOTAL_TOKENS = 5_000 — skip tiny sessions
9
+ HIT_RATE_THRESHOLD = 0.50 — below this → fire finding
10
+ HALF_DROP_THRESHOLD = 0.20 — early_rate - late_rate drop to flag as degrading
11
+ """
12
+ from __future__ import annotations
13
+
14
+ from typing import TYPE_CHECKING
15
+
16
+ from cctx.models import Confidence, Finding, FindingKind, Severity
17
+
18
+ if TYPE_CHECKING:
19
+ from cctx.models import SessionTrace, Turn
20
+
21
+ MIN_TOTAL_TOKENS = 5_000
22
+ HIT_RATE_THRESHOLD = 0.50
23
+ HALF_DROP_THRESHOLD = 0.20
24
+
25
+
26
+ def _hit_rate(turns: list[Turn]) -> float:
27
+ total_in = sum(
28
+ t.usage.input_tokens + t.usage.cache_read for t in turns if t.usage
29
+ )
30
+ total_cached = sum(t.usage.cache_read for t in turns if t.usage)
31
+ return total_cached / total_in if total_in > 0 else 0.0
32
+
33
+
34
+ def _detect_cause(trace: SessionTrace, assistant_turns: list[Turn]) -> str | None:
35
+ """Identify the most likely cause of low cache hit rate from JSONL signals."""
36
+ from cctx.diagnostician.patterns.stale_context import _is_compaction
37
+
38
+ # Compaction events invalidate the cache entirely.
39
+ compaction_turns = [t for t in trace.turns if _is_compaction(t)]
40
+ if compaction_turns:
41
+ return (
42
+ f"context compacted at turn {compaction_turns[0].turn_number}"
43
+ " (cache invalidated)"
44
+ )
45
+
46
+ # Many tools loaded means the tool-definition prefix is large and unstable.
47
+ if len(trace.tool_names_loaded) > 20:
48
+ return (
49
+ "large tool definition surface (>20 tools loaded)"
50
+ " reduces prefix stability"
51
+ )
52
+
53
+ # No cached tokens on turn 1 with a non-trivial prompt suggests the
54
+ # prompt prefix differs each session and cannot be cached.
55
+ if assistant_turns and assistant_turns[0].usage:
56
+ first = assistant_turns[0].usage
57
+ if first.cache_read == 0 and first.input_tokens > 1000:
58
+ return (
59
+ "no cached tokens on turn 1"
60
+ " — prompt prefix may not be stable across sessions"
61
+ )
62
+
63
+ return None
64
+
65
+
66
+ def _classify_impl(trace: SessionTrace) -> list[Finding]:
67
+ assistant_turns = [t for t in trace.turns if t.role == "assistant" and t.usage]
68
+ if not assistant_turns:
69
+ return []
70
+
71
+ total_tokens = sum(
72
+ t.usage.input_tokens + t.usage.cache_read for t in assistant_turns
73
+ )
74
+ if total_tokens < MIN_TOTAL_TOKENS:
75
+ return []
76
+
77
+ overall_rate = _hit_rate(assistant_turns)
78
+ if overall_rate >= HIT_RATE_THRESHOLD:
79
+ return []
80
+
81
+ # Split into halves to detect in-session degradation.
82
+ mid = len(assistant_turns) // 2
83
+ early_rate = _hit_rate(assistant_turns[:mid]) if mid > 0 else overall_rate
84
+ late_rate = (
85
+ _hit_rate(assistant_turns[mid:]) if mid < len(assistant_turns) else overall_rate
86
+ )
87
+
88
+ cause = _detect_cause(trace, assistant_turns)
89
+ severity = Severity.HIGH if overall_rate < 0.25 else Severity.MEDIUM
90
+ degrading = early_rate - late_rate > HALF_DROP_THRESHOLD
91
+
92
+ summary_parts = [f"cache hit rate {overall_rate:.0%}"]
93
+ if degrading:
94
+ summary_parts.append(
95
+ f"degraded from {early_rate:.0%} (first half)"
96
+ f" to {late_rate:.0%} (second half)"
97
+ )
98
+ if cause:
99
+ summary_parts.append(cause)
100
+
101
+ return [
102
+ Finding(
103
+ kind=FindingKind.CACHE_HYGIENE,
104
+ severity=severity,
105
+ confidence=Confidence.MEDIUM,
106
+ first_turn=assistant_turns[0].turn_number,
107
+ last_turn=assistant_turns[-1].turn_number,
108
+ evidence={
109
+ "overall_hit_rate": round(overall_rate, 3),
110
+ "early_hit_rate": round(early_rate, 3),
111
+ "late_hit_rate": round(late_rate, 3),
112
+ "total_tokens": total_tokens,
113
+ "cause": cause,
114
+ },
115
+ cost_usd=None,
116
+ summary="; ".join(summary_parts),
117
+ )
118
+ ]
119
+
120
+
121
+ def classify(trace: SessionTrace) -> list[Finding]:
122
+ try:
123
+ return _classify_impl(trace)
124
+ except Exception:
125
+ return []
@@ -174,6 +174,7 @@ class FindingKind(str, Enum):
174
174
  DEAD_END = "dead_end"
175
175
  FANOUT_WASTE = "fanout_waste"
176
176
  PROJECT_PATTERN = "project_pattern"
177
+ CACHE_HYGIENE = "cache_hygiene"
177
178
 
178
179
 
179
180
  KIND_LABEL: dict[FindingKind, str] = {
@@ -184,6 +185,7 @@ KIND_LABEL: dict[FindingKind, str] = {
184
185
  FindingKind.DEAD_END: "DEAD END",
185
186
  FindingKind.FANOUT_WASTE: "FANOUT WASTE",
186
187
  FindingKind.PROJECT_PATTERN: "PROJECT PATTERN",
188
+ FindingKind.CACHE_HYGIENE: "CACHE HYGIENE",
187
189
  }
188
190
 
189
191
  # Maps FindingKind to the exact ## heading emitted by its recommender patch
@@ -197,6 +199,7 @@ MANAGED_HEADINGS: dict[FindingKind, str] = {
197
199
  FindingKind.TOOL_THRASH: "## Tool-call discipline",
198
200
  FindingKind.DEAD_END: "## Exploration discipline",
199
201
  FindingKind.FANOUT_WASTE: "## Fan-out discipline",
202
+ FindingKind.CACHE_HYGIENE: "## Cache hygiene",
200
203
  }
201
204
 
202
205
  # Project-specific patterns use a heading that embeds tool+key, so the managed
@@ -66,6 +66,16 @@ _FANOUT_WASTE_DIFF = """\
66
66
  +after changing something meaningful about the task — identical re-spawns waste
67
67
  +the full subagent cost with no new information."""
68
68
 
69
+ _CACHE_HYGIENE_DIFF = """\
70
+ +## Cache hygiene
71
+ +
72
+ +Keep the prompt prefix stable across turns so Claude's KV-cache can be reused.
73
+ +Avoid changing tool definitions mid-session, keep system prompt content
74
+ +consistent, and prefer append-only context updates over rewrites. If context
75
+ +compaction fires frequently, consider splitting long sessions into shorter ones
76
+ +with a stable, cacheable preamble. A 10× cost difference separates a warm
77
+ +cache hit from a cold input read."""
78
+
69
79
  _TEMPLATES: dict[FindingKind, tuple[str, str, str]] = {
70
80
  # kind → (description, diff_body, target_file)
71
81
  FindingKind.RETRY_LOOP: ("Add retry discipline rule", _RETRY_LOOP_DIFF, "CLAUDE.md"),
@@ -74,6 +84,7 @@ _TEMPLATES: dict[FindingKind, tuple[str, str, str]] = {
74
84
  FindingKind.TOOL_THRASH: ("Add tool-call discipline rule", _TOOL_THRASH_DIFF, "CLAUDE.md"),
75
85
  FindingKind.DEAD_END: ("Add exploration discipline rule", _DEAD_END_DIFF, "CLAUDE.md"),
76
86
  FindingKind.FANOUT_WASTE: ("Add fan-out discipline rule", _FANOUT_WASTE_DIFF, "CLAUDE.md"),
87
+ FindingKind.CACHE_HYGIENE: ("Add cache hygiene rule", _CACHE_HYGIENE_DIFF, "CLAUDE.md"),
77
88
  }
78
89
 
79
90
 
@@ -1,14 +1,20 @@
1
- # Using cctx with the OpenAI Agents SDK
1
+ # Diagnosing other agent frameworks with cctx
2
2
 
3
- cctx diagnoses OpenAI Agents SDK runs the same way it diagnoses Claude Code sessions point it at a trace file and get an autopsy.
3
+ cctx diagnoses any agent framework that writes OpenTelemetry spans using `gen_ai.*` semantic conventions — the same way it diagnoses Claude Code sessions. Point it at a trace file and get an autopsy.
4
4
 
5
- ## 1. Install dependencies
5
+ **Verified frameworks:** OpenAI Agents SDK, LangGraph
6
+
7
+ ---
8
+
9
+ ## OpenAI Agents SDK
10
+
11
+ ### 1. Install dependencies
6
12
 
7
13
  ```bash
8
- pip install cctx opentelemetry-sdk
14
+ pip install cctx-cli opentelemetry-sdk
9
15
  ```
10
16
 
11
- ## 2. Export traces to a local file
17
+ ### 2. Export traces to a local file
12
18
 
13
19
  Add this to your agent script before running your agent. It configures OpenTelemetry to write spans to a local JSONL file.
14
20
 
@@ -84,14 +90,14 @@ provider.add_span_processor(BatchSpanProcessor(FileSpanExporter("agent_trace.jso
84
90
  # set_trace_processors([...])
85
91
  ```
86
92
 
87
- ## 3. Run your agent
93
+ ### 3. Run your agent
88
94
 
89
95
  ```bash
90
96
  python my_agent.py
91
97
  # agent_trace.jsonl is written
92
98
  ```
93
99
 
94
- ## 4. Diagnose the run
100
+ ### 4. Diagnose the run
95
101
 
96
102
  ```bash
97
103
  cctx autopsy agent_trace.jsonl
@@ -99,8 +105,71 @@ cctx autopsy agent_trace.jsonl
99
105
 
100
106
  `cctx autopsy` picks up the OTLP format automatically — no flags needed.
101
107
 
102
- ## Notes
108
+ ### Notes
103
109
 
104
110
  - If your trace file contains multiple runs, cctx diagnoses the first trace by trace ID.
105
111
  - Token costs shown in the autopsy are estimates; cctx does not call the OpenAI API.
106
112
  - The exact `set_trace_processors` API varies by SDK version — check the `openai-agents` changelog if the import above doesn't work.
113
+
114
+ ---
115
+
116
+ ## LangGraph
117
+
118
+ LangGraph emits `gen_ai.*` spans via the `opentelemetry-instrumentation-langchain` package from Traceloop. Pair it with the same `FileSpanExporter` above to write traces cctx can read.
119
+
120
+ ### 1. Install dependencies
121
+
122
+ ```bash
123
+ pip install cctx-cli opentelemetry-sdk opentelemetry-instrumentation-langchain
124
+ ```
125
+
126
+ ### 2. Export traces to a local file
127
+
128
+ Copy the `FileSpanExporter` and `_otlp_value` definitions from the OpenAI Agents SDK section above, then add the LangChain instrumentor before your graph runs:
129
+
130
+ ```python
131
+ from opentelemetry.sdk.trace import TracerProvider
132
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
133
+ from opentelemetry.instrumentation.langchain import LangchainInstrumentor
134
+
135
+ provider = TracerProvider()
136
+ provider.add_span_processor(BatchSpanProcessor(FileSpanExporter("agent_trace.jsonl")))
137
+
138
+ LangchainInstrumentor().instrument(tracer_provider=provider)
139
+ ```
140
+
141
+ ### 3. Run your graph
142
+
143
+ ```python
144
+ from langgraph.graph import StateGraph, END
145
+ # ... build graph ...
146
+
147
+ result = graph.invoke({"messages": [HumanMessage(content="...")]})
148
+ # agent_trace.jsonl is written
149
+ ```
150
+
151
+ ### 4. Diagnose the run
152
+
153
+ ```bash
154
+ cctx autopsy agent_trace.jsonl
155
+ ```
156
+
157
+ ### Notes
158
+
159
+ - `opentelemetry-instrumentation-langchain` is maintained by [Traceloop](https://github.com/traceloop/openllmetry). It emits `gen_ai.usage.input_tokens`, `gen_ai.request.model`, and other attributes cctx maps to its canonical model.
160
+ - LangGraph's `recursion_limit` (default 25) governs step count, not agent nesting depth. cctx handles arbitrary span depth.
161
+ - Token costs are estimates; cctx does not call the OpenAI or Anthropic APIs during analysis.
162
+
163
+ ---
164
+
165
+ ## Other frameworks
166
+
167
+ Any framework instrumented with `gen_ai.*` semantic conventions works. The minimum attributes cctx needs per span:
168
+
169
+ | Span type | Required attributes |
170
+ |---|---|
171
+ | Agent span (`run_agent`) | `gen_ai.operation.name = "run_agent"` |
172
+ | LLM call (`chat`) | `gen_ai.operation.name = "chat"`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.request.model` |
173
+ | Tool call (`invoke_function`) | `gen_ai.operation.name = "invoke_function"`, `gen_ai.tool.name` |
174
+
175
+ Spans are linked via `parentSpanId`. Use the `FileSpanExporter` above (or any OTLP JSON exporter that writes one `resourceSpans` batch per line) to produce a file cctx can read.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cctx-cli"
7
- version = "1.12.1"
7
+ version = "1.13.0"
8
8
  description = "Diagnose Claude Code sessions — find what went wrong, what it cost, and what to add to CLAUDE.md"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"