agentmetry 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 (205) hide show
  1. agentmetry-0.4.0/.dockerignore +5 -0
  2. agentmetry-0.4.0/.env.agentmetry-demo +29 -0
  3. agentmetry-0.4.0/.env.example +20 -0
  4. agentmetry-0.4.0/.gitignore +98 -0
  5. agentmetry-0.4.0/Dockerfile +18 -0
  6. agentmetry-0.4.0/PKG-INFO +86 -0
  7. agentmetry-0.4.0/README.md +45 -0
  8. agentmetry-0.4.0/agentmetry/__init__.py +12 -0
  9. agentmetry-0.4.0/agentmetry/api/__init__.py +0 -0
  10. agentmetry-0.4.0/agentmetry/api/main.py +232 -0
  11. agentmetry-0.4.0/agentmetry/api/routes/__init__.py +0 -0
  12. agentmetry-0.4.0/agentmetry/api/routes/audit.py +396 -0
  13. agentmetry-0.4.0/agentmetry/api/websocket.py +53 -0
  14. agentmetry-0.4.0/agentmetry/api/ws_bridge.py +34 -0
  15. agentmetry-0.4.0/agentmetry/cli/__init__.py +941 -0
  16. agentmetry-0.4.0/agentmetry/cli/__main__.py +5 -0
  17. agentmetry-0.4.0/agentmetry/core/__init__.py +0 -0
  18. agentmetry-0.4.0/agentmetry/core/audit/__init__.py +1 -0
  19. agentmetry-0.4.0/agentmetry/core/audit/adapters/__init__.py +0 -0
  20. agentmetry-0.4.0/agentmetry/core/audit/adapters/agt.py +304 -0
  21. agentmetry-0.4.0/agentmetry/core/audit/adapters/cloudevents.py +159 -0
  22. agentmetry-0.4.0/agentmetry/core/audit/adapters/ecs.py +103 -0
  23. agentmetry-0.4.0/agentmetry/core/audit/adapters/splunk.py +40 -0
  24. agentmetry-0.4.0/agentmetry/core/audit/alerts.py +56 -0
  25. agentmetry-0.4.0/agentmetry/core/audit/canonical.py +150 -0
  26. agentmetry-0.4.0/agentmetry/core/audit/compliance_digest.py +299 -0
  27. agentmetry-0.4.0/agentmetry/core/audit/detection/__init__.py +9 -0
  28. agentmetry-0.4.0/agentmetry/core/audit/detection/benchmark.py +194 -0
  29. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_approval_denied_then_executed.jsonl +3 -0
  30. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_arbitrary_host_stage_execute.jsonl +3 -0
  31. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_autonomous_unapproved_write.jsonl +3 -0
  32. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_credential_exfil.jsonl +2 -0
  33. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_credential_then_cloud_api.jsonl +2 -0
  34. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_destructive_delete_burst.jsonl +6 -0
  35. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_discovery_then_collect.jsonl +5 -0
  36. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_dotfile_then_git_push.jsonl +2 -0
  37. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_encoded_command_download.jsonl +1 -0
  38. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_env_credential_exfil.jsonl +3 -0
  39. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_hashed_only_no_command.jsonl +2 -0
  40. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_interpreter_egress.jsonl +2 -0
  41. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_pr_merged_without_review.jsonl +2 -0
  42. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_proc_substitution_cradle.jsonl +2 -0
  43. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_remote_pipe_to_shell.jsonl +1 -0
  44. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_remote_staging_then_execute.jsonl +2 -0
  45. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_session_tool_burst.jsonl +42 -0
  46. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_single_command_exfil.jsonl +2 -0
  47. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_ssh_directory_exfil.jsonl +3 -0
  48. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_subagent_swarm.jsonl +6 -0
  49. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_timestamp_collision.jsonl +2 -0
  50. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/attack_untrusted_input_then_action.jsonl +3 -0
  51. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_authoring_merge_fixtures.jsonl +3 -0
  52. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_autonomous_after_approval.jsonl +4 -0
  53. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_build_artifact_cleanup.jsonl +5 -0
  54. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_ci_artifact_download.jsonl +3 -0
  55. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_database_migration.jsonl +5 -0
  56. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_dependency_install_and_build.jsonl +5 -0
  57. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_download_release_archive.jsonl +4 -0
  58. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_fetch_data_then_run_repo_script.jsonl +3 -0
  59. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_fetch_dataset_then_analyse.jsonl +3 -0
  60. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_fetch_lockfile_then_install.jsonl +3 -0
  61. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_git_review_and_push.jsonl +6 -0
  62. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_human_driven_deletes.jsonl +6 -0
  63. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_local_api_probing.jsonl +5 -0
  64. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_long_but_calm_session.jsonl +30 -0
  65. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_loopback_is_not_egress.jsonl +2 -0
  66. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_loopback_pipe_to_interpreter.jsonl +3 -0
  67. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_ordinary_development.jsonl +5 -0
  68. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_package_manager_after_fetch.jsonl +2 -0
  69. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_reading_config_that_is_not_secret.jsonl +5 -0
  70. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_remote_api_call_no_credentials.jsonl +4 -0
  71. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_research_then_docs.jsonl +5 -0
  72. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_reversed_order_is_not_exfil.jsonl +2 -0
  73. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_test_and_fix_loop.jsonl +6 -0
  74. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/benign_writing_about_credentials.jsonl +6 -0
  75. agentmetry-0.4.0/agentmetry/core/audit/detection/corpus/corpus.yaml +443 -0
  76. agentmetry-0.4.0/agentmetry/core/audit/detection/disposition.py +651 -0
  77. agentmetry-0.4.0/agentmetry/core/audit/detection/engine.py +78 -0
  78. agentmetry-0.4.0/agentmetry/core/audit/detection/live.py +127 -0
  79. agentmetry-0.4.0/agentmetry/core/audit/detection/live_store.py +355 -0
  80. agentmetry-0.4.0/agentmetry/core/audit/detection/models.py +53 -0
  81. agentmetry-0.4.0/agentmetry/core/audit/detection/rules.py +1314 -0
  82. agentmetry-0.4.0/agentmetry/core/audit/detection/traits.py +648 -0
  83. agentmetry-0.4.0/agentmetry/core/audit/detection/yaml_config.py +91 -0
  84. agentmetry-0.4.0/agentmetry/core/audit/detection/yaml_rules.py +83 -0
  85. agentmetry-0.4.0/agentmetry/core/audit/dlp/__init__.py +4 -0
  86. agentmetry-0.4.0/agentmetry/core/audit/dlp/loader.py +29 -0
  87. agentmetry-0.4.0/agentmetry/core/audit/dlp/models.py +29 -0
  88. agentmetry-0.4.0/agentmetry/core/audit/dlp/scanner.py +96 -0
  89. agentmetry-0.4.0/agentmetry/core/audit/dogfood.py +398 -0
  90. agentmetry-0.4.0/agentmetry/core/audit/evidence_pack.py +500 -0
  91. agentmetry-0.4.0/agentmetry/core/audit/external.py +213 -0
  92. agentmetry-0.4.0/agentmetry/core/audit/hashing.py +21 -0
  93. agentmetry-0.4.0/agentmetry/core/audit/hook_bootstrap.py +451 -0
  94. agentmetry-0.4.0/agentmetry/core/audit/identity.py +39 -0
  95. agentmetry-0.4.0/agentmetry/core/audit/ingest.py +242 -0
  96. agentmetry-0.4.0/agentmetry/core/audit/migrate.py +73 -0
  97. agentmetry-0.4.0/agentmetry/core/audit/mitre.py +244 -0
  98. agentmetry-0.4.0/agentmetry/core/audit/policy.py +99 -0
  99. agentmetry-0.4.0/agentmetry/core/audit/redaction.py +50 -0
  100. agentmetry-0.4.0/agentmetry/core/audit/replay.py +54 -0
  101. agentmetry-0.4.0/agentmetry/core/audit/run_context.py +129 -0
  102. agentmetry-0.4.0/agentmetry/core/audit/sinks.py +235 -0
  103. agentmetry-0.4.0/agentmetry/core/audit/spool.py +394 -0
  104. agentmetry-0.4.0/agentmetry/core/audit/tool_policy/__init__.py +4 -0
  105. agentmetry-0.4.0/agentmetry/core/audit/tool_policy/evaluator.py +198 -0
  106. agentmetry-0.4.0/agentmetry/core/audit/tool_policy/loader.py +44 -0
  107. agentmetry-0.4.0/agentmetry/core/audit/tool_policy/models.py +25 -0
  108. agentmetry-0.4.0/agentmetry/core/audit/trail_chain.py +300 -0
  109. agentmetry-0.4.0/agentmetry/core/audit/trail_db.py +491 -0
  110. agentmetry-0.4.0/agentmetry/core/audit/trail_merkle.py +332 -0
  111. agentmetry-0.4.0/agentmetry/core/auth.py +54 -0
  112. agentmetry-0.4.0/agentmetry/core/bus/__init__.py +5 -0
  113. agentmetry-0.4.0/agentmetry/core/bus/audit_exporter.py +107 -0
  114. agentmetry-0.4.0/agentmetry/core/bus/bridges.py +26 -0
  115. agentmetry-0.4.0/agentmetry/core/bus/bus.py +102 -0
  116. agentmetry-0.4.0/agentmetry/core/bus/events.py +50 -0
  117. agentmetry-0.4.0/agentmetry/core/bus/outbox.py +124 -0
  118. agentmetry-0.4.0/agentmetry/core/config.py +177 -0
  119. agentmetry-0.4.0/agentmetry/core/diagnostics/__init__.py +0 -0
  120. agentmetry-0.4.0/agentmetry/core/diagnostics/autostart.py +563 -0
  121. agentmetry-0.4.0/agentmetry/core/diagnostics/doctor.py +535 -0
  122. agentmetry-0.4.0/agentmetry/core/diagnostics/driver_paths.py +156 -0
  123. agentmetry-0.4.0/agentmetry/core/diagnostics/env_file.py +45 -0
  124. agentmetry-0.4.0/agentmetry/core/drivers/__init__.py +4 -0
  125. agentmetry-0.4.0/agentmetry/core/drivers/host.py +263 -0
  126. agentmetry-0.4.0/agentmetry/core/drivers/permissions.py +37 -0
  127. agentmetry-0.4.0/agentmetry/core/drivers/spec.py +118 -0
  128. agentmetry-0.4.0/agentmetry/core/extensions.py +107 -0
  129. agentmetry-0.4.0/agentmetry/core/health.py +26 -0
  130. agentmetry-0.4.0/agentmetry/core/version.py +13 -0
  131. agentmetry-0.4.0/agentmetry/policies/detection/manifest.yaml +43 -0
  132. agentmetry-0.4.0/agentmetry/policies/dlp/manifest.yaml +161 -0
  133. agentmetry-0.4.0/agentmetry/policies/opa/agent_rules.rego +33 -0
  134. agentmetry-0.4.0/agentmetry/policies/tool/manifest.yaml +117 -0
  135. agentmetry-0.4.0/pyproject.toml +89 -0
  136. agentmetry-0.4.0/tests/conftest.py +47 -0
  137. agentmetry-0.4.0/tests/fixtures/agt_filesink_exfil.jsonl +3 -0
  138. agentmetry-0.4.0/tests/fixtures/agt_filesink_mixed.jsonl +3 -0
  139. agentmetry-0.4.0/tests/fixtures/fake_mcp_server.py +15 -0
  140. agentmetry-0.4.0/tests/test_agentmetry_audit.py +260 -0
  141. agentmetry-0.4.0/tests/test_agentmetry_ingest_client.py +310 -0
  142. agentmetry-0.4.0/tests/test_agt_adapter.py +230 -0
  143. agentmetry-0.4.0/tests/test_audit_sinks.py +213 -0
  144. agentmetry-0.4.0/tests/test_audit_stats.py +100 -0
  145. agentmetry-0.4.0/tests/test_audit_tail.py +384 -0
  146. agentmetry-0.4.0/tests/test_auth.py +33 -0
  147. agentmetry-0.4.0/tests/test_autostart.py +319 -0
  148. agentmetry-0.4.0/tests/test_boot_sequence.py +178 -0
  149. agentmetry-0.4.0/tests/test_burst_windows.py +169 -0
  150. agentmetry-0.4.0/tests/test_chinese_agent_hooks.py +152 -0
  151. agentmetry-0.4.0/tests/test_chinese_agent_sprint_b.py +69 -0
  152. agentmetry-0.4.0/tests/test_chinese_agent_sprint_c.py +126 -0
  153. agentmetry-0.4.0/tests/test_cli_backup.py +81 -0
  154. agentmetry-0.4.0/tests/test_cloudevents_adapter.py +229 -0
  155. agentmetry-0.4.0/tests/test_compliance_digest.py +163 -0
  156. agentmetry-0.4.0/tests/test_crewai_adapter.py +175 -0
  157. agentmetry-0.4.0/tests/test_detection_adi.py +314 -0
  158. agentmetry-0.4.0/tests/test_detection_benchmark.py +97 -0
  159. agentmetry-0.4.0/tests/test_detection_default_config.py +144 -0
  160. agentmetry-0.4.0/tests/test_detection_disposition.py +350 -0
  161. agentmetry-0.4.0/tests/test_detection_disposition_api.py +146 -0
  162. agentmetry-0.4.0/tests/test_detection_emit_durability.py +128 -0
  163. agentmetry-0.4.0/tests/test_detection_engine.py +401 -0
  164. agentmetry-0.4.0/tests/test_detection_evasion.py +304 -0
  165. agentmetry-0.4.0/tests/test_detection_hf_incident.py +169 -0
  166. agentmetry-0.4.0/tests/test_detection_rule_identity.py +262 -0
  167. agentmetry-0.4.0/tests/test_detection_rules_v2.py +177 -0
  168. agentmetry-0.4.0/tests/test_dlp_agent_env_override.py +70 -0
  169. agentmetry-0.4.0/tests/test_dlp_invisible_unicode.py +111 -0
  170. agentmetry-0.4.0/tests/test_dlp_markdown_exfil.py +84 -0
  171. agentmetry-0.4.0/tests/test_dlp_scanner.py +79 -0
  172. agentmetry-0.4.0/tests/test_doctor.py +153 -0
  173. agentmetry-0.4.0/tests/test_dogfood.py +222 -0
  174. agentmetry-0.4.0/tests/test_dogfood_freeze.py +83 -0
  175. agentmetry-0.4.0/tests/test_driver_paths.py +142 -0
  176. agentmetry-0.4.0/tests/test_event_bus.py +127 -0
  177. agentmetry-0.4.0/tests/test_evidence_pack.py +330 -0
  178. agentmetry-0.4.0/tests/test_extensions.py +43 -0
  179. agentmetry-0.4.0/tests/test_external_ingest.py +328 -0
  180. agentmetry-0.4.0/tests/test_forwarding_shape.py +173 -0
  181. agentmetry-0.4.0/tests/test_hook_bootstrap.py +144 -0
  182. agentmetry-0.4.0/tests/test_hook_enforcement_timing.py +125 -0
  183. agentmetry-0.4.0/tests/test_hook_spool.py +334 -0
  184. agentmetry-0.4.0/tests/test_isolation.py +65 -0
  185. agentmetry-0.4.0/tests/test_launch_targets.py +119 -0
  186. agentmetry-0.4.0/tests/test_live_detection.py +160 -0
  187. agentmetry-0.4.0/tests/test_live_detection_store.py +124 -0
  188. agentmetry-0.4.0/tests/test_mcp_audit_proxy.py +57 -0
  189. agentmetry-0.4.0/tests/test_mitre_dlp.py +170 -0
  190. agentmetry-0.4.0/tests/test_opensre_adapter.py +145 -0
  191. agentmetry-0.4.0/tests/test_readme_claims.py +128 -0
  192. agentmetry-0.4.0/tests/test_redaction.py +66 -0
  193. agentmetry-0.4.0/tests/test_replay.py +43 -0
  194. agentmetry-0.4.0/tests/test_static_serving.py +46 -0
  195. agentmetry-0.4.0/tests/test_subagent_lifecycle.py +198 -0
  196. agentmetry-0.4.0/tests/test_tool_policy.py +150 -0
  197. agentmetry-0.4.0/tests/test_tool_policy_agent_cli.py +151 -0
  198. agentmetry-0.4.0/tests/test_tool_policy_git_hooks.py +119 -0
  199. agentmetry-0.4.0/tests/test_trail_chain.py +145 -0
  200. agentmetry-0.4.0/tests/test_trail_merkle.py +265 -0
  201. agentmetry-0.4.0/tests/test_unattended_agent_policy.py +98 -0
  202. agentmetry-0.4.0/tests/test_version.py +67 -0
  203. agentmetry-0.4.0/tests/test_yaml_detection_rules.py +48 -0
  204. agentmetry-0.4.0/tools/mcp_audit_proxy.py +198 -0
  205. agentmetry-0.4.0/tools/vault_fs_server.py +84 -0
@@ -0,0 +1,5 @@
1
+ .venv
2
+ __pycache__
3
+ *.pyc
4
+ data
5
+ .git
@@ -0,0 +1,29 @@
1
+ # Agentmetry — zero-cloud dogfood profile
2
+ # Copy to apps/orchestrator/.env for audit-only runs (no Gemini, no Qdrant).
3
+ #
4
+ # copy apps\orchestrator\.env.agentmetry-demo apps\orchestrator\.env
5
+ # scripts\agentmetry.bat start
6
+ #
7
+ # Generates real tool_called + approval_* events via mock LLM. Draft text is
8
+ # placeholder (mock-dry-run) — fine for JSONL/replay verification, not for Loom.
9
+ # Switch to Gemini or Ollama for the Loom take — see docs/agentmetry-dependency-audit.md Profile B.
10
+
11
+ # --- audit layer (the product) ---
12
+ AGENTMETRY_OPERATOR_ID=home-lab
13
+ AGENTMETRY_AUDIT_EXPORT_ENABLED=1
14
+ AGENTMETRY_AUDIT_SINK=file
15
+ # Log shell commands from Tier B hooks (Cursor/Claude/Codex/Antigravity) in JSONL + dashboard
16
+ AGENTMETRY_AUDIT_LOG_COMMANDS=1
17
+
18
+ # --- runtime, no cloud LLM ---
19
+ AGENTMETRY_LLM_PROVIDER=mock
20
+ AGENTMETRY_ALLOW_MOCK=1
21
+ AGENTMETRY_VAULT_PATH=../../vault
22
+
23
+ # Faster boot for audit-only (no semantic index)
24
+ AGENTMETRY_STARTUP_VAULT_INDEX=false
25
+
26
+ # Not required for audit dogfood — leave unset / empty:
27
+ # GEMINI_API_KEY=
28
+ # AGENTMETRY_QDRANT_URL=
29
+ # AGENTMETRY_USE_POSTGRES=false (default)
@@ -0,0 +1,20 @@
1
+ # Agentmetry orchestrator — copy to .env and adjust
2
+ # cp apps/orchestrator/.env.example apps/orchestrator/.env
3
+ # Never commit .env — it is gitignored
4
+
5
+ # Demo MCP vault path (relative to this directory)
6
+ AGENTMETRY_VAULT_PATH=../../vault
7
+
8
+ AGENTMETRY_OPERATOR_ID=local
9
+ AGENTMETRY_FLEET_ID=
10
+ AGENTMETRY_API_KEY=
11
+
12
+ # Hook boundary — log | block | disable
13
+ AGENTMETRY_TOOL_POLICY_MODE=log
14
+ AGENTMETRY_DLP_MODE=log
15
+
16
+ # Audit export (JSONL + SQLite index)
17
+ AGENTMETRY_AUDIT_EXPORT_ENABLED=1
18
+ AGENTMETRY_AUDIT_SINK=file
19
+
20
+ # More tuning: see repo root .env.example and docs/agentmetry-dogfood-checklist.md
@@ -0,0 +1,98 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Python
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+ .venv/
11
+ venv/
12
+ *.egg-info/
13
+ dist/
14
+ build/
15
+
16
+ # Next.js
17
+ apps/dashboard/.next/
18
+ apps/dashboard/out/
19
+
20
+ # Environment
21
+ .env
22
+ .env.local
23
+ .env.*.local
24
+
25
+ # Vault runtime artifacts (agent-generated)
26
+ vault/20-Active-Loops/
27
+ vault/30-Archive/
28
+ vault/.obsidian/
29
+ vault/.system/run-log.md
30
+ vault/.system/Approvals-Digest.md
31
+
32
+ # IDE
33
+ .idea/
34
+ .vscode/
35
+ *.swp
36
+
37
+ # OS
38
+ .DS_Store
39
+ Thumbs.db
40
+
41
+ # Docker volumes
42
+ data/
43
+
44
+ # Logs
45
+ *.log
46
+
47
+ # Tier B — machine-local hook wrappers (install scripts regenerate)
48
+ scripts/agentmetry_*_hook.cmd
49
+
50
+ # Local driver toggles (never commit enabled/disabled state)
51
+ vault/.system/drivers.json
52
+ vault/.system/feedback/
53
+
54
+ # Backups
55
+ backups/
56
+
57
+ # Dashboard scratch / scratchpad (never commit)
58
+ apps/dashboard/scratch/
59
+
60
+ # Next.js/TS incremental build artifact
61
+ *.tsbuildinfo
62
+
63
+ # Local-only scratch directories (never part of the published repo):
64
+ # apps/landing/ an unused Vite scaffold (88M of node_modules)
65
+ # Ignored so a stray `git add -A` cannot commit them.
66
+ /apps/landing/
67
+
68
+ # A stale duplicate clone of this repo used to sit at /agentmetry/, and the rule
69
+ # blocking it was `/agentmetry/`. That rule had to go when the Python package was
70
+ # renamed to `agentmetry`.
71
+ #
72
+ # Git anchors a leading slash to the repository root, so `/agentmetry/` never
73
+ # matched apps/orchestrator/agentmetry/ and `git ls-files` listed all 72 files
74
+ # happily. Hatchling anchors it to the *project* root instead, which is
75
+ # apps/orchestrator, so it excluded the entire package and built a wheel
76
+ # containing nothing but dist-info. A published package that installs no code is
77
+ # the worst possible first release, and nothing in the build said a word.
78
+ #
79
+ # Only a nested clone has a .git directory, and our package never will, so this
80
+ # blocks the thing that was actually the problem without any anchoring ambiguity.
81
+ /agentmetry/.git/
82
+
83
+ # Local dev launch config (absolute machine paths)
84
+ .claude/launch.json
85
+
86
+ # Internal review prompts and audit reports. These name pilot pricing, kill
87
+ # gates, and the private repo contents; they belong in agentmetry-notes.
88
+ #
89
+ # The "review" patterns were already here and still let `audit-prompt.md` and
90
+ # `audit-2026-08.md` through, because the rule matched the word we happened to
91
+ # use last time rather than the kind of document. An audit of a security tool
92
+ # is the worst thing to publish by accident: it is an evasion writeup with the
93
+ # author's name on it.
94
+ docs/*review*prompt*.md
95
+ docs/*-review-*.md
96
+ docs/*audit*prompt*.md
97
+ docs/audit-*.md
98
+ docs/*-audit-*.md
@@ -0,0 +1,18 @@
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update && apt-get install -y --no-install-recommends \
6
+ gcc libpq-dev \
7
+ && rm -rf /var/lib/apt/lists/*
8
+
9
+ COPY pyproject.toml ./
10
+ COPY . .
11
+
12
+ RUN pip install --no-cache-dir -e .
13
+
14
+ RUN mkdir -p /app/data
15
+
16
+ EXPOSE 8000
17
+
18
+ CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"]
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentmetry
3
+ Version: 0.4.0
4
+ Summary: Local-first flight recorder for AI coding agents: hash-chained audit trail, MITRE-mapped sequence detection, DLP
5
+ Project-URL: Homepage, https://agentmetry.ai
6
+ Project-URL: Source, https://github.com/blitzcrieg1/agentmetry
7
+ Project-URL: Issues, https://github.com/blitzcrieg1/agentmetry/issues
8
+ Project-URL: Changelog, https://github.com/blitzcrieg1/agentmetry/blob/master/CHANGELOG.md
9
+ Author: Ioannis L.
10
+ License: Apache-2.0
11
+ Keywords: agentic-ai,ai-agents,ai-security,audit-log,claude-code,cursor,devsecops,dlp,local-first,mitre-attack,siem
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Security
22
+ Classifier: Topic :: System :: Logging
23
+ Classifier: Topic :: System :: Monitoring
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: aiosqlite>=0.20.0
26
+ Requires-Dist: fastapi>=0.115.0
27
+ Requires-Dist: httpx>=0.28.0
28
+ Requires-Dist: mcp>=1.2
29
+ Requires-Dist: pydantic-settings>=2.6.0
30
+ Requires-Dist: pydantic>=2.9.0
31
+ Requires-Dist: pyyaml>=6.0
32
+ Requires-Dist: sqlalchemy>=2.0.0
33
+ Requires-Dist: tzdata; sys_platform == 'win32'
34
+ Requires-Dist: uvicorn[standard]>=0.32.0
35
+ Requires-Dist: websockets>=14.0
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
38
+ Requires-Dist: pytest>=8.0; extra == 'dev'
39
+ Requires-Dist: ruff==0.16.0; extra == 'dev'
40
+ Description-Content-Type: text/markdown
41
+
42
+ # Agentmetry
43
+
44
+ A local-first flight recorder for AI coding agents.
45
+
46
+ Agentmetry hooks the tool lifecycle of Claude Code, Cursor, Codex and Antigravity,
47
+ writes every tool call, approval and denial to a hash-chained JSONL trail on your
48
+ machine, and runs sequence detection over the session. A credential read followed
49
+ by network egress becomes one finding rather than two unremarkable log lines.
50
+
51
+ Everything runs locally. There are no cloud calls and no telemetry. Forwarding to
52
+ Elastic ECS, Splunk HEC or a webhook exists and is off unless you configure it.
53
+
54
+ ```bash
55
+ pip install agentmetry
56
+ agentmetry doctor
57
+ ```
58
+
59
+ ## Check the detection claims yourself
60
+
61
+ The corpus ships inside the package, so this works from a clean install:
62
+
63
+ ```bash
64
+ agentmetry benchmark
65
+ ```
66
+
67
+ It replays recorded sessions through the real rule engine and exits non-zero on
68
+ any missed rule or any false positive. The benign half is the number that
69
+ matters: any tool can fire on an attack, and a feed that cries wolf gets muted.
70
+
71
+ ## What it does not do
72
+
73
+ - **It is not a CASB.** It records the agents you wire in. An unmanaged browser
74
+ assistant is invisible to it.
75
+ - **It is a recorder, not a sandbox.** The only enforcement path is pre-execution
76
+ DLP blocking in the hook.
77
+ - **The DLP is regex, not ML.** A starting pack you extend in YAML.
78
+ - **It is a public alpha.** Integration surfaces may still change.
79
+
80
+ Full documentation, the event schema, and the SIEM integration guides are in the
81
+ repository.
82
+
83
+ - Source and issues: https://github.com/blitzcrieg1/agentmetry
84
+ - Website: https://agentmetry.ai
85
+
86
+ Apache-2.0.
@@ -0,0 +1,45 @@
1
+ # Agentmetry
2
+
3
+ A local-first flight recorder for AI coding agents.
4
+
5
+ Agentmetry hooks the tool lifecycle of Claude Code, Cursor, Codex and Antigravity,
6
+ writes every tool call, approval and denial to a hash-chained JSONL trail on your
7
+ machine, and runs sequence detection over the session. A credential read followed
8
+ by network egress becomes one finding rather than two unremarkable log lines.
9
+
10
+ Everything runs locally. There are no cloud calls and no telemetry. Forwarding to
11
+ Elastic ECS, Splunk HEC or a webhook exists and is off unless you configure it.
12
+
13
+ ```bash
14
+ pip install agentmetry
15
+ agentmetry doctor
16
+ ```
17
+
18
+ ## Check the detection claims yourself
19
+
20
+ The corpus ships inside the package, so this works from a clean install:
21
+
22
+ ```bash
23
+ agentmetry benchmark
24
+ ```
25
+
26
+ It replays recorded sessions through the real rule engine and exits non-zero on
27
+ any missed rule or any false positive. The benign half is the number that
28
+ matters: any tool can fire on an attack, and a feed that cries wolf gets muted.
29
+
30
+ ## What it does not do
31
+
32
+ - **It is not a CASB.** It records the agents you wire in. An unmanaged browser
33
+ assistant is invisible to it.
34
+ - **It is a recorder, not a sandbox.** The only enforcement path is pre-execution
35
+ DLP blocking in the hook.
36
+ - **The DLP is regex, not ML.** A starting pack you extend in YAML.
37
+ - **It is a public alpha.** Integration surfaces may still change.
38
+
39
+ Full documentation, the event schema, and the SIEM integration guides are in the
40
+ repository.
41
+
42
+ - Source and issues: https://github.com/blitzcrieg1/agentmetry
43
+ - Website: https://agentmetry.ai
44
+
45
+ Apache-2.0.
@@ -0,0 +1,12 @@
1
+ """Agentmetry: a local-first flight recorder for AI coding agents.
2
+
3
+ Everything lives under this one top-level package on purpose. The orchestrator
4
+ used to ship `core`, `api` and `cli` as top-level names, which is harmless for an
5
+ editable install inside this repo and antisocial once published: three of the
6
+ most generic importable names in Python, dropped into someone else's
7
+ site-packages, where they collide with whatever else claims them.
8
+ """
9
+
10
+ from agentmetry.core.version import __version__
11
+
12
+ __all__ = ["__version__"]
File without changes
@@ -0,0 +1,232 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ from contextlib import asynccontextmanager
6
+ from logging.handlers import RotatingFileHandler
7
+ from pathlib import Path
8
+
9
+ from fastapi import FastAPI, Query, WebSocket, WebSocketDisconnect
10
+ from fastapi.middleware.cors import CORSMiddleware
11
+
12
+ from agentmetry.api.routes.audit import router as audit_router
13
+ from agentmetry.api.websocket import ws_manager
14
+ from agentmetry.api.ws_bridge import ws_event_bridge
15
+ from agentmetry.core.auth import verify_ws_token
16
+ from agentmetry.core.bus.audit_exporter import audit_exporter
17
+ from agentmetry.core.bus.bridges import outbox_persister
18
+ from agentmetry.core.bus.bus import bus
19
+ from agentmetry.core.bus.outbox import get_outbox
20
+ from agentmetry.core.config import settings
21
+ from agentmetry.core.extensions import load_extensions
22
+ from agentmetry.core.health import get_system_health
23
+ from agentmetry.core.version import __version__
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ _LOG_DIR = Path(__file__).resolve().parents[2] / "data" / "logs"
28
+
29
+
30
+ def _setup_logging() -> None:
31
+ """Persist app logs to disk so they survive a closed terminal."""
32
+ root = logging.getLogger()
33
+ if any(isinstance(h, RotatingFileHandler) for h in root.handlers):
34
+ return
35
+ _LOG_DIR.mkdir(parents=True, exist_ok=True)
36
+ formatter = logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s")
37
+
38
+ file_handler = RotatingFileHandler(
39
+ _LOG_DIR / "orchestrator.log",
40
+ maxBytes=5_000_000,
41
+ backupCount=3,
42
+ encoding="utf-8",
43
+ )
44
+ file_handler.setFormatter(formatter)
45
+ root.addHandler(file_handler)
46
+
47
+ console = logging.StreamHandler()
48
+ console.setFormatter(formatter)
49
+ root.addHandler(console)
50
+
51
+ if root.level in (logging.NOTSET, logging.WARNING):
52
+ root.setLevel(logging.INFO)
53
+
54
+
55
+ _setup_logging()
56
+
57
+
58
+
59
+
60
+ @asynccontextmanager
61
+ async def lifespan(app: FastAPI):
62
+ from agentmetry.core.audit.migrate import backfill_db_from_jsonl
63
+
64
+ # Backfill SQLite from the existing JSONL trail. A broken or locked audit DB
65
+ # must degrade the dashboard, never stop the daemon from booting: the
66
+ # recorder's job is to keep recording.
67
+ try:
68
+ await asyncio.to_thread(backfill_db_from_jsonl)
69
+ except Exception:
70
+ logger.exception("Audit trail backfill failed; continuing without it")
71
+
72
+ # Replay events the hooks captured while this process was down. Same
73
+ # non-fatal contract as the backfill: a broken spool must not stop the
74
+ # recorder from booting.
75
+ #
76
+ # Deliberately not awaited. Draining a few thousand spooled events takes
77
+ # minutes, and awaiting it here holds the ingest port closed for the whole
78
+ # time — so every hook that fires during the drain is refused and spooled,
79
+ # which makes the next drain larger. The recorder has to be reachable first
80
+ # and catch up second.
81
+ from agentmetry.core.audit.spool import drain_forever, drain_spool
82
+
83
+ async def _boot_drain() -> None:
84
+ try:
85
+ await drain_spool()
86
+ except Exception:
87
+ logger.exception("Hook spool drain failed; continuing without it")
88
+
89
+ # Bring the triage index back in step with the trail. `reconcile_at_boot`
90
+ # declines rather than rebuilding when the trail cannot account for a
91
+ # decision the index already holds — a pruned or repointed trail must not
92
+ # silently erase the corrective-action record.
93
+ from agentmetry.core.audit.detection.disposition import reconcile_at_boot
94
+
95
+ try:
96
+ await asyncio.to_thread(reconcile_at_boot)
97
+ except Exception:
98
+ logger.exception("Disposition reconcile failed; continuing without it")
99
+
100
+ # Event bus first: everything downstream publishes onto it.
101
+ bus.set_initial_seq(get_outbox().max_seq())
102
+ bridge_tasks = [
103
+ asyncio.create_task(ws_event_bridge(), name="ws-bridge"),
104
+ asyncio.create_task(outbox_persister(), name="outbox-persister"),
105
+ asyncio.create_task(audit_exporter(), name="audit-exporter"),
106
+ asyncio.create_task(_boot_drain(), name="spool-boot-drain"),
107
+ # Keep draining for as long as we run. A boot-only drain leaves a
108
+ # backlog growing unnoticed whenever ingest is unreachable while the
109
+ # process itself stays up.
110
+ asyncio.create_task(drain_forever(), name="spool-drain"),
111
+ ]
112
+
113
+ # Drivers mount in the background: a slow npx download must not delay boot.
114
+ from agentmetry.core.drivers.host import get_mcp_host
115
+
116
+ mount_task = asyncio.create_task(get_mcp_host().mount_all(), name="driver-mounts")
117
+
118
+ from agentmetry.core.audit.hook_bootstrap import bootstrap_tier_b_hooks
119
+
120
+ try:
121
+ hook_paths = bootstrap_tier_b_hooks()
122
+ if hook_paths.get("cursor"):
123
+ logger.info("Global Cursor hooks ready: %s", hook_paths["cursor"])
124
+ if hook_paths.get("claude"):
125
+ logger.info("Global Claude hooks ready: %s", hook_paths["claude"])
126
+ except Exception as exc:
127
+ logger.warning("Tier B hook bootstrap failed: %s", exc)
128
+
129
+ # Launch transcript watcher for Antigravity in the background
130
+ import subprocess
131
+ import sys
132
+ watcher_process = None
133
+ try:
134
+ watcher_path = Path(__file__).resolve().parents[4] / "scripts" / "antigravity_transcript_watcher.py"
135
+ if watcher_path.exists():
136
+ watcher_process = subprocess.Popen(
137
+ [sys.executable, str(watcher_path)],
138
+ stdout=subprocess.DEVNULL,
139
+ stderr=subprocess.DEVNULL,
140
+ )
141
+ logger.info("Started Antigravity transcript watcher (PID: %s)", watcher_process.pid)
142
+ except Exception as exc:
143
+ logger.warning("Failed to start Antigravity transcript watcher: %s", exc)
144
+
145
+ yield
146
+ mount_task.cancel()
147
+ await get_mcp_host().unmount_all()
148
+ for task in bridge_tasks:
149
+ task.cancel()
150
+ if watcher_process:
151
+ watcher_process.terminate()
152
+
153
+
154
+ app = FastAPI(
155
+ title="Agentmetry",
156
+ description="Open-source SIEM flight recorder for AI agent tool-use",
157
+ version=__version__,
158
+ lifespan=lifespan,
159
+ )
160
+
161
+ app.add_middleware(
162
+ CORSMiddleware,
163
+ allow_origins=[
164
+ "http://localhost:3000",
165
+ "http://127.0.0.1:3000",
166
+ "http://localhost:3001",
167
+ "http://127.0.0.1:3001",
168
+ "http://dashboard:3000",
169
+ ],
170
+ allow_origin_regex=r"http://(localhost|127\.0\.0\.1):\d+",
171
+ allow_credentials=True,
172
+ allow_methods=["*"],
173
+ allow_headers=["*"],
174
+ )
175
+
176
+ app.include_router(audit_router, prefix="/api/v1")
177
+
178
+ load_extensions(app, settings=settings)
179
+
180
+
181
+ @app.get("/api/v1/health")
182
+ async def health():
183
+ return await get_system_health()
184
+
185
+
186
+
187
+
188
+
189
+ @app.websocket("/ws/{session_id}")
190
+ async def websocket_endpoint(
191
+ websocket: WebSocket,
192
+ session_id: str,
193
+ token: str | None = Query(None),
194
+ ):
195
+ if not verify_ws_token(token, websocket):
196
+ await websocket.close(code=4401)
197
+ return
198
+ await ws_manager.connect(websocket, session_id)
199
+ try:
200
+ while True:
201
+ await websocket.receive_text()
202
+ except WebSocketDisconnect:
203
+ ws_manager.disconnect(websocket, session_id)
204
+
205
+
206
+ _DASHBOARD_DIR = Path(__file__).resolve().parents[3] / "dashboard" / "out"
207
+
208
+
209
+ def mount_dashboard(target: FastAPI, directory: Path = _DASHBOARD_DIR) -> bool:
210
+ """Serve the dashboard's static export when it has been built.
211
+
212
+ Single-process mode: `npm run build` in apps/dashboard emits `out/`, which
213
+ the orchestrator serves at the root. Mounted last so it only catches paths
214
+ not already claimed by the API or WebSocket. Dev uses the :3000 dev server
215
+ instead, so this is a no-op when the export is absent.
216
+ """
217
+ if not directory.is_dir():
218
+ logger.info(
219
+ "Dashboard export not found at %s — run 'npm run build' in "
220
+ "apps/dashboard for single-process serving",
221
+ directory,
222
+ )
223
+ return False
224
+
225
+ from fastapi.staticfiles import StaticFiles
226
+
227
+ target.mount("/", StaticFiles(directory=str(directory), html=True), name="dashboard")
228
+ logger.info("Serving dashboard from %s", directory)
229
+ return True
230
+
231
+
232
+ mount_dashboard(app)
File without changes