stacktrace-cli 0.3.1__tar.gz → 0.4.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 (315) hide show
  1. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.agents/skills/release-stacktrace/SKILL.md +18 -13
  2. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.github/workflows/claude.yml +10 -0
  3. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/PKG-INFO +56 -24
  4. stacktrace_cli-0.4.0/README.md +160 -0
  5. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0004-three-stage-detector.md +1 -1
  6. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0006-trust-boundary-and-detection-upload.md +1 -1
  7. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0011-verdict-cache.md +1 -0
  8. stacktrace_cli-0.4.0/docs/adrs/0030-a-detection-is-dated-by-the-turns-it-cites.md +104 -0
  9. stacktrace_cli-0.4.0/docs/adrs/0031-one-host-daemon-observes-native-session-logs.md +115 -0
  10. stacktrace_cli-0.4.0/docs/adrs/0032-refresh-daemon-compositions-outside-detection.md +89 -0
  11. stacktrace_cli-0.4.0/docs/adrs/0033-a-third-party-analyzer-only-by-a-flag-that-names-it.md +119 -0
  12. stacktrace_cli-0.4.0/docs/adrs/0034-the-drift-grade-is-read-off-a-run-not-a-call.md +138 -0
  13. stacktrace_cli-0.4.0/docs/adrs/0035-naming-an-analyzer-selects-stored-answers.md +88 -0
  14. stacktrace_cli-0.4.0/docs/adrs/0036-deliver-eligible-findings-to-slack-from-the-daemon.md +495 -0
  15. stacktrace_cli-0.4.0/docs/adrs/0037-reuse-openaidr-append-cursors-in-the-daemon.md +94 -0
  16. stacktrace_cli-0.4.0/docs/adrs/0038-poll-normalized-sessions-for-supplemental-changes.md +82 -0
  17. stacktrace_cli-0.4.0/docs/adrs/0039-send-usage-telemetry-by-default-with-an-opt-out.md +231 -0
  18. stacktrace_cli-0.4.0/docs/adrs/0041-defer-native-windows-support.md +71 -0
  19. stacktrace_cli-0.4.0/docs/adrs/0042-read-the-build-commit-from-the-install-record.md +72 -0
  20. stacktrace_cli-0.4.0/docs/adrs/0043-name-the-session-agent-and-host-and-count-errors-by-class.md +144 -0
  21. stacktrace_cli-0.4.0/docs/adrs/0044-send-the-build-as-version-prints-it.md +62 -0
  22. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/INDEX.md +19 -1
  23. stacktrace_cli-0.4.0/docs/plans/009-reasoning-jev.md +3439 -0
  24. stacktrace_cli-0.4.0/docs/plans/010-session-daemon.md +16 -0
  25. stacktrace_cli-0.4.0/docs/releases/v0.4.0.md +204 -0
  26. stacktrace_cli-0.4.0/docs/research/001-intent-drift-metric.md +313 -0
  27. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/aidr.md +32 -16
  28. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/detection-upload.md +18 -18
  29. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/detector.md +131 -170
  30. stacktrace_cli-0.4.0/docs/specs/event-time.md +174 -0
  31. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/monitor.md +160 -47
  32. stacktrace_cli-0.4.0/docs/specs/notification-delivery.md +235 -0
  33. stacktrace_cli-0.4.0/docs/specs/reasoning-jev.md +445 -0
  34. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/session-input.md +5 -3
  35. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/pyproject.toml +13 -5
  36. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/__init__.py +1 -1
  37. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/analysis.py +202 -20
  38. stacktrace_cli-0.4.0/src/stacktrace_cli/build.py +130 -0
  39. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/cli.py +137 -55
  40. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/acquire.py +23 -2
  41. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/orchestrate.py +73 -9
  42. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/render.py +7 -5
  43. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/__init__.py +1 -0
  44. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/cli.py +106 -0
  45. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/client.py +134 -0
  46. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/composition.py +133 -0
  47. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/observer.py +173 -0
  48. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/paths.py +35 -0
  49. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/protocol.py +29 -0
  50. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/runtime.py +222 -0
  51. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/server.py +164 -0
  52. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/service.py +154 -0
  53. stacktrace_cli-0.4.0/src/stacktrace_cli/daemon/store.py +368 -0
  54. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/blocked.py +450 -0
  55. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/cache.py +245 -9
  56. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/deterministic.py +502 -0
  57. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/finding.py +163 -15
  58. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/history.py +210 -0
  59. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/jev.py +213 -0
  60. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/priors.py +270 -0
  61. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/prompts/__init__.py +20 -0
  62. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/prompts/jev-v1/stacktrace-deceptive-completion.json +16 -0
  63. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/prompts/jev-v2/stacktrace-deceptive-completion.json +16 -0
  64. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/reasoning.py +1741 -0
  65. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/render.py +88 -7
  66. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/rules.py +69 -56
  67. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/run.py +423 -77
  68. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/secrets.py +8 -6
  69. stacktrace_cli-0.4.0/src/stacktrace_cli/detector/windows.py +293 -0
  70. stacktrace_cli-0.4.0/src/stacktrace_cli/monitor/reasoning.py +304 -0
  71. stacktrace_cli-0.4.0/src/stacktrace_cli/monitor/render.py +667 -0
  72. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/server.py +242 -21
  73. stacktrace_cli-0.4.0/src/stacktrace_cli/monitor/site/app.js +2023 -0
  74. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/site/index.html +16 -1
  75. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/site/styles.css +89 -1
  76. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/state.py +27 -1
  77. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/watch.py +227 -47
  78. stacktrace_cli-0.4.0/src/stacktrace_cli/options.py +107 -0
  79. stacktrace_cli-0.4.0/src/stacktrace_cli/private_state.py +38 -0
  80. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/cli.py +20 -10
  81. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/detect_payload.py +37 -5
  82. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/redact.py +3 -3
  83. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/spool.py +3 -2
  84. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/sync_detect.py +15 -1
  85. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/upload_contract.py +7 -0
  86. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/sessions/access.py +24 -0
  87. stacktrace_cli-0.4.0/src/stacktrace_cli/sessions/index.py +30 -0
  88. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/sessions/protocols.py +13 -0
  89. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/sessions/render.py +15 -9
  90. stacktrace_cli-0.4.0/src/stacktrace_cli/telemetry/__init__.py +11 -0
  91. stacktrace_cli-0.4.0/src/stacktrace_cli/telemetry/cli.py +67 -0
  92. stacktrace_cli-0.4.0/src/stacktrace_cli/telemetry/events.py +266 -0
  93. stacktrace_cli-0.4.0/src/stacktrace_cli/telemetry/posthog.py +126 -0
  94. stacktrace_cli-0.4.0/src/stacktrace_cli/telemetry/state.py +190 -0
  95. stacktrace_cli-0.4.0/tests/conftest.py +87 -0
  96. stacktrace_cli-0.4.0/tests/daemon/__init__.py +1 -0
  97. stacktrace_cli-0.4.0/tests/daemon/test_cli.py +124 -0
  98. stacktrace_cli-0.4.0/tests/daemon/test_client.py +136 -0
  99. stacktrace_cli-0.4.0/tests/daemon/test_composition.py +158 -0
  100. stacktrace_cli-0.4.0/tests/daemon/test_observer.py +407 -0
  101. stacktrace_cli-0.4.0/tests/daemon/test_runtime.py +411 -0
  102. stacktrace_cli-0.4.0/tests/daemon/test_service.py +227 -0
  103. stacktrace_cli-0.4.0/tests/daemon/test_socket.py +183 -0
  104. stacktrace_cli-0.4.0/tests/daemon/test_store.py +188 -0
  105. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/detector_session_fixture.py +17 -0
  106. stacktrace_cli-0.4.0/tests/monitor/feed_harness.mjs +1894 -0
  107. stacktrace_cli-0.4.0/tests/monitor/test_feed_model.py +1192 -0
  108. stacktrace_cli-0.4.0/tests/monitor/test_reasoning_gates.py +686 -0
  109. stacktrace_cli-0.4.0/tests/monitor/test_render.py +1015 -0
  110. stacktrace_cli-0.4.0/tests/monitor/test_server.py +796 -0
  111. stacktrace_cli-0.4.0/tests/monitor/test_site_assets.py +372 -0
  112. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/monitor/test_verdicts.py +14 -15
  113. stacktrace_cli-0.4.0/tests/monitor/test_watch.py +1124 -0
  114. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_activity.py +56 -4
  115. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_contract_is_exhaustive.py +4 -1
  116. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_layers_compose.py +4 -41
  117. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_seam.py +11 -3
  118. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_spool.py +1 -0
  119. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_sync_detect.py +19 -18
  120. stacktrace_cli-0.4.0/tests/telemetry/__init__.py +0 -0
  121. stacktrace_cli-0.4.0/tests/telemetry/test_cli.py +148 -0
  122. stacktrace_cli-0.4.0/tests/telemetry/test_events.py +344 -0
  123. stacktrace_cli-0.4.0/tests/telemetry/test_hooks.py +414 -0
  124. stacktrace_cli-0.4.0/tests/telemetry/test_release_gate.py +14 -0
  125. stacktrace_cli-0.4.0/tests/telemetry/test_state.py +150 -0
  126. stacktrace_cli-0.4.0/tests/telemetry/test_uploader.py +173 -0
  127. stacktrace_cli-0.4.0/tests/test_adr_cross_references_are_reciprocal.py +104 -0
  128. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_analysis.py +116 -8
  129. stacktrace_cli-0.4.0/tests/test_build_commit.py +244 -0
  130. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_call_status_conventions.py +64 -0
  131. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_cli.py +290 -40
  132. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_correlate_orchestrate.py +20 -0
  133. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_correlate_render.py +1 -0
  134. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detection_components.py +30 -30
  135. stacktrace_cli-0.4.0/tests/test_detection_event_time.py +245 -0
  136. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detection_subject.py +3 -93
  137. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_analyzer_live.py +20 -0
  138. stacktrace_cli-0.4.0/tests/test_detector_blocked.py +717 -0
  139. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_cache.py +482 -6
  140. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_deterministic.py +35 -87
  141. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_end_to_end.py +47 -40
  142. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_finding.py +109 -13
  143. stacktrace_cli-0.4.0/tests/test_detector_history.py +291 -0
  144. stacktrace_cli-0.4.0/tests/test_detector_jev.py +306 -0
  145. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_priors.py +103 -312
  146. stacktrace_cli-0.4.0/tests/test_detector_prompts.py +42 -0
  147. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_reasoning.py +714 -507
  148. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_render.py +117 -8
  149. stacktrace_cli-0.4.0/tests/test_detector_run.py +1358 -0
  150. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_verdict.py +17 -17
  151. stacktrace_cli-0.4.0/tests/test_detector_why_it_stopped.py +322 -0
  152. stacktrace_cli-0.4.0/tests/test_detector_windows.py +547 -0
  153. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_fingerprint_covers_what_the_analyzer_reads.py +37 -55
  154. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_monitor_cli.py +68 -0
  155. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_readme_examples_are_real_output.py +8 -1
  156. stacktrace_cli-0.4.0/tests/test_release_gate_coverage.py +58 -0
  157. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_release_readiness.py +18 -0
  158. stacktrace_cli-0.4.0/tests/test_session_identity_is_the_pair.py +340 -0
  159. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_sessions_access.py +18 -1
  160. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_sessions_render.py +65 -1
  161. stacktrace_cli-0.4.0/tests/test_the_detector_spec_lists_the_shipped_catalogue.py +72 -0
  162. stacktrace_cli-0.4.0/tests/test_the_jev_spec_states_the_shipped_thresholds.py +96 -0
  163. stacktrace_cli-0.4.0/tests/test_the_locality_claim_is_qualified_everywhere.py +115 -0
  164. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_untrusted_content_never_travels.py +164 -29
  165. stacktrace_cli-0.4.0/tests/test_what_jev_is_told_is_what_was_disclosed.py +322 -0
  166. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/uv.lock +215 -9
  167. stacktrace_cli-0.3.1/README.md +0 -130
  168. stacktrace_cli-0.3.1/src/stacktrace_cli/detector/deterministic.py +0 -654
  169. stacktrace_cli-0.3.1/src/stacktrace_cli/detector/markers.py +0 -158
  170. stacktrace_cli-0.3.1/src/stacktrace_cli/detector/priors.py +0 -502
  171. stacktrace_cli-0.3.1/src/stacktrace_cli/detector/prompts/v1/stacktrace-injected-instruction-followed.md +0 -14
  172. stacktrace_cli-0.3.1/src/stacktrace_cli/detector/prompts/v1/stacktrace-intent-drift.md +0 -11
  173. stacktrace_cli-0.3.1/src/stacktrace_cli/detector/reasoning.py +0 -1191
  174. stacktrace_cli-0.3.1/src/stacktrace_cli/monitor/reasoning.py +0 -172
  175. stacktrace_cli-0.3.1/src/stacktrace_cli/monitor/render.py +0 -256
  176. stacktrace_cli-0.3.1/src/stacktrace_cli/monitor/site/app.js +0 -1047
  177. stacktrace_cli-0.3.1/tests/monitor/feed_harness.mjs +0 -853
  178. stacktrace_cli-0.3.1/tests/monitor/test_feed_model.py +0 -508
  179. stacktrace_cli-0.3.1/tests/monitor/test_reasoning_gates.py +0 -400
  180. stacktrace_cli-0.3.1/tests/monitor/test_render.py +0 -363
  181. stacktrace_cli-0.3.1/tests/monitor/test_server.py +0 -413
  182. stacktrace_cli-0.3.1/tests/monitor/test_site_assets.py +0 -208
  183. stacktrace_cli-0.3.1/tests/monitor/test_watch.py +0 -607
  184. stacktrace_cli-0.3.1/tests/test_detector_liveness.py +0 -698
  185. stacktrace_cli-0.3.1/tests/test_detector_markers.py +0 -150
  186. stacktrace_cli-0.3.1/tests/test_detector_run.py +0 -854
  187. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.claude/settings.json +0 -0
  188. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.claude/skills/release-stacktrace/SKILL.md +0 -0
  189. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.codex/hooks.json +0 -0
  190. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.github/workflows/autofix.yml +0 -0
  191. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.github/workflows/ci.yml +0 -0
  192. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.github/workflows/publish-pypi.yml +0 -0
  193. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/.gitignore +0 -0
  194. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/AGENTS.md +0 -0
  195. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/CLAUDE.md +0 -0
  196. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0001-session-telemetry-as-input.md +0 -0
  197. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0002-session-collection-in-openaidr.md +0 -0
  198. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0003-runtime-edges.md +0 -0
  199. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0005-detection-family-and-report-assembly.md +0 -0
  200. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0007-proprietary-package-on-open-dependencies.md +0 -0
  201. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0008-console-in-separate-demo-package.md +0 -0
  202. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0010-detection-severity-and-confidence-ladders.md +0 -0
  203. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0012-observation-evidence-kinds-and-transport.md +0 -0
  204. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0013-rule-catalogue-triage-and-per-rule-context.md +0 -0
  205. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0014-declared-project-mapping.md +0 -0
  206. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0015-narrow-the-security-catalogue.md +0 -0
  207. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0016-stall-grouping-is-session-wide.md +0 -0
  208. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0017-a-declined-repeat-is-a-stall.md +0 -0
  209. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0018-remote-sync-config-and-facade-consumption.md +0 -0
  210. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0019-delegated-commands-are-openaca-objects.md +0 -0
  211. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0020-openaca-consumption-boundary.md +0 -0
  212. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0021-two-command-kinds.md +0 -0
  213. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0022-detection-scope-is-a-catalogue-column.md +0 -0
  214. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0023-sync-detect-collects-and-does-not-escalate.md +0 -0
  215. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0024-the-upload-carries-observations.md +0 -0
  216. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0025-a-denied-call-is-activity-never-an-invocation.md +0 -0
  217. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0026-the-console-becomes-a-product-surface.md +0 -0
  218. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0027-a-finding-may-name-what-it-could-not-place.md +0 -0
  219. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0028-the-console-shows-what-it-placed.md +0 -0
  220. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/0029-stage-three-returns-to-opt-in.md +0 -0
  221. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/HOOK-PROMPT.md +0 -0
  222. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/adrs/TEMPLATE.md +0 -0
  223. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/cutover-openaca-remote.md +0 -0
  224. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/plans/002-session-input.md +0 -0
  225. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/plans/003-correlation.md +0 -0
  226. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/plans/004-detector.md +0 -0
  227. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/plans/005-remote-sync.md +0 -0
  228. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/plans/006-cli-composition.md +0 -0
  229. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/plans/007-detection-upload.md +0 -0
  230. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/plans/008-monitor.md +0 -0
  231. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.0.1.md +0 -0
  232. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.1.0.md +0 -0
  233. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.2.0.md +0 -0
  234. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.2.1.md +0 -0
  235. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.2.2.md +0 -0
  236. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.2.3.md +0 -0
  237. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.3.0.md +0 -0
  238. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/releases/v0.3.1.md +0 -0
  239. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/cli-composition.md +0 -0
  240. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/correlation.md +0 -0
  241. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/docs/specs/remote-sync.md +0 -0
  242. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/scripts/git-hooks/pre-push +0 -0
  243. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/scripts/install-hooks.sh +0 -0
  244. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/__main__.py +0 -0
  245. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/__init__.py +0 -0
  246. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/composition.py +0 -0
  247. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/join.py +0 -0
  248. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/observed.py +0 -0
  249. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/project_map.py +0 -0
  250. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/correlate/record.py +0 -0
  251. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/__init__.py +0 -0
  252. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/analyzer.py +0 -0
  253. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/prompts/v1/exclusions.md +0 -0
  254. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/prompts/v1/framing.md +0 -0
  255. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/prompts/v1/stacktrace-deceptive-completion.md +0 -0
  256. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/detector/verdict.py +0 -0
  257. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/__init__.py +0 -0
  258. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/site/fonts/OFL.txt +0 -0
  259. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/site/fonts/dm-mono-400-latin.woff2 +0 -0
  260. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/site/fonts/dm-mono-500-latin.woff2 +0 -0
  261. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/site/fonts/dm-sans-latin.woff2 +0 -0
  262. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/monitor/verdicts.py +0 -0
  263. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/__init__.py +0 -0
  264. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/client.py +0 -0
  265. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/config.py +0 -0
  266. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/payload.py +0 -0
  267. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/policy.py +0 -0
  268. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/remote/sync.py +0 -0
  269. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/sessions/__init__.py +0 -0
  270. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/src/stacktrace_cli/sessions/outcome.py +0 -0
  271. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/__init__.py +0 -0
  272. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/agent_bom_fixture.py +0 -0
  273. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/monitor/__init__.py +0 -0
  274. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/monitor/test_state.py +0 -0
  275. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/__init__.py +0 -0
  276. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/helpers.py +0 -0
  277. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_cli.py +0 -0
  278. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_client.py +0 -0
  279. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_config.py +0 -0
  280. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_cli.py +0 -0
  281. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_client.py +0 -0
  282. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_gate_matches_the_cloud.py +0 -0
  283. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_payload_reaches_the_cloud_model.py +0 -0
  284. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_redaction.py +0 -0
  285. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_spool.py +0 -0
  286. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_upload_contract.py +0 -0
  287. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_detect_wire_payload.py +0 -0
  288. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_facade_contract.py +0 -0
  289. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_payload.py +0 -0
  290. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_policy.py +0 -0
  291. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_redact_payload.py +0 -0
  292. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_sync.py +0 -0
  293. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/remote/test_upload_contract.py +0 -0
  294. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_acquire.py +0 -0
  295. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_agent_instance_id.py +0 -0
  296. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_bom_shape.py +0 -0
  297. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_composition.py +0 -0
  298. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_correlated_session.py +0 -0
  299. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_analyzer_contract.py +0 -0
  300. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_detector_secrets.py +0 -0
  301. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_help_sections.py +0 -0
  302. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_join.py +0 -0
  303. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_no_live_document_states_the_old_stage_three_default.py +0 -0
  304. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_observed.py +0 -0
  305. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_openaca_contract.py +0 -0
  306. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_openaidr_contract.py +0 -0
  307. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_option_arity_matches_the_binary.py +0 -0
  308. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_project_map.py +0 -0
  309. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_seam_boundary.py +0 -0
  310. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_sessions_end_to_end.py +0 -0
  311. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_sessions_protocol_typing.py +0 -0
  312. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_sessions_protocols.py +0 -0
  313. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_shell_separators_match_the_shell.py +0 -0
  314. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_stored_verdicts_are_never_gated_on_reasoning.py +0 -0
  315. {stacktrace_cli-0.3.1 → stacktrace_cli-0.4.0}/tests/test_verification_subcommands_match_the_binary.py +0 -0
@@ -42,11 +42,12 @@ git rev-parse --verify "v<version>" 2>/dev/null # MUST FAIL — tag must not
42
42
  test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
43
43
  ```
44
44
 
45
- `tests/test_release_readiness.py -m release_gate` is **not** run here: it
46
- requires `openaca`/`openaidr` pinned exactly, which is not true of a normal
47
- checkout (both float on `>=` between releases) and is only made true by
48
- Step 4. Running it against an unpinned tree would fail on every release, not
49
- just a broken one. It runs at the end of Step 4, once its precondition holds.
45
+ The `release_gate` marker is **not** run here: `test_release_readiness.py`'s
46
+ share of it requires `openaca`/`openaidr` pinned exactly, which is not true of
47
+ a normal checkout (both float on `>=` between releases) and is only made true
48
+ by Step 4. Running it against an unpinned tree would fail on every release,
49
+ not just a broken one. It runs at the end of Step 4, once its precondition
50
+ holds.
50
51
 
51
52
  PyPI versions are immutable, including yanked ones. If `<version>` is
52
53
  already on PyPI, the only path forward is a new version number:
@@ -146,16 +147,20 @@ openaidr_version=$(grep -A1 '^name = "openaidr"' uv.lock | grep version | cut -d
146
147
  sed -i.bak -E "s/^ \"openaca(>=|==)[^\"]*\"/ \"openaca==${openaca_version}\"/" pyproject.toml && rm pyproject.toml.bak
147
148
  sed -i.bak -E "s/^ \"openaidr(>=|==)[^\"]*\"/ \"openaidr==${openaidr_version}\"/" pyproject.toml && rm pyproject.toml.bak
148
149
  uv lock # refresh uv.lock for the exact pin
149
- uv run pytest tests/test_release_readiness.py -m release_gate
150
+ uv run pytest -m release_gate
150
151
  ```
151
152
 
152
- The gate is not covered by `.github/workflows/publish-pypi.yml`, which runs
153
- the default `uv run pytest -q` — and `pyproject.toml`'s `addopts` excludes
154
- `release_gate` from that default run on purpose (it fails throughout normal
155
- development, before this step pins the floors). This skill is the only place
156
- it runs before a tag is pushed, so skipping it here is the one way a version
157
- with an unpinned `openaidr`/`openaca` requirement reaches PyPI. Stop and ask
158
- if it fails.
153
+ By marker, not by file: a second `release_gate` test can be added anywhere
154
+ under `tests/` (as `tests/telemetry/test_release_gate.py` was, checking that
155
+ PostHog's project key is set) and this command picks it up without the skill
156
+ needing to name it. The gate is not covered by `.github/workflows/publish-pypi.yml`,
157
+ which runs the default `uv run pytest -q` — and `pyproject.toml`'s `addopts`
158
+ excludes `release_gate` from that default run on purpose (it fails throughout
159
+ normal development, before this step pins the floors and, for the PostHog key,
160
+ before Micheal fills it in). This skill is the only place any `release_gate`
161
+ test runs before a tag is pushed, so skipping it here, or naming only one file
162
+ here, is the one way an unpinned `openaidr`/`openaca` requirement or an unset
163
+ PostHog key reaches PyPI. Stop and ask if it fails.
159
164
 
160
165
  ### Step 5. Release-prep commit + PR
161
166
 
@@ -99,6 +99,16 @@ jobs:
99
99
  id: claude
100
100
  uses: anthropics/claude-code-action@v1
101
101
  with:
102
+ # Keep pre-push checks attached to the session until they finish.
103
+ # Background pushes can be abandoned when the model ends its turn.
104
+ settings: |
105
+ {
106
+ "env": {
107
+ "CLAUDE_CODE_DISABLE_BACKGROUND_TASKS": "1",
108
+ "BASH_DEFAULT_TIMEOUT_MS": "600000"
109
+ }
110
+ }
111
+
102
112
  # Subscription-tied OAuth path. Provision via `claude setup-token`
103
113
  # CLI and store as the CLAUDE_CODE_OAUTH_TOKEN repo secret.
104
114
  #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: stacktrace-cli
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: CLI for Stacktrace — Detection and Response platform for AI Agents.
5
5
  Project-URL: Homepage, https://stacktrace.ai
6
6
  Author-email: "Stacktrace AI, Inc" <founders@stacktrace.ai>
@@ -10,7 +10,8 @@ Classifier: Development Status :: 4 - Beta
10
10
  Classifier: Environment :: Console
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: Other/Proprietary License
13
- Classifier: Operating System :: OS Independent
13
+ Classifier: Operating System :: MacOS
14
+ Classifier: Operating System :: POSIX :: Linux
14
15
  Classifier: Programming Language :: Python :: 3
15
16
  Classifier: Programming Language :: Python :: 3.11
16
17
  Classifier: Programming Language :: Python :: 3.12
@@ -19,8 +20,9 @@ Classifier: Topic :: Security
19
20
  Requires-Python: >=3.11
20
21
  Requires-Dist: click>=8.1
21
22
  Requires-Dist: httpx<1.0.dev0,>=0.28.1
22
- Requires-Dist: openaca==0.6.0
23
- Requires-Dist: openaidr==0.1.0
23
+ Requires-Dist: openaca==0.7.0
24
+ Requires-Dist: openaidr==0.3.0
25
+ Requires-Dist: posthog<8,>=7.0
24
26
  Description-Content-Type: text/markdown
25
27
 
26
28
  # stacktrace-cli
@@ -49,7 +51,7 @@ Requires Python 3.11 or newer.
49
51
 
50
52
  ```console
51
53
  $ stacktrace --version
52
- stacktrace 0.3.1 (openaca 0.6.0)
54
+ stacktrace 0.4.0 (openaca 0.7.0)
53
55
  ```
54
56
 
55
57
  ## Quick start
@@ -81,10 +83,10 @@ name.
81
83
  ```console
82
84
  $ stacktrace sessions --since 2d --include-content
83
85
  claude-code:s1 [claude-code] 2026-08-27T09:00:00+00:00 2 turns 2 calls
84
- assistant: Reading the changelog before drafting the release notes.
86
+ 2026-08-29T12:00:00+00:00 assistant: Reading the changelog before drafting the release notes.
85
87
  ok 28c Read
86
88
  result: ## 0.4.0 - correlate, detect
87
- assistant: Filing the release-notes follow-up.
89
+ 2026-08-29T12:00:00+00:00 assistant: Filing the release-notes follow-up.
88
90
  - github/create_issue
89
91
 
90
92
  Summary — 1 sessions, 2 turns, 2 tool calls
@@ -110,31 +112,61 @@ counts those rather than filling one in.
110
112
 
111
113
  ## What `detect` finds
112
114
 
113
- Four kinds of finding, under two families that carry separate severity
114
- ladders — a stalled loop and a leaked credential do not belong on one scale.
115
+ Three kinds of finding, under two families that carry separate severity
116
+ ladders — a blocked agent and a leaked credential do not belong on one scale.
115
117
 
116
- **Security** — a credential reaching an outbound call; an injected instruction
117
- the agent then followed; a vulnerable component actually reached, with the
118
- vulnerability behind it.
118
+ **Security** — a credential reaching an outbound call; success reported against
119
+ the session's own evidence of failure.
119
120
 
120
- **Reliability** — a loop that stalled; a call that hung.
121
+ **Reliability** — why the agent stopped, in words, with what to do about it: a
122
+ spend limit reached, a safety check blocking, a service refusing a call.
121
123
 
122
- Findings are correlated against an Agent BOM before they are judged, so a
123
- vulnerable component is reported when something actually used it rather than
124
- because it is installed.
124
+ Findings are correlated against an Agent BOM before they are reported, so one
125
+ that names a component names the one a call actually reached.
125
126
 
126
127
  ## What leaves your machine
127
128
 
128
- Two of `detect`'s three stages run entirely locally and need no model or
129
- credential, and they are the two a bare `detect` runs. The third sends flagged
130
- sessions to the agent's *own* CLI — the provider that produced the transcript,
131
- never a different one — and runs only when you pass `--reasoning`, capped by
132
- `--budget`.
129
+ **On a default run**, `detect` reads the record on this machine. It needs no
130
+ model, no credential and no account, and nothing derived from a session — no
131
+ prompt, no tool argument, no result — is sent anywhere.
132
+
133
+ One network call is made even then, and it is worth stating because *nothing
134
+ leaves* is not what happens: correlation matches advisories by sending the
135
+ package coordinates of the components a session invoked to osv.dev.
136
+ Coordinates only.
137
+
138
+ **One flag pair changes that, and it has to be typed in full.** `detect
139
+ --reasoning --analyzer jev` adds a third stage that sends two small states to
140
+ TypeSafe's Jev: a *gate* carrying the closing lines of each hand-back, capped,
141
+ which ends most sessions there — and, for a session that clears it, one
142
+ per-call *window* each carrying a completion claim, one verification command
143
+ and the tail of its output. Neither flag has a default and neither implies the other,
144
+ so naming the vendor is your act rather than ours (ADR-0033). Without both,
145
+ stage three is not asked. `detect --analyzer jev` alone reads back what such a
146
+ run already paid for and commissions nothing (ADR-0035).
133
147
 
134
148
  `sessions` omits prompts, tool arguments and results unless you pass
135
- `--include-content`. `monitor` binds to loopback only, refuses a non-loopback
136
- address rather than warning about it, and analyses nothing with a model unless
137
- `--reasoning` is given.
149
+ `--include-content`. `monitor` binds to loopback only, and refuses a
150
+ non-loopback address rather than warning about it.
151
+
152
+ **Usage telemetry is enabled by default.** Disable it before normal use with
153
+ `stacktrace telemetry off`. An existing opt-out stays off; unreadable or invalid
154
+ settings also disable telemetry. The first enabled usage event creates a random
155
+ identifier. The daemon sends four event types to PostHog's US region: an enabled
156
+ identity first becomes active, a session starts, a finding is delivered, or a
157
+ product error occurs. Event fields describe the rule, severity, destination,
158
+ reason code or error category, the session id and agent kind for session and finding events, plus CLI version, OS, environment, whether it ran in a Claude Code cloud session (`remote`) and timestamp.
159
+ `environment` is `production` unless `STACKTRACE_TELEMETRY_ENV` is set to
160
+ `staging`, `development` or `test`. They do not
161
+ include prompts, tool arguments, results, full findings, paths or repository
162
+ names. The persistent identifier and timing mean this is not anonymous data.
163
+
164
+ `stacktrace telemetry show` prints the state, the destination, the environment,
165
+ the identifier and every event with every property it may carry. `off` deletes
166
+ the local identifier; it does not delete previously uploaded records, and an
167
+ event already handed to the client may still be sent. `stacktrace telemetry on`
168
+ enables telemetry again under a new identity (ADR-0039).
169
+ `STACKTRACE_TELEMETRY_DISABLED=1` sends nothing, for CI and test runs.
138
170
 
139
171
  ## Status
140
172
 
@@ -0,0 +1,160 @@
1
+ # stacktrace-cli
2
+
3
+ Detection and response for AI coding agents, from the command line.
4
+
5
+ Coding agents read files, run shell commands and call MCP servers on their own
6
+ initiative, and they write a transcript of every bit of it to disk.
7
+ `stacktrace` reads those transcripts, correlates what ran against the
8
+ components the agent is built from, and reports the security and reliability
9
+ findings in it — locally, on the machine the agent worked on.
10
+
11
+ The PyPI distribution is `stacktrace-cli`; the command it installs is
12
+ `stacktrace`. The two names differ because the bare `stacktrace` name on PyPI
13
+ belongs to an unrelated project.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ uv tool install stacktrace-cli # isolated; recommended
19
+ # or
20
+ pip install stacktrace-cli
21
+ ```
22
+
23
+ Requires Python 3.11 or newer.
24
+
25
+ ```console
26
+ $ stacktrace --version
27
+ stacktrace 0.4.0 (openaca 0.7.0)
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ```bash
33
+ stacktrace sessions # what the agents on this machine did
34
+ stacktrace detect # what is wrong with it
35
+ stacktrace monitor # the same, live in a browser
36
+ ```
37
+
38
+ ## Commands
39
+
40
+ | Command | |
41
+ |---|---|
42
+ | `sessions` | Print what the agents on this machine actually did. |
43
+ | `detect` | Find security and reliability findings in what agents did. |
44
+ | `monitor` | Watch this machine's agents in a browser, live. |
45
+ | `remote` | Configure remote endpoint services and upload to Stacktrace Cloud. |
46
+ | `scan` | Scan a repository or endpoint for agent-composition findings. |
47
+ | `bom` | Generate an Agent BOM for a repository or endpoint. |
48
+ | `policy` | Validate and compile restrictive endpoint policies. |
49
+
50
+ The last three are composition analysis, supplied by
51
+ [`openaca`](https://pypi.org/project/openaca/) and available under either
52
+ name.
53
+
54
+ ## What it looks like
55
+
56
+ ```console
57
+ $ stacktrace sessions --since 2d --include-content
58
+ claude-code:s1 [claude-code] 2026-08-27T09:00:00+00:00 2 turns 2 calls
59
+ 2026-08-29T12:00:00+00:00 assistant: Reading the changelog before drafting the release notes.
60
+ ok 28c Read
61
+ result: ## 0.4.0 - correlate, detect
62
+ 2026-08-29T12:00:00+00:00 assistant: Filing the release-notes follow-up.
63
+ - github/create_issue
64
+
65
+ Summary — 1 sessions, 2 turns, 2 tool calls
66
+
67
+ agent kinds
68
+ 1 claude-code
69
+
70
+ tools called (2 distinct)
71
+ 1 Read
72
+ 1 github/create_issue
73
+
74
+ MCP servers reached (1 distinct)
75
+ 1 github
76
+
77
+ 0 subagent turns · 0 results abridged upstream · 1 ok
78
+
79
+ 1 of 2 calls returned with no outcome the collector could establish; the agent's parser supplies no success signal.
80
+ ```
81
+
82
+ A blank status column is the collector's `unknown`, not a pending call: the
83
+ client recorded no outcome that could be established, and the closing line
84
+ counts those rather than filling one in.
85
+
86
+ ## What `detect` finds
87
+
88
+ Three kinds of finding, under two families that carry separate severity
89
+ ladders — a blocked agent and a leaked credential do not belong on one scale.
90
+
91
+ **Security** — a credential reaching an outbound call; success reported against
92
+ the session's own evidence of failure.
93
+
94
+ **Reliability** — why the agent stopped, in words, with what to do about it: a
95
+ spend limit reached, a safety check blocking, a service refusing a call.
96
+
97
+ Findings are correlated against an Agent BOM before they are reported, so one
98
+ that names a component names the one a call actually reached.
99
+
100
+ ## What leaves your machine
101
+
102
+ **On a default run**, `detect` reads the record on this machine. It needs no
103
+ model, no credential and no account, and nothing derived from a session — no
104
+ prompt, no tool argument, no result — is sent anywhere.
105
+
106
+ One network call is made even then, and it is worth stating because *nothing
107
+ leaves* is not what happens: correlation matches advisories by sending the
108
+ package coordinates of the components a session invoked to osv.dev.
109
+ Coordinates only.
110
+
111
+ **One flag pair changes that, and it has to be typed in full.** `detect
112
+ --reasoning --analyzer jev` adds a third stage that sends two small states to
113
+ TypeSafe's Jev: a *gate* carrying the closing lines of each hand-back, capped,
114
+ which ends most sessions there — and, for a session that clears it, one
115
+ per-call *window* each carrying a completion claim, one verification command
116
+ and the tail of its output. Neither flag has a default and neither implies the other,
117
+ so naming the vendor is your act rather than ours (ADR-0033). Without both,
118
+ stage three is not asked. `detect --analyzer jev` alone reads back what such a
119
+ run already paid for and commissions nothing (ADR-0035).
120
+
121
+ `sessions` omits prompts, tool arguments and results unless you pass
122
+ `--include-content`. `monitor` binds to loopback only, and refuses a
123
+ non-loopback address rather than warning about it.
124
+
125
+ **Usage telemetry is enabled by default.** Disable it before normal use with
126
+ `stacktrace telemetry off`. An existing opt-out stays off; unreadable or invalid
127
+ settings also disable telemetry. The first enabled usage event creates a random
128
+ identifier. The daemon sends four event types to PostHog's US region: an enabled
129
+ identity first becomes active, a session starts, a finding is delivered, or a
130
+ product error occurs. Event fields describe the rule, severity, destination,
131
+ reason code or error category, the session id and agent kind for session and finding events, plus CLI version, OS, environment, whether it ran in a Claude Code cloud session (`remote`) and timestamp.
132
+ `environment` is `production` unless `STACKTRACE_TELEMETRY_ENV` is set to
133
+ `staging`, `development` or `test`. They do not
134
+ include prompts, tool arguments, results, full findings, paths or repository
135
+ names. The persistent identifier and timing mean this is not anonymous data.
136
+
137
+ `stacktrace telemetry show` prints the state, the destination, the environment,
138
+ the identifier and every event with every property it may carry. `off` deletes
139
+ the local identifier; it does not delete previously uploaded records, and an
140
+ event already handed to the client may still be sent. `stacktrace telemetry on`
141
+ enables telemetry again under a new identity (ADR-0039).
142
+ `STACKTRACE_TELEMETRY_DISABLED=1` sends nothing, for CI and test runs.
143
+
144
+ ## Status
145
+
146
+ Beta, and under active development.
147
+
148
+ `sessions`, `detect` and `monitor` work end to end today. Session collection
149
+ currently reads Claude Code transcripts; further agent kinds are in progress
150
+ upstream in [OpenAIDR](https://github.com/open-agent-security/openaidr).
151
+
152
+ ## Built on
153
+
154
+ Two Apache-2.0 packages, neither of which depends on this one:
155
+ [`openaca`](https://pypi.org/project/openaca/) for agent composition analysis,
156
+ and [`openaidr`](https://pypi.org/project/openaidr/) for session collection.
157
+
158
+ ## Licence
159
+
160
+ Proprietary. © Stacktrace AI, Inc. — [stacktrace.ai](https://stacktrace.ai)
@@ -6,7 +6,7 @@ date: 2026-08-27
6
6
  supersedes: null
7
7
  superseded-by: null
8
8
  amends: null
9
- amended-by: 0029
9
+ amended-by: 0029, 0033
10
10
  ---
11
11
 
12
12
  ## Context
@@ -5,7 +5,7 @@ status: accepted
5
5
  date: 2026-08-28
6
6
  supersedes: null
7
7
  superseded-by: null
8
- amended-by: 0011, 0027
8
+ amended-by: 0011, 0027, 0031, 0039
9
9
  ---
10
10
 
11
11
  ## Context
@@ -6,6 +6,7 @@ date: 2026-08-31
6
6
  supersedes: null
7
7
  superseded-by: null
8
8
  amends: 0006
9
+ amended-by: 0033
9
10
  ---
10
11
 
11
12
  ## Context
@@ -0,0 +1,104 @@
1
+ ---
2
+ id: 0030
3
+ title: A detection is dated by the turns it cites
4
+ status: accepted
5
+ date: 2026-09-15
6
+ supersedes: null
7
+ superseded-by: null
8
+ ---
9
+
10
+ ## Context
11
+
12
+ A finding carried no time of its own. `Detection` had no timestamp, `Evidence`
13
+ was `(span, kind, detail)`, and `SessionRef` carried the session's `started_at`
14
+ — so every surface answered "when did this happen" with the session's start.
15
+
16
+ That is wrong by however long the session ran. OpenAIDR takes `started_at` from
17
+ the transcript's earliest record, so a session left open for a day dates its last
18
+ finding by its first minute, and a session resumed across a fortnight dates
19
+ today's finding two weeks ago. The local console worked around it with the
20
+ transcript file's modification time; the receiving service works around it by
21
+ admitting a finding on the later of the session start and its own receipt time.
22
+ Both are compensating for a value this package never produced.
23
+
24
+ OpenAIDR now carries `Turn.occurred_at` (its ADR-0010). The question this ADR
25
+ settles is which turns date a finding, and what shape that date takes.
26
+
27
+ ## Decision
28
+
29
+ A detection is dated by **the turns its evidence cites**: `occurred_start` is the
30
+ MIN and `occurred_end` the MAX over its citations' turn times, and each
31
+ `Evidence` carries the time of its own turn beside it. A finding citing one turn
32
+ has equal bounds, which is the correct answer rather than a degenerate one.
33
+
34
+ Citations that resolve to no turn — `ContextItem` spans, which take the literal
35
+ turn key `context` — contribute nothing and do not undate a finding its other
36
+ citations can date. A finding with no dated citation carries no range, and the
37
+ consuming surface falls back to the clocks it used before.
38
+
39
+ Dating is applied **once**, at the seam where a detector run is assembled, not at
40
+ each of the five sites that extend the finding list.
41
+
42
+ ## Alternatives considered
43
+
44
+ - **Date a finding by its session's start.** The status quo, and the thing being
45
+ fixed. Rejected: wrong by the session's whole duration, and worst exactly where
46
+ it matters — the long, busy sessions that produce the most findings.
47
+ - **Date a finding by the anchor citation alone** (`evidence[0]`). Rejected: the
48
+ anchor is *what the finding is about*, not *when it happened*. A session-scoped
49
+ rule accumulates citations as the session grows, so the anchor would freeze a
50
+ live finding at its oldest evidence.
51
+ - **A single instant per detection — the newest cited turn.** Specified first,
52
+ then cut. It answers "how recent" but destroys "over what span", and the span
53
+ is the question for a multi-turn episode: a finding whose citations run from
54
+ turn 12 to turn 47 is telling a story about an interval, and collapsing it to
55
+ turn 47 discards the part a responder reconstructs the incident from.
56
+ - **Per-turn start *and* end, carried on every citation.** Also specified, then
57
+ cut. It requires OpenAIDR to model a turn end, which needs the ambiguous
58
+ call-id join and a rule for a turn holding a still-running call — and it
59
+ answers a question nobody asked. A consumer wanting the span of an episode
60
+ gets it from the first and last turn it cites, which is exactly this decision.
61
+ - **Put the range on `SessionRef`.** Rejected twice. `SessionRef`'s four fields
62
+ mirror OpenAIDR's outward-carriage descriptor, and widening one without the
63
+ other breaks the mirror. More decisively, a time on `SessionRef` would be
64
+ shared by every detection from that session — which is the bug restated, not
65
+ fixed.
66
+ - **Let the receiving service derive the range from the evidence rows it
67
+ stores.** Rejected: it forces a join to answer the commonest filter, and the
68
+ producer already holds the values. The range is denormalised onto the
69
+ detection for exactly that reason.
70
+ - **Re-derive the turn from the span string.** The span embeds its turn key, so
71
+ parsing it would work. Rejected: span construction is OpenAIDR's (its
72
+ ADR-0001), and a consumer that parses it takes a dependency on a format it does
73
+ not own and cannot be told has changed. The lookup walks the turns instead.
74
+
75
+ ## Consequences
76
+
77
+ A responder can see when a finding happened, and for a multi-turn finding, over
78
+ what interval. The monitor and the receiving service both get a device-side clock
79
+ that is a property of the session rather than of the file holding it.
80
+
81
+ Every consumer must treat equal bounds as ordinary and print one time rather than
82
+ a range — most findings cite one turn, so this is the common path, not an edge.
83
+
84
+ Nulls propagate honestly and therefore have to be handled honestly: a finding
85
+ citing only context spans is undated, and a surface that renders that as "just
86
+ now" or as the session's start has reintroduced the defect this fixes.
87
+
88
+ The wire shape grows three nullable keys. Because the upload contract is an
89
+ exhaustive allowlist, they must be added to it in the same commit as the
90
+ producer, or every upload fails locally before it is sent.
91
+
92
+ ## When to revisit
93
+
94
+ If a rule family appears whose citations are not tool calls — a finding about a
95
+ session's shape rather than its actions — the span-to-turn lookup would return
96
+ nothing for it, and dating would need a second source.
97
+
98
+ If undated findings turn out to be common rather than rare in practice, which
99
+ would mean context-only citations matter more than measured, and would justify
100
+ dating a `ContextItem` upstream.
101
+
102
+ If the range is ever used to *admit* a finding to a window rather than to
103
+ display it, the null-together property and the fallback chain need restating for
104
+ that use before it is relied on.
@@ -0,0 +1,115 @@
1
+ ---
2
+ id: 0031
3
+ title: Let one host daemon observe native session logs and deliver findings
4
+ status: accepted
5
+ date: 2026-09-17
6
+ supersedes: null
7
+ superseded-by: null
8
+ amends: 0006
9
+ amended-by: 0032, 0036, 0037, 0038, 0039
10
+ ---
11
+
12
+ ## Context
13
+
14
+ Automatic detection needs to work while an agent session is active without
15
+ making every agent integration implement the detector. Claude exposes lifecycle
16
+ hooks and an experimental session monitor, but other hosts expose different
17
+ surfaces. Hooks also describe lifecycle boundaries rather than the completion of
18
+ an asynchronous detection pass: starting detached work on every turn creates
19
+ overlapping workers, while waiting in the hook delays the agent.
20
+
21
+ The native session log is already the complete local event ledger consumed
22
+ through OpenAIDR. Reading it requires no proxy, SDK wrapper, provider
23
+ instrumentation or change to the user's agent configuration beyond installing
24
+ an adapter. The missing piece is a process that notices changes, runs the
25
+ existing pipeline incrementally, and routes the result back to the one session
26
+ that caused it.
27
+
28
+ That process needs durable delivery state. ADR-0006 permits findings to travel
29
+ but says session models and correlation records do not persist; ADR-0011 makes a
30
+ narrow exception for verdicts and explicitly says another kind of
31
+ session-derived state needs its own case. A content-free finding and its delivery
32
+ receipt are that second case.
33
+
34
+ ## Decision
35
+
36
+ One per-user, host-level Stacktrace daemon observes native session logs, runs the
37
+ existing in-process analysis pipeline, persists content-free findings, and
38
+ delivers eligible notification events over a local Unix socket.
39
+
40
+ 1. Agent adapters identify a native session and subscribe to the daemon. They do
41
+ not parse transcripts or run detection. The daemon routes only by exact
42
+ `(host, native session id)`; current directory and newest-session heuristics
43
+ are never routing keys.
44
+ 2. OpenAIDR remains the only session-log parsing boundary. The daemon narrows
45
+ analysis to subscribed sessions and re-runs it only when that session's file
46
+ size or modification time changes.
47
+ 3. The socket protocol is versioned newline-delimited JSON. Notification
48
+ delivery is at least once: the subscriber acknowledges only after flushing
49
+ the tagged event to its host, and reconnecting subscribers receive unacknowledged
50
+ events with the same stable event id.
51
+ 4. This amends ADR-0006 to permit one durable local ledger containing the
52
+ already-published, content-free detection shape, stable event ids, native
53
+ session ids, transcript size and modification time, and delivery status. It
54
+ never stores turns, prompts, tool arguments, tool results, correlation
55
+ records, compositions, evidence excerpts or analyzer explanations.
56
+ 5. Notification prose is generated from Stacktrace-owned rule identifiers and
57
+ grades. Transcript text and finding-provided titles are not copied into the
58
+ host-facing notification channel.
59
+ 6. The daemon exists while at least one adapter is subscribed, plus a short
60
+ final-flush grace after disconnect. A lock admits one daemon per user, and an
61
+ adapter reconnects after daemon replacement.
62
+
63
+ ## Alternatives considered
64
+
65
+ - **Run detection from Stop and SessionEnd hooks.** Rejected because a turn
66
+ boundary is not a detection boundary. Detached hooks create overlapping
67
+ workers and lose their results; attached hooks delay the agent. Hosts without
68
+ equivalent hooks would also need another architecture.
69
+ - **Put a session watcher and detector inside every plugin.** Rejected because
70
+ every active session would own duplicate parsing, policy and durable state,
71
+ and each new host adapter would copy the same engine.
72
+ - **Require OTEL, OpenInference, an MCP proxy or an SDK wrapper.** Rejected for
73
+ the default path because each requires instrumentation or traffic-path changes
74
+ before Stacktrace can observe an existing agent. They may become additional
75
+ inputs, but not an installation prerequisite.
76
+ - **Persist transcripts or normalized session events and process only appended
77
+ bytes.** Rejected because it widens the local data boundary and duplicates the
78
+ parser's state model. The first increment is the session selector plus the
79
+ file fingerprint: only a changed subscribed session is reparsed, and stable
80
+ finding identity prevents duplicate work at the delivery boundary.
81
+ - **Send findings to whichever subscriber shares a working directory.**
82
+ Rejected because parallel sessions commonly share a project. A plausible
83
+ notification delivered to the wrong conversation is a security failure, not
84
+ a cosmetic race.
85
+
86
+ ## Consequences
87
+
88
+ Agent plugins become small adapters: identify the native session, maintain one
89
+ local subscription, and teach the host how to render a tagged Stacktrace event.
90
+ The analysis engine, policy, persistence and delivery semantics remain in one
91
+ place and can serve later Codex or Cursor adapters without moving them.
92
+
93
+ The persisted ledger weakens ADR-0006's former absolute local-persistence rule,
94
+ but only with the same content-free finding object already allowed to travel.
95
+ Tests must continue to prove notification text cannot contain attacker-controlled
96
+ finding titles and that sessions cannot receive one another's events.
97
+
98
+ The first increment reparses the changed session rather than parsing an append
99
+ stream. That keeps OpenAIDR as the format owner and is simpler to recover after
100
+ partial writes, at the cost of work proportional to one growing session. If
101
+ that cost threatens the notification objective, the incremental cursor belongs
102
+ in OpenAIDR's per-kind reader contract rather than in the daemon.
103
+
104
+ The model-mediated host notification is best effort: a host that is unavailable
105
+ cannot render it. Findings remain durable, so an independent notification
106
+ adapter can be added without changing observation or detection.
107
+
108
+ ## When to revisit
109
+
110
+ Revisit the file-fingerprint increment when measured changed-session analysis
111
+ cannot meet the notification objective. Revisit native-log observation when a
112
+ host offers a stable, complete event stream requiring no user instrumentation.
113
+ Revisit Unix sockets if supported hosts require Windows. Do not revisit merely
114
+ because one host adds another lifecycle hook; hooks do not change the ownership
115
+ or asynchronous-boundary arguments.