dashcam-ai 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 (42) hide show
  1. dashcam_ai-0.4.0/.github/workflows/ci.yml +16 -0
  2. dashcam_ai-0.4.0/.github/workflows/release.yml +24 -0
  3. dashcam_ai-0.4.0/.gitignore +8 -0
  4. dashcam_ai-0.4.0/CONTRIBUTING.md +37 -0
  5. dashcam_ai-0.4.0/LICENSE +21 -0
  6. dashcam_ai-0.4.0/PKG-INFO +145 -0
  7. dashcam_ai-0.4.0/README.md +122 -0
  8. dashcam_ai-0.4.0/SECURITY.md +65 -0
  9. dashcam_ai-0.4.0/docs/ARCHITECTURE.md +120 -0
  10. dashcam_ai-0.4.0/docs/ROADMAP.md +42 -0
  11. dashcam_ai-0.4.0/docs/SIEM.md +69 -0
  12. dashcam_ai-0.4.0/docs/assets/demo.svg +176 -0
  13. dashcam_ai-0.4.0/pyproject.toml +44 -0
  14. dashcam_ai-0.4.0/src/dashcam/__init__.py +7 -0
  15. dashcam_ai-0.4.0/src/dashcam/anomaly.py +108 -0
  16. dashcam_ai-0.4.0/src/dashcam/brief.py +164 -0
  17. dashcam_ai-0.4.0/src/dashcam/cli.py +387 -0
  18. dashcam_ai-0.4.0/src/dashcam/cost.py +58 -0
  19. dashcam_ai-0.4.0/src/dashcam/data/models.json +1 -0
  20. dashcam_ai-0.4.0/src/dashcam/demo.py +87 -0
  21. dashcam_ai-0.4.0/src/dashcam/digest.py +134 -0
  22. dashcam_ai-0.4.0/src/dashcam/ingest/__init__.py +8 -0
  23. dashcam_ai-0.4.0/src/dashcam/ingest/base.py +31 -0
  24. dashcam_ai-0.4.0/src/dashcam/ingest/claude_code.py +130 -0
  25. dashcam_ai-0.4.0/src/dashcam/ingest/codex.py +148 -0
  26. dashcam_ai-0.4.0/src/dashcam/ingest/gemini.py +194 -0
  27. dashcam_ai-0.4.0/src/dashcam/ingest/opencode.py +272 -0
  28. dashcam_ai-0.4.0/src/dashcam/models.py +35 -0
  29. dashcam_ai-0.4.0/src/dashcam/redact.py +49 -0
  30. dashcam_ai-0.4.0/src/dashcam/serve.py +239 -0
  31. dashcam_ai-0.4.0/src/dashcam/signing.py +119 -0
  32. dashcam_ai-0.4.0/src/dashcam/store.py +268 -0
  33. dashcam_ai-0.4.0/tests/test_adversarial.py +195 -0
  34. dashcam_ai-0.4.0/tests/test_anomaly.py +80 -0
  35. dashcam_ai-0.4.0/tests/test_brief.py +116 -0
  36. dashcam_ai-0.4.0/tests/test_cli.py +115 -0
  37. dashcam_ai-0.4.0/tests/test_codex_parser.py +91 -0
  38. dashcam_ai-0.4.0/tests/test_dashcam.py +268 -0
  39. dashcam_ai-0.4.0/tests/test_gemini_parser.py +85 -0
  40. dashcam_ai-0.4.0/tests/test_opencode_parser.py +134 -0
  41. dashcam_ai-0.4.0/tests/test_serve.py +85 -0
  42. dashcam_ai-0.4.0/tests/test_signing.py +74 -0
@@ -0,0 +1,16 @@
1
+ name: ci
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: actions/setup-python@v5
12
+ with:
13
+ python-version: ${{ matrix.python-version }}
14
+ - run: pip install -e . && pip install pytest ruff
15
+ - run: ruff check src tests
16
+ - run: pytest -q
@@ -0,0 +1,24 @@
1
+ name: release
2
+ on:
3
+ push:
4
+ tags: ["v*"]
5
+ permissions:
6
+ id-token: write
7
+ contents: write
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.12"
16
+ - run: pip install build
17
+ - run: python -m build
18
+ - uses: pypa/gh-action-pypi-publish@release/v1
19
+ with:
20
+ attestations: true
21
+ - name: Create GitHub Release
22
+ run: gh release create "${{ github.ref_name }}" --generate-notes
23
+ env:
24
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .pytest_cache/
8
+ .ruff_cache/
@@ -0,0 +1,37 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ python3 -m venv .venv && source .venv/bin/activate
7
+ pip install -e . && pip install pytest ruff
8
+ pytest -q && ruff check src tests
9
+ ```
10
+
11
+ CI runs the same on Python 3.10–3.13. Keep it green.
12
+
13
+ ## Ground rules
14
+
15
+ - **Deterministic, read-only, tested.** Parsers never modify harness logs.
16
+ - **Narrow beats bundle.** If a feature doesn't make the receipts more
17
+ trustworthy or more useful, it probably doesn't belong.
18
+ - Every parser change needs fixture transcripts under
19
+ `tests/fixtures/<harness>/` and tests for: parsing, malformed input,
20
+ incremental resume, no-duplicate re-ingest.
21
+ - Price updates touch **only** `src/dashcam/data/models.json`.
22
+ - Never persist full prompts. Run new tool-input shapes through
23
+ `redact()` and add a test proving secrets don't land in SQLite.
24
+ - Don't weaken `store.py`'s transaction discipline, WAL mode, or file
25
+ permissions without discussion.
26
+
27
+ ## Adding a harness
28
+
29
+ See `docs/ARCHITECTURE.md`. The hard requirement: verify the log format
30
+ against real harness output. An unverified parser doesn't ship.
31
+
32
+ ## Commits & PRs
33
+
34
+ - Small, focused commits with clear messages.
35
+ - PRs: describe what changed, what you verified, and how (tests, manual
36
+ runs). Link fixtures to their source format.
37
+ - Be ready to defend every line — this project holds people's receipts.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Varshith Puli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.5
2
+ Name: dashcam-ai
3
+ Version: 0.4.0
4
+ Summary: The dashcam for your AI coding agents — tamper-evident session receipts and cross-provider cost. Read-only.
5
+ Project-URL: Homepage, https://github.com/Varshith-Kali/dashcam
6
+ Project-URL: Repository, https://github.com/Varshith-Kali/dashcam
7
+ Project-URL: Issues, https://github.com/Varshith-Kali/dashcam/issues
8
+ Author: Varshith Puli
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,ai,audit,coding-assistant,cost-tracking,observability
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Software Development :: Debuggers
17
+ Classifier: Topic :: System :: Logging
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: cryptography>=41.0.0
20
+ Requires-Dist: rich>=13.0.0
21
+ Requires-Dist: typer>=0.9.0
22
+ Description-Content-Type: text/markdown
23
+
24
+ <div align="center">
25
+
26
+ # dashcam
27
+
28
+ **The dashcam for your AI coding agents.**
29
+
30
+ [![CI](https://github.com/Varshith-Kali/dashcam/actions/workflows/ci.yml/badge.svg)](https://github.com/Varshith-Kali/dashcam/actions)
31
+ [![PyPI](https://img.shields.io/pypi/v/dashcam-ai)](https://pypi.org/project/dashcam-ai/)
32
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
33
+ [![License: MIT](https://img.shields.io/github/license/Varshith-Kali/dashcam)](LICENSE)
34
+
35
+ *A dashcam doesn't stop the car. It records.*
36
+
37
+ <img src="docs/assets/demo.svg" alt="dashcam today — sessions, tool calls, files touched, tokens and cost per model" width="720">
38
+
39
+ </div>
40
+
41
+ ## The problem
42
+
43
+ Your coding agents take hundreds of actions a day — reading files, running commands, calling models. When something goes wrong (a bad deploy, a surprise bill, an auditor's question), you have **no tape**:
44
+
45
+ - **Harness logs exist but nobody reads them.** Claude Code writes every session to `~/.claude/projects/`, but it's raw JSONL exhaust — no digests, no cost, no verification.
46
+ - **Your SIEM doesn't see it.** Agent activity lives on developer laptops. Nobody pays Splunk ingest pricing for "agent ran `ls` 400 times" — so the tool-call tape simply never reaches the SOC.
47
+ - **Cost is invisible until the invoice.** Tokens scatter across providers and models with no per-session attribution.
48
+
49
+ dashcam reads the logs your agents *already write* and keeps **tamper-evident receipts**: every tool call, every token, every dollar. Read-only. Local-first. Nothing leaves your machine unless you say so.
50
+
51
+ ## What it is
52
+
53
+ - **Session receipts** — every agent session parsed from the harness's own logs into local SQLite, each row hash-chained (`sha256(prev_hash + record)`). `dashcam verify` proves the tape wasn't altered.
54
+ - **Multi-harness** — Claude Code, Codex CLI, Gemini CLI, and opencode, each with a verified parser. `dashcam ingest` reads them all; `dashcam ingest --harness codex` reads one.
55
+ - **Cross-provider cost** — token usage converted to USD per provider/model from a community price table. No proxy, no MITM, no behavior change.
56
+ - **`dashcam today`** — the daily digest: sessions, tool calls, files touched, tokens, spend — plus **unusual-session flags** when a session costs or calls tools far above its project's baseline. `dashcam today --project foo` filters to one project.
57
+ - **Signed bundles** — `dashcam export --format bundle --session <id>` emits an Ed25519-signed portable receipt anyone can verify offline with `dashcam verify-bundle`. The artifact you hand to an auditor.
58
+ - **`dashcam serve`** — a localhost-only read-only timeline UI: today's stats, anomaly flags, recent sessions, per-session detail with chain-integrity check.
59
+ - **`dashcam brief`** — optional BYOK narration: your own API key (OpenAI-compatible or Anthropic) turns the digest into a plain-English briefing. Off by default; only aggregate stats are ever sent.
60
+ - **SIEM-ready** — `dashcam export --format hec` emits Splunk HEC events. dashcam is the edge sensor; your SIEM stays the system of record. See [docs/SIEM.md](docs/SIEM.md).
61
+
62
+ ## What it is not
63
+
64
+ - **Not a firewall.** dashcam never blocks, prompts, or restrains your agent. Blocking sidecars get bypassed by the agent, fatigue the user, and get uninstalled — we chose the other side of that trade on purpose. The tape doesn't lie, and it doesn't nag.
65
+ - **Not a cloud service.** No accounts, no servers, no telemetry. Receipts live in `~/.dashcam/receipts.db`.
66
+
67
+ ## Already have Splunk?
68
+
69
+ Then you know the gap: your SIEM sees EDR process events and proxy logs — *that something ran* — but not the agent's tool-call sequence. dashcam records the tape where the work happens (free, zero-config) and forwards clean JSONL to HEC when you're ready:
70
+
71
+ ```bash
72
+ dashcam export --format hec | curl -H "Authorization: Splunk $HEC_TOKEN" \
73
+ --data-binary @- https://your-splunk:8088/services/collector/event
74
+ ```
75
+
76
+ Regulators are asking for exactly this artifact: the EU AI Act (Art. 12, enforceable since Aug 2026) requires high-risk AI systems to keep **tamper-evident** event logs; SOC 2 and ISO 42001 demand the same discipline. dashcam produces the receipt; your SIEM keeps it. Full mapping in [docs/SIEM.md](docs/SIEM.md).
77
+
78
+ ## Quickstart
79
+
80
+ ```bash
81
+ pipx install dashcam-ai # or: pip install dashcam-ai
82
+ dashcam demo # 60-second tour on a scratch DB — your receipts stay clean
83
+ dashcam ingest # read all your agents' session logs (read-only, resumable)
84
+ dashcam today # what did my agents do today? (+ unusual-session flags)
85
+ dashcam serve # localhost timeline UI at http://127.0.0.1:8321
86
+ dashcam brief # BYOK plain-English briefing (needs your API key)
87
+ dashcam runs # sessions with tool calls, tokens and cost each
88
+ dashcam verify # prove the receipts weren't tampered with
89
+ dashcam export --format bundle --session <id> # signed receipt for auditors
90
+ dashcam export # dump receipts as JSON (or --format hec for Splunk)
91
+ ```
92
+
93
+ ## How it works
94
+
95
+ ```mermaid
96
+ flowchart LR
97
+ A["Agent transcripts<br/>Claude Code · Codex · Gemini · opencode"] -->|"read-only parse<br/>(nothing is modified)"| B["dashcam ingest"]
98
+ B -->|"hash-chained,<br/>one ACID txn per file"| C[("SQLite<br/>~/.dashcam/receipts.db")]
99
+ C --> D["today · brief<br/>(digest + anomaly flags)"]
100
+ C --> E["serve<br/>(localhost UI)"]
101
+ C --> F["verify<br/>(chain check)"]
102
+ C --> G["export --format hec"]
103
+ G --> H["Splunk / SIEM"]
104
+ C --> I["export --format bundle"]
105
+ I --> J["Signed receipt<br/>(auditors, clients)"]
106
+ ```
107
+
108
+ Each recorded row seals the previous one into a SHA-256 chain. Delete or alter a row and `dashcam verify` fails — the same tamper-evidence idea behind signed audit logs, running entirely on your laptop. Details in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
109
+
110
+ ## Security
111
+
112
+ Full threat model in [SECURITY.md](SECURITY.md). The short version:
113
+
114
+ - **Tamper-evident, not tamper-proof** — stated honestly, with the upgrade path documented.
115
+ - **Secret redaction** — command text is scrubbed for recognizable secrets before persistence; full prompts are never stored.
116
+ - **Local-first** — receipts never leave your machine. The only network calls dashcam ever makes are the ones you explicitly opt into: `brief` with your own API key. No telemetry, ever. DB is `0600`, directory `0700`.
117
+ - **Crash-safe** — per-file ingestion is one ACID transaction; concurrent writers can't fork the chain (WAL + `BEGIN IMMEDIATE`).
118
+
119
+ ## Cost data
120
+
121
+ Prices live in [`src/dashcam/data/models.json`](src/dashcam/data/models.json) (USD per 1M tokens). Providers change prices; when they do, send a PR that touches *only* that file. If the table is stale, drop your own `~/.dashcam/pricing.json` (same format) — it overrides the packaged table without a reinstall.
122
+
123
+ ## Roadmap
124
+
125
+ - **v0.1** — the tape: Claude Code transcripts, hash-chained receipts, cost, digest, demo, verify, SIEM export
126
+ - **v0.2** — universal tape: Codex CLI + Gemini CLI parsers, unusual-session flags, Ed25519 signed bundles
127
+ - **v0.3** — opencode parser (SQLite), `dashcam serve` localhost timeline UI, `dashcam today --project`
128
+ - **v0.4** — `dashcam brief`: optional BYOK narration (your key, off by default, aggregates only)
129
+
130
+ The roadmap is complete. What's next is driven by real usage — file an issue with
131
+ what your agents do that dashcam doesn't capture yet. See [docs/ROADMAP.md](docs/ROADMAP.md).
132
+
133
+ ## Honest comparisons
134
+
135
+ - **vs. blocking sidecars** (pre-execution firewalls): they restrain, we record. Restraint gets bypassed by a capable agent and fatigues users; recording stays out of the agent's way and never nags. Different jobs. (Honest scope note: we only see what the harness actually writes to its logs.)
136
+ - **vs. session scorers** (e.g. `agent-dashcam`): they grade your agent's *quality*; we keep the *evidence*. The tape comes before the verdict.
137
+ - **vs. agentmetry** (closest in spirit — local-first flight recorder, hash-chained): they go wider (MITRE mapping, detections, DLP, blocking modes) via IDE hooks; we stay narrow (receipts + cost + digest) and read-only — no hooks to install, none to bypass. Early days for both; pick the philosophy you want.
138
+
139
+ ## Contributing
140
+
141
+ PRs welcome. The bar: deterministic, read-only, tested. Every parser change needs fixture transcripts in `tests/`; price updates touch only the pricing file. See [CONTRIBUTING.md](CONTRIBUTING.md).
142
+
143
+ ## License
144
+
145
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,122 @@
1
+ <div align="center">
2
+
3
+ # dashcam
4
+
5
+ **The dashcam for your AI coding agents.**
6
+
7
+ [![CI](https://github.com/Varshith-Kali/dashcam/actions/workflows/ci.yml/badge.svg)](https://github.com/Varshith-Kali/dashcam/actions)
8
+ [![PyPI](https://img.shields.io/pypi/v/dashcam-ai)](https://pypi.org/project/dashcam-ai/)
9
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
10
+ [![License: MIT](https://img.shields.io/github/license/Varshith-Kali/dashcam)](LICENSE)
11
+
12
+ *A dashcam doesn't stop the car. It records.*
13
+
14
+ <img src="docs/assets/demo.svg" alt="dashcam today — sessions, tool calls, files touched, tokens and cost per model" width="720">
15
+
16
+ </div>
17
+
18
+ ## The problem
19
+
20
+ Your coding agents take hundreds of actions a day — reading files, running commands, calling models. When something goes wrong (a bad deploy, a surprise bill, an auditor's question), you have **no tape**:
21
+
22
+ - **Harness logs exist but nobody reads them.** Claude Code writes every session to `~/.claude/projects/`, but it's raw JSONL exhaust — no digests, no cost, no verification.
23
+ - **Your SIEM doesn't see it.** Agent activity lives on developer laptops. Nobody pays Splunk ingest pricing for "agent ran `ls` 400 times" — so the tool-call tape simply never reaches the SOC.
24
+ - **Cost is invisible until the invoice.** Tokens scatter across providers and models with no per-session attribution.
25
+
26
+ dashcam reads the logs your agents *already write* and keeps **tamper-evident receipts**: every tool call, every token, every dollar. Read-only. Local-first. Nothing leaves your machine unless you say so.
27
+
28
+ ## What it is
29
+
30
+ - **Session receipts** — every agent session parsed from the harness's own logs into local SQLite, each row hash-chained (`sha256(prev_hash + record)`). `dashcam verify` proves the tape wasn't altered.
31
+ - **Multi-harness** — Claude Code, Codex CLI, Gemini CLI, and opencode, each with a verified parser. `dashcam ingest` reads them all; `dashcam ingest --harness codex` reads one.
32
+ - **Cross-provider cost** — token usage converted to USD per provider/model from a community price table. No proxy, no MITM, no behavior change.
33
+ - **`dashcam today`** — the daily digest: sessions, tool calls, files touched, tokens, spend — plus **unusual-session flags** when a session costs or calls tools far above its project's baseline. `dashcam today --project foo` filters to one project.
34
+ - **Signed bundles** — `dashcam export --format bundle --session <id>` emits an Ed25519-signed portable receipt anyone can verify offline with `dashcam verify-bundle`. The artifact you hand to an auditor.
35
+ - **`dashcam serve`** — a localhost-only read-only timeline UI: today's stats, anomaly flags, recent sessions, per-session detail with chain-integrity check.
36
+ - **`dashcam brief`** — optional BYOK narration: your own API key (OpenAI-compatible or Anthropic) turns the digest into a plain-English briefing. Off by default; only aggregate stats are ever sent.
37
+ - **SIEM-ready** — `dashcam export --format hec` emits Splunk HEC events. dashcam is the edge sensor; your SIEM stays the system of record. See [docs/SIEM.md](docs/SIEM.md).
38
+
39
+ ## What it is not
40
+
41
+ - **Not a firewall.** dashcam never blocks, prompts, or restrains your agent. Blocking sidecars get bypassed by the agent, fatigue the user, and get uninstalled — we chose the other side of that trade on purpose. The tape doesn't lie, and it doesn't nag.
42
+ - **Not a cloud service.** No accounts, no servers, no telemetry. Receipts live in `~/.dashcam/receipts.db`.
43
+
44
+ ## Already have Splunk?
45
+
46
+ Then you know the gap: your SIEM sees EDR process events and proxy logs — *that something ran* — but not the agent's tool-call sequence. dashcam records the tape where the work happens (free, zero-config) and forwards clean JSONL to HEC when you're ready:
47
+
48
+ ```bash
49
+ dashcam export --format hec | curl -H "Authorization: Splunk $HEC_TOKEN" \
50
+ --data-binary @- https://your-splunk:8088/services/collector/event
51
+ ```
52
+
53
+ Regulators are asking for exactly this artifact: the EU AI Act (Art. 12, enforceable since Aug 2026) requires high-risk AI systems to keep **tamper-evident** event logs; SOC 2 and ISO 42001 demand the same discipline. dashcam produces the receipt; your SIEM keeps it. Full mapping in [docs/SIEM.md](docs/SIEM.md).
54
+
55
+ ## Quickstart
56
+
57
+ ```bash
58
+ pipx install dashcam-ai # or: pip install dashcam-ai
59
+ dashcam demo # 60-second tour on a scratch DB — your receipts stay clean
60
+ dashcam ingest # read all your agents' session logs (read-only, resumable)
61
+ dashcam today # what did my agents do today? (+ unusual-session flags)
62
+ dashcam serve # localhost timeline UI at http://127.0.0.1:8321
63
+ dashcam brief # BYOK plain-English briefing (needs your API key)
64
+ dashcam runs # sessions with tool calls, tokens and cost each
65
+ dashcam verify # prove the receipts weren't tampered with
66
+ dashcam export --format bundle --session <id> # signed receipt for auditors
67
+ dashcam export # dump receipts as JSON (or --format hec for Splunk)
68
+ ```
69
+
70
+ ## How it works
71
+
72
+ ```mermaid
73
+ flowchart LR
74
+ A["Agent transcripts<br/>Claude Code · Codex · Gemini · opencode"] -->|"read-only parse<br/>(nothing is modified)"| B["dashcam ingest"]
75
+ B -->|"hash-chained,<br/>one ACID txn per file"| C[("SQLite<br/>~/.dashcam/receipts.db")]
76
+ C --> D["today · brief<br/>(digest + anomaly flags)"]
77
+ C --> E["serve<br/>(localhost UI)"]
78
+ C --> F["verify<br/>(chain check)"]
79
+ C --> G["export --format hec"]
80
+ G --> H["Splunk / SIEM"]
81
+ C --> I["export --format bundle"]
82
+ I --> J["Signed receipt<br/>(auditors, clients)"]
83
+ ```
84
+
85
+ Each recorded row seals the previous one into a SHA-256 chain. Delete or alter a row and `dashcam verify` fails — the same tamper-evidence idea behind signed audit logs, running entirely on your laptop. Details in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
86
+
87
+ ## Security
88
+
89
+ Full threat model in [SECURITY.md](SECURITY.md). The short version:
90
+
91
+ - **Tamper-evident, not tamper-proof** — stated honestly, with the upgrade path documented.
92
+ - **Secret redaction** — command text is scrubbed for recognizable secrets before persistence; full prompts are never stored.
93
+ - **Local-first** — receipts never leave your machine. The only network calls dashcam ever makes are the ones you explicitly opt into: `brief` with your own API key. No telemetry, ever. DB is `0600`, directory `0700`.
94
+ - **Crash-safe** — per-file ingestion is one ACID transaction; concurrent writers can't fork the chain (WAL + `BEGIN IMMEDIATE`).
95
+
96
+ ## Cost data
97
+
98
+ Prices live in [`src/dashcam/data/models.json`](src/dashcam/data/models.json) (USD per 1M tokens). Providers change prices; when they do, send a PR that touches *only* that file. If the table is stale, drop your own `~/.dashcam/pricing.json` (same format) — it overrides the packaged table without a reinstall.
99
+
100
+ ## Roadmap
101
+
102
+ - **v0.1** — the tape: Claude Code transcripts, hash-chained receipts, cost, digest, demo, verify, SIEM export
103
+ - **v0.2** — universal tape: Codex CLI + Gemini CLI parsers, unusual-session flags, Ed25519 signed bundles
104
+ - **v0.3** — opencode parser (SQLite), `dashcam serve` localhost timeline UI, `dashcam today --project`
105
+ - **v0.4** — `dashcam brief`: optional BYOK narration (your key, off by default, aggregates only)
106
+
107
+ The roadmap is complete. What's next is driven by real usage — file an issue with
108
+ what your agents do that dashcam doesn't capture yet. See [docs/ROADMAP.md](docs/ROADMAP.md).
109
+
110
+ ## Honest comparisons
111
+
112
+ - **vs. blocking sidecars** (pre-execution firewalls): they restrain, we record. Restraint gets bypassed by a capable agent and fatigues users; recording stays out of the agent's way and never nags. Different jobs. (Honest scope note: we only see what the harness actually writes to its logs.)
113
+ - **vs. session scorers** (e.g. `agent-dashcam`): they grade your agent's *quality*; we keep the *evidence*. The tape comes before the verdict.
114
+ - **vs. agentmetry** (closest in spirit — local-first flight recorder, hash-chained): they go wider (MITRE mapping, detections, DLP, blocking modes) via IDE hooks; we stay narrow (receipts + cost + digest) and read-only — no hooks to install, none to bypass. Early days for both; pick the philosophy you want.
115
+
116
+ ## Contributing
117
+
118
+ PRs welcome. The bar: deterministic, read-only, tested. Every parser change needs fixture transcripts in `tests/`; price updates touch only the pricing file. See [CONTRIBUTING.md](CONTRIBUTING.md).
119
+
120
+ ## License
121
+
122
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,65 @@
1
+ # Security policy
2
+
3
+ ## What dashcam is
4
+
5
+ A read-only, local-first flight recorder. It parses the session logs your
6
+ coding agents already write, keeps hash-chained receipts in SQLite, and
7
+ never sends anything anywhere. There is no network code in this project —
8
+ no telemetry, no accounts, no cloud sync, no update checks.
9
+
10
+ ## Threat model
11
+
12
+ **In scope:**
13
+
14
+ - *Post-hoc tampering with receipts.* Every evidentiary row (tool call,
15
+ spend) is sealed into a SHA-256 hash chain in global insertion order.
16
+ `dashcam verify` recomputes the chain; altering or deleting a row breaks
17
+ it. This catches accidental corruption (crashes, bit rot, partial
18
+ writes) and unsophisticated tampering.
19
+ - *Secret leakage into receipts.* Command text and tool inputs pass
20
+ through deterministic redaction (`src/dashcam/redact.py`) before they
21
+ are persisted, and text is truncated. Full prompts are never stored.
22
+ - *Local file exposure.* The database directory is created `0700` and the
23
+ database `0600` (POSIX). Receipts can contain command text — they are
24
+ not world-readable.
25
+ - *Concurrent writers.* SQLite WAL mode, `BEGIN IMMEDIATE` around every
26
+ read-modify-write (so two processes can't fork the chain), a re-entrant
27
+ lock for threads, 30s busy timeout. Per-file ingestion runs inside one
28
+ ACID transaction: a crash mid-file rolls back instead of leaving half a
29
+ transcript.
30
+
31
+ **Out of scope — stated plainly:**
32
+
33
+ - The chain is **tamper-evident, not tamper-proof**. It is not keyed: an
34
+ attacker with unrestricted write access to `receipts.db` *and* the
35
+ knowledge to recompute the chain could forge a valid-looking history.
36
+ What the chain guarantees is *detection* of any modification by parties
37
+ who can't or don't rebuild it, plus all accidental corruption. If you
38
+ need proof against a fully-privileged local attacker, keep independent
39
+ copies of the database (backups detect divergence) — and see the
40
+ roadmap note on keyed receipts below.
41
+ - dashcam does not sandbox, block, or restrain your agents. It is a
42
+ recorder. A compromised agent is outside this project's scope to stop;
43
+ the point is that the tape survives to show what happened.
44
+ - Redaction is best-effort pattern matching, not a guarantee. Exotic
45
+ secret formats will slip through. Treat receipts as sensitive and keep
46
+ the `0600` permissions intact.
47
+
48
+ **Roadmap (not yet built):** keyed receipts — HMAC-SHA256 with the key
49
+ held in the OS keychain, so forging the chain requires keychain access
50
+ too. This is the honest upgrade path from tamper-evident to tamper-proof.
51
+
52
+ ## Reporting a vulnerability
53
+
54
+ Open a GitHub issue titled `[security]` with the details. Do not include
55
+ secrets, tokens, or private data in the report. This is a young project;
56
+ response time is best-effort but reports are taken seriously.
57
+
58
+ ## For contributors
59
+
60
+ - Parsers must be read-only: never modify the harness logs.
61
+ - Never persist full prompts, and run new tool-input shapes through
62
+ `redact()` — add a test in `tests/` proving the secret doesn't land in
63
+ the database.
64
+ - Don't weaken file permissions, WAL mode, or the transaction discipline
65
+ in `store.py` without discussion in the PR.
@@ -0,0 +1,120 @@
1
+ # Architecture
2
+
3
+ ```
4
+ harness logs (read-only) local receipt store outputs
5
+ ──────────────────────── ─────────────────── ───────
6
+ ~/.claude/projects/*/*.jsonl
7
+ ~/.codex/sessions/**/*.jsonl ──┐
8
+ ~/.gemini/tmp/**/chats/*.{json,jsonl} │
9
+ │ parsers (ingest/) │ SQLite, hash-chained
10
+ │ resume via file offsets│ ┌──────────────┐
11
+ ▼ │ │ events, spend │──► dashcam today (digest + anomaly flags)
12
+ dashcam ingest ──atomic/file──► │ │ sessions │──► dashcam runs
13
+ │ │ meta (offsets,│──► dashcam verify
14
+ │ │ chain head) │──► dashcam export (JSON / HEC / signed bundle)
15
+ └──────────────┘ └──► dashcam verify-bundle (offline)
16
+ ```
17
+
18
+ ## The chain
19
+
20
+ Each evidentiary row seals the previous one:
21
+
22
+ ```
23
+ hash_n = sha256(hash_{n-1} + canonical_json({kind, seq, ...payload}))
24
+ ```
25
+
26
+ - `seq` is a global monotonic counter across *both* tables, so verify
27
+ recomputes rows in exactly the order they were sealed — interleaved
28
+ event/spend writes verify correctly.
29
+ - `canonical_json` is `json.dumps(sort_keys=True, separators=(",",":"))`.
30
+ - Genesis is 64 zeroes. The head hash and seq live in `meta`.
31
+ - `verify()` recomputes every row and compares both the per-row hash and
32
+ the stored head. Any modification or deletion is detected.
33
+
34
+ `sessions` is index metadata (id, harness, project, timestamps) and is
35
+ not chained; the *evidence* — what the agent did and what it cost — is.
36
+
37
+ ## Ingestion
38
+
39
+ - Parsers translate one harness's log format into normalized
40
+ `Session` / `ToolEvent` / `Spend` records. See `ingest/base.py`.
41
+ - Resume: per-file line offsets are stored in `meta` (`file:<path>`), so
42
+ re-running `ingest` only reads new lines. Sessions are idempotent
43
+ (`INSERT OR IGNORE` + offset tracking); re-ingestion never duplicates.
44
+ - Malformed lines are skipped, never fatal. A parser must be total.
45
+ - Each file's writes happen inside `Store.atomic()`: one ACID
46
+ transaction per file.
47
+ - Summaries are truncated and passed through `redact()` before storage.
48
+
49
+ ## Cost
50
+
51
+ `src/dashcam/data/models.json` maps `provider/model` → USD per 1M input/output
52
+ tokens. Cost is computed at ingest from transcript token counts — no
53
+ model calls, no proxy. Unknown models record `$0` and warn; price updates
54
+ are data-only PRs touching just that file.
55
+
56
+ ## Adding a harness parser
57
+
58
+ 1. Read `ingest/base.py` — implement `HARNESS`, `iter_transcripts`,
59
+ `parse_transcript`.
60
+ 2. **Verify the format against real harness output.** A parser whose
61
+ format can't be confirmed against the actual harness does not ship:
62
+ wrong receipts are worse than missing ones.
63
+ 3. Add fixtures under `tests/fixtures/<harness>/` copied from real
64
+ (sanitized) logs, and tests covering: parsing, malformed lines,
65
+ incremental resume, dedup on re-ingest.
66
+ 4. Register it in `cli.PARSERS`.
67
+
68
+ ## Concurrency
69
+
70
+ WAL mode + `BEGIN IMMEDIATE` on every read-modify-write + re-entrant
71
+ thread lock + 30s busy timeout. Two `dashcam ingest` processes (or two
72
+ agents' harnesses writing logs while dashcam reads) don't corrupt the
73
+ store and can't fork the chain.
74
+
75
+ ## What this is not
76
+
77
+ No firewall, no blocking, no prompt-injection judge, no network. The
78
+ narrowness is the design: every feature must keep the receipt layer
79
+ trustworthy, or it doesn't ship.
80
+
81
+ ## Anomaly surfacing (`anomaly.py`)
82
+
83
+ Explainable statistics, no ML. For each (project, harness) pair, the
84
+ trailing-30-day median per-session cost and tool-call count form the
85
+ baseline (median is robust to the outliers being hunted). A session is
86
+ flagged when it exceeds 3x the median on cost (floor: $1) or tool calls
87
+ (floor: 10), and only when at least 5 baseline sessions exist — so new
88
+ projects don't cry wolf. `dashcam today` shows the flags with the
89
+ baseline numbers that triggered them.
90
+
91
+ ## Signed bundles (`signing.py`)
92
+
93
+ The hash chain proves the local DB wasn't altered in place, but it can't
94
+ leave the machine. `dashcam init` creates a local Ed25519 keypair
95
+ (`~/.dashcam/signing.key`, mode 0600). `export --format bundle --session
96
+ <id>` emits the session's canonical receipts plus signature and public
97
+ key; `verify-bundle` checks the signature offline with no database
98
+ access. This proves *provenance* — these receipts came from this dashcam
99
+ identity, unaltered since signing — not protection against an attacker
100
+ who owned the machine before signing. Keep offline copies of bundles
101
+ for that threat.
102
+
103
+ ## Local UI (`serve.py`)
104
+
105
+ `dashcam serve` renders a read-only timeline over the receipts with stdlib
106
+ `http.server` only — no frameworks, no JavaScript. It binds 127.0.0.1,
107
+ answers GET, and 405s everything else; user-controlled strings are
108
+ HTML-escaped at render time. `/` shows today's cards, anomaly flags,
109
+ recent sessions, and cost by harness; `/session?id=` shows tool calls,
110
+ spend, and a per-session chain-link check (`dashcam verify` remains the
111
+ full-chain authority).
112
+
113
+ ## BYOK narration (`brief.py`)
114
+
115
+ `dashcam brief` is the only network-calling feature, and it's off unless
116
+ you configure a key (`DASHCAM_API_KEY` or `~/.dashcam/llm.json`, 0600).
117
+ It sends the *aggregate* digest text — counts, costs, top tools, anomaly
118
+ flags — never raw summaries or prompt text, to an OpenAI-compatible or
119
+ Anthropic endpoint over stdlib `urllib`. The system prompt forbids
120
+ inventing numbers. Receipts stay the source of truth; the model narrates.
@@ -0,0 +1,42 @@
1
+ # dashcam roadmap
2
+
3
+ Principle: **depth on the core thesis** — the universal, intelligent,
4
+ undeniable tape. A feature ships only if it makes the receipts more
5
+ universal, more intelligent, or more portable.
6
+
7
+ ## v0.1 — the tape (shipped)
8
+ - Claude Code transcript ingestion (read-only, resumable)
9
+ - Hash-chained SQLite receipts + `dashcam verify`
10
+ - Cross-provider cost from `src/dashcam/data/models.json`
11
+ - `dashcam today` digest, `dashcam runs`, `dashcam demo`
12
+ - Splunk HEC export (`docs/SIEM.md`)
13
+ - CI (ruff + pytest on 3.10–3.13), PyPI trusted publishing with Sigstore attestations
14
+
15
+ ## v0.2 — universal tape (shipped)
16
+ - Codex CLI + Gemini CLI parsers (verified against documented formats);
17
+ `dashcam ingest` reads all harnesses, `--harness` selects one
18
+ - Unusual-session flags in `dashcam today` (median-baseline anomaly surfacing)
19
+ - Ed25519 signed bundles: `export --format bundle` + `verify-bundle`
20
+ (offline-verifiable receipts for auditors)
21
+
22
+ ## v0.3 — more harnesses, more surface (shipped)
23
+ - opencode session parser (SQLite source, read-only, fork-deduped)
24
+ - `dashcam serve`: localhost-only read-only timeline UI (stdlib only)
25
+ - Per-project digests (`dashcam today --project foo`)
26
+
27
+ ## v0.4 — optional brains (shipped, all off by default)
28
+ - `dashcam brief`: BYOK narration of the digest via your own key
29
+ (OpenAI-compatible or Anthropic, stdlib HTTP). Deterministic receipts
30
+ stay the source of truth; the model only narrates. Only aggregate
31
+ stats are ever sent — never prompts or tool output.
32
+
33
+ ## What's next
34
+
35
+ The planned roadmap is complete. Further work is driven by real usage:
36
+ file an issue describing what your agents do that dashcam doesn't
37
+ capture yet.
38
+
39
+ ## Non-goals (will not build)
40
+ - Pre-execution blocking / firewalls — bypassable, fatiguing, uninstall-bait
41
+ - Cloud sync, accounts, telemetry of any kind
42
+ - LLM-as-judge verdicts on agent behavior — evidence in, verdicts out