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.
- dashcam_ai-0.4.0/.github/workflows/ci.yml +16 -0
- dashcam_ai-0.4.0/.github/workflows/release.yml +24 -0
- dashcam_ai-0.4.0/.gitignore +8 -0
- dashcam_ai-0.4.0/CONTRIBUTING.md +37 -0
- dashcam_ai-0.4.0/LICENSE +21 -0
- dashcam_ai-0.4.0/PKG-INFO +145 -0
- dashcam_ai-0.4.0/README.md +122 -0
- dashcam_ai-0.4.0/SECURITY.md +65 -0
- dashcam_ai-0.4.0/docs/ARCHITECTURE.md +120 -0
- dashcam_ai-0.4.0/docs/ROADMAP.md +42 -0
- dashcam_ai-0.4.0/docs/SIEM.md +69 -0
- dashcam_ai-0.4.0/docs/assets/demo.svg +176 -0
- dashcam_ai-0.4.0/pyproject.toml +44 -0
- dashcam_ai-0.4.0/src/dashcam/__init__.py +7 -0
- dashcam_ai-0.4.0/src/dashcam/anomaly.py +108 -0
- dashcam_ai-0.4.0/src/dashcam/brief.py +164 -0
- dashcam_ai-0.4.0/src/dashcam/cli.py +387 -0
- dashcam_ai-0.4.0/src/dashcam/cost.py +58 -0
- dashcam_ai-0.4.0/src/dashcam/data/models.json +1 -0
- dashcam_ai-0.4.0/src/dashcam/demo.py +87 -0
- dashcam_ai-0.4.0/src/dashcam/digest.py +134 -0
- dashcam_ai-0.4.0/src/dashcam/ingest/__init__.py +8 -0
- dashcam_ai-0.4.0/src/dashcam/ingest/base.py +31 -0
- dashcam_ai-0.4.0/src/dashcam/ingest/claude_code.py +130 -0
- dashcam_ai-0.4.0/src/dashcam/ingest/codex.py +148 -0
- dashcam_ai-0.4.0/src/dashcam/ingest/gemini.py +194 -0
- dashcam_ai-0.4.0/src/dashcam/ingest/opencode.py +272 -0
- dashcam_ai-0.4.0/src/dashcam/models.py +35 -0
- dashcam_ai-0.4.0/src/dashcam/redact.py +49 -0
- dashcam_ai-0.4.0/src/dashcam/serve.py +239 -0
- dashcam_ai-0.4.0/src/dashcam/signing.py +119 -0
- dashcam_ai-0.4.0/src/dashcam/store.py +268 -0
- dashcam_ai-0.4.0/tests/test_adversarial.py +195 -0
- dashcam_ai-0.4.0/tests/test_anomaly.py +80 -0
- dashcam_ai-0.4.0/tests/test_brief.py +116 -0
- dashcam_ai-0.4.0/tests/test_cli.py +115 -0
- dashcam_ai-0.4.0/tests/test_codex_parser.py +91 -0
- dashcam_ai-0.4.0/tests/test_dashcam.py +268 -0
- dashcam_ai-0.4.0/tests/test_gemini_parser.py +85 -0
- dashcam_ai-0.4.0/tests/test_opencode_parser.py +134 -0
- dashcam_ai-0.4.0/tests/test_serve.py +85 -0
- 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,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.
|
dashcam_ai-0.4.0/LICENSE
ADDED
|
@@ -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
|
+
[](https://github.com/Varshith-Kali/dashcam/actions)
|
|
31
|
+
[](https://pypi.org/project/dashcam-ai/)
|
|
32
|
+
[](https://www.python.org/)
|
|
33
|
+
[](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
|
+
[](https://github.com/Varshith-Kali/dashcam/actions)
|
|
8
|
+
[](https://pypi.org/project/dashcam-ai/)
|
|
9
|
+
[](https://www.python.org/)
|
|
10
|
+
[](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
|