最新资讯
bloomberg.com Google 接手 Crusoe 曾推介的怀俄明州数据中心 techxplore.com 三种新技术针对隐藏 AI 后门且不显著损失性能 unite.ai OpenAI CFO 称中期选举后数据中心建设仍将继续 techcrunch.com 数百个 Artex AI 黑客工具服务器暴露在公网 techcrunch.com Meta 推出 Spaces,为 Muse 智能体提供新协作方式 wired.com Wired:免费中国 AI 模型的黑客能力快速提升 unite.ai OpenAI 与 Hacktron 合作测试第三方服务连接安全 dev.to 如何将 PostgreSQL 接入 AI agent 并对写入操作设置审批 unite.ai AWS 在 SageMaker 推理端点加入 NVIDIA GPU 分区支持 unite.ai BMO 在信用卡客服引入 agentic AI 案件准备 theverge.com Meta 的 Muse AI 可创建自定义 spaces,按需生成应用式体验 thenewstack.io Meta 用最强 AI 模型训练多数用户实际使用的模型
多元动态
登录 注册
智能体 github.com · @dillonsmartdev

Docket:为 agent 编写的代码提供逐 commit 证据记录

原文 我的收藏

Docket 是一个单静态二进制工具,用于捕获 coding agent 在提交时通常被丢弃的实现过程信息,并将其与 diff 折叠,生成按 hunk 的证据记录,标注哪些行有覆盖率、测试执行等证据、哪些行无人查看。示例输出包含记录哈希、本地签名校验、证据密度、来源模型与任务意图、被取代的尝试及测试失败记录。记录存放在仓库的 orphan ref 中,无需账号和网络。项目提供安装脚本、SHA256SUMS 校验和演示脚本,但未给出独立验证或实际使用效果数据。

AI推荐理由 针对 coding agent 生成代码难以审查的痛点,提出按 commit 记录 agent 实现过程证据(尝试、测试结果、覆盖率、人工接触情况)并折叠到 diff 的 per-hunk 证据记录,思路具体且有 CLI 示例。但正文为项目自述,未提供独立验证或实际使用效果数据,安装脚本与发布校验仅说明分发方式,不能证明工具可靠性;trust 字段自述为 local_claimed,证据链的可信度依赖本地签名。

72 评论 5 社区积分 18

正文

A per-commit evidence record for agent-written code. Coding agents produce code faster than anyone can verify it. The reviewer receives a finished diff with no implementation journey: no record of what the agent tried first, what it verified, or which lines nobody ever looked at. The harness already emits that journey and then throws it away at commit time. Docket captures it, folds it against the diff, and produces a per-hunk evidence record — so review attention lands where there is no evidence. $ docket show HEAD docket 7a9da95a2a748c2fb99706f48f2ddf64760ffab2 record sha256:046c5278e93cb516e3ba72400fd1a69648c85b93833d31d57648e9ed8e535ebf trust local_claimed (signed on local) verified digest and signature check out (ed25519:f889a26cbc34c95e) 1 hunks in 1 files, 4 added lines 100% of added lines attributed to a recorded edit mean evidence density 0.77 src/auth.js:3-6 (4 lines) covered density 0.77 origin claude-code/main via Edit (reported by the harness) claude-opus-5 task Fix session fixation on login intent The raw UUID is reused across logins, so minting a prefixed id instead. attempt Stamping a creation time on the session so expiry can be checked. [superseded] vitest failed after this change: npx vitest run evidence coverage: 4 of 4 lines executed (coverage/coverage-final.json) evidence test_execution: pass (npx vitest run --coverage) — failed before this change human no recorded human contact with these lines No account. No network. The records live in the repository, on an orphan ref. Install A single static binary. No Go toolchain, no runtime, nothing to compile. curl -fsSL https://raw.githubusercontent.com/Dillonsmart/docket/main/install.sh | sh Or take the archive for your platform from the releases page — macOS and Linux on arm64 and x86-64, Windows on both — unpack it, and put docket on your PATH. Every release publishes SHA256SUMS; the installer checks them for you. Building from source stays available for anyone who wants it: go install github.com/Dillonsmart/docket/cmd/docket@latest Then, in a repository: docket init See it before instrumenting anything scripts/demo.sh It builds a throwaway repository in a temp directory with a recorded session in it — an agent fixes a session fixation bug, gets it wrong once, watches a test fail, fixes it properly — and prints the docket for the commit. Your own repositories are not touched, and the directory is deleted on exit. Upgrading Re-run the installer. It overwrites the binary in place with the newest release: curl -fsSL https://raw.githubusercontent.com/Dillonsmart/docket/main/install.sh | sh docket version says what you have; the releases page says what is current. To pin, or to go back, name the tag: curl -fsSL https://raw.githubusercontent.com/Dillonsmart/docket/main/install.sh | DOCKET_VERSION=v0.0.2 sh (The variable goes on the sh side of the pipe. In front of curl it would be set for the download and not for the script.) From source, it is go install github.com/Dillonsmart/docket/cmd/docket@latest. In CI, the action's default version: latest takes the newest release on every run; pin it to a tag if you would rather decide when that happens. Nothing needs migrating. Records already stored stay readable — each one carries the schema version it was written against — and there is no local state beyond the signing key, which upgrades never touch. You only need to re-run docket init if the binary lands somewhere new. The hooks call it by absolute path, falling back to whatever docket is on PATH, so an upgrade in place needs nothing; installing to a different directory and deleting the old copy is the case where the recorded path goes stale. That installs a prepare-commit-msg hook (which writes the trailer — the audited agent never writes its own audit record), a post-commit hook (which stores the record), the refs/docket/* refspec, a local signing key, and the Claude Code hooks that let docket observe edits made through the shell. From then on, every commit gets one extra line, in the trailer block where Signed-off-by and Reviewed-by live: Add the session helper The API needs a stable id per session, and the obvious place is here rather than in the middleware. Reviewed-by: Someone Else Docket: sha256:db77fdb4b0c1fc6cc7644d3fa2204267e25799d74a6f8f665aff3d32b12c39af That is the whole footprint in your history. git log --oneline is unchanged, your subject line is untouched, and the digest names a signed record on refs/docket/records rather than a URL — so nothing in the permanent history depends on a service still existing. Amending rebuilds the record and replaces the trailer, so a commit never points at the content it used to have. A merge gets no trailer, and neither does a commit with nothing attributable in it. Rebases and cherry-picks are the awkward case: git does not run prepare-commit-msg for either, so the trailer travels onto a diff it was not built from — docket verify reports that plainly rather than trusting the trailer. To stop: delete the two hooks in .git/hooks. Existing trailers stay in the history as inert text. Use it docket show HEAD # the record for a commit, risk-ordered docket explain src/auth.js:51 # why does this line exist? (via git blame) docket review --format md # the pull request comment docket verify HEAD # digest, signature and commit binding docket push # send the records to the remote docket doctor # what can docket see here, and what can't it docket gate --commits 20 # measure attribution against real history For pull requests, the GitHub Action reads the records the commits brought with them and posts one comment, reordering the diff so the hunks nothing can vouch for come first and the well-covered boilerplate is collapsed underneath. It downloads the same binary, so nothing needs installing on the runner either. Reading someone's reasoning back The fields that answer why does this code look like this are task, intent and attempt: task — the request this edit descends from, i.e. what the human actually asked for. intent — what the agent said it was doing in the sentence immediately before it made the edit. This is where the reasoning lands, in the agent's own words. attempt — code written into this same region and then taken out again, with the check that failed in between when there was one. The abandoned approaches are the part that is otherwise lost within hours. $ docket explain database/migrations/0001_01_01_000000_create_players_table.php:54 database/migrations/…:54 was last written by be66f35c5977 origin claude-code/main via Edit task Look at the engine plan for this project, challenge any assumptions then start implementing intent Postgres `jsonb` normalises key order, so the replayed response wasn't byte-identical to the original. For a stored response we only ever return verbatim, `json` is the right column type. attempt Now the schema. Replacing the default `users` table with `players` as the authenticatable model. [superseded] docket explain finds the commit through git blame, so you can start from the code in front of you rather than having to know which commit to look in. docket show --all --json gives the whole record if you would rather read it as data. Docket stores short redacted excerpts, not the conversation: enough to reconstruct the decision, never the whole transcript, because whole transcripts carry secrets and grow without bound. How it works Attribution. Docket parses the agent transcript into an ordered event stream, replays every recorded edit per file, and carries a provenance vector — one origin per line — forward through subsequent edits. At commit time it aligns the committed file against that replay and resolves each hunk. A line is attributed only when its text is found at the aligned position and in the recorded output of the edit being credited. Timestamps only order events; they never justify an attribution. When an edit's recorded pre-image disagrees with the replay — because a shell command, an editor or a person changed the file in between — the disagreement is detected, the affected lines become unknown, and the replay re-seeds from the recorded truth. Carrying a reconstruction past a disagreement is how tools produce confident, wrong answers. An attribution engine that is confidently wrong is worse than no product, so unknown is always an available answer, and it always comes with a reason. Agents. Docket reads Claude Code, Codex CLI and opencode. Everything downstream — replay, attribution, evidence, the record — is agent-agnostic, so supporting another agent is a reader, not a redesign: Agent Where its session lives What docket gets from it Claude Code ~/.claude/projects/**/*.jsonl Edit/Write calls with before and after images, shell commands, prompts, the agent's own narration Codex CLI ~/.codex/sessions/**/rollout-*.jsonl apply_patch calls, shell commands with exit codes, prompts, narration opencode ~/.local/share/opencode/opencode.db (needs sqlite3) write/edit calls with diffs, shell commands with exit codes, prompts, narration anything else — wire its hooks to docket collect pre / docket collect post and the edits are observed directly Codex and opencode send patches rather than whole files, so their edits carry no before-image. Docket seeds the replay from the base revision and applies the patch to the content it was actually written against; when that does not fit, it re-seeds and marks what it cannot explain rather than placing the hunk by guesswork. Observation. Reading the transcript recovers Edit and Write calls. An agent that writes files through the shell — a heredoc, sed -i, a generator, a formatter — leaves nothing there to recover. So docket watches the working tree itself: a PreToolUse hook snapshots content, a PostToolUse hook diffs it, and both images are stored as git blobs. Those edits are marked observed rather than transcript, because docket read them itself. Evidence. Test runs, type checks and static analysis are correlated with the edits they followed — a check that ran before the code was written is not evidence about it. Coverage reports (istanbul coverage-final.json, lcov) are matched line by line against the hunk, and ignored when the report is older than the code it would otherwise appear to cover. Density. One number per hunk, between 0 and 1, published in full rather than tuned in private: coverage of these lines is worth at most 0.5, a check that passed after the edit 0.3 (0.35 if this change turned it green), type and static checks 0.1 together, recorded human contact 0.1. If nothing executed the code, the score is capped at 0.15. If nobody can say who wrote it, at 0.5. A locally-claimed record scores 0.9 of what a CI-attested one would. Those caps are the point. This number will be turned into a target, exactly as coverage was, and a metric you can raise without running anything is worse than no metric. How well does attribution actually work Docket measures itself. docket gate replays real sessions against real commits and reports what it could and could not explain: Session Agent Hunks in files the session edited Added lines Content-verified A Laravel engine, Edit/Write tools (4 commits, 98 edits) Claude Code 98.1% 99.8% 100% A Python app, apply_patch (4 commits, 256 edits) Codex CLI 94.7% 95.7% 99.8% A FastAPI project, 100 edits (uncommitted, measured against the working tree) opencode — 92.9% — A PHP framework built largely through the shell (12 commits, 79 edits) Claude Code 59.2% 82.1% 100% Two things to take from this. Every attribution was verified against the crediting edit's own recorded output — docket did not credit a line to an edit that did not write it. And the last row is why the collector exists: those sessions wrote files with heredocs and sed, which no transcript records, and that work happened before docket could observe it. With docket init in place, those edits are observed directly. Across whole diffs the headline rate is lower — 40%, 94%, 37% — because real commits also contain composer.lock, scaffolded models and generated code that no agent edit ever touched. Docket reports those as unknown with the commands that ran nearby listed as candidates, never as attributions. That is the honest answer, and it is deliberately not smoothed into the number. Run it on your own history: docket gate --commits 20 What it is not Not orchestration, task assignment or agent spawning. Not agent-to-agent handoff or provider routing. Not a window you live in. It annotates the review surface you already use. Not a live dashboard. Not something that asks for an account before it does anything. Privacy Traces contain raw prompts, file contents and terminal output. So: Everything that reaches a record goes through an aggressive redaction pass: known credential shapes, private keys, JWTs, authorization headers, connection-string credentials, KEY=/SECRET=/PASSWORD= assignments — and, failing closed, any long token whose character distribution looks random. A record stores short redacted excerpts, never whole files or whole prompts. Nothing is sent anywhere. The records live in your repository, and docket push sends them to the git host you already trust. The signing key lives in .git/docket/ and never leaves the machine. Trust Tier Meaning local_claimed Built on a developer machine, signed with a key that machine holds. It is a claim. ci_attested Built by a runner, signed with a key the developer does not hold. Set DOCKET_SIGNING_KEY in CI. The distinction is in the schema from day one and is shown everywhere a record is rendered. The format The record format is specified separately as the Commit Evidence Record, with a JSON Schema. Docket is its reference implementation. The specification is Apache 2.0 and deliberately boring: it is meant to be implemented by other tools, including ones that compete with this one. Status Built and working: attribution, the shell-edit collector, redaction, signed records on an orphan ref, coverage and test correlation, the terminal viewer, explain, the pull request comment, the GitHub Action, and the self-measurement gate. Not built yet: readers for Gemini CLI and anything ACP-native, coverage correlation beyond istanbul/lcov, GitLab, cross-repository aggregation, policy gates on paths, and the hosted team tier. Licence Apache 2.0. See LICENSE and NOTICE.

来源报道 · 2 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容