The audit primitive nobody is building. Draft reviewable, cryptographically-stamped time entries from Claude Code session logs. Lawyer accepts / edits / rejects every row before anything reaches a billing system. The tool never bills.
If you bill a client for AI-assisted work, you need to be able to prove — to your client, to opposing counsel, and to your bar — exactly how AI was used and that you reviewed every line. The opinions are out and stacking up:
- ABA Formal Opinion 512 (July 2024) — competence, confidentiality, supervision, candor, fees.
- Florida Bar Op. 24-1 (Jan 2024) — first state opinion dedicated to GAI. Binding on Florida lawyers.
- California State Bar Practical Guidance (Nov 2023) — closest thing to a CA position pending rulemaking.
- NYSBA AI Task Force Report + NYCBA Op. 2024-5 (Apr 2024).
- DC Bar Op. 388 (Apr 2024).
- More coming, monthly.
Every one of them says some version of: bill actual time, disclose AI use, supervise the output, and don't share client confidences with a vendor that has no safeguards. Nobody has built the primitive that lets a lawyer prove they did all four when the bill is questioned a year later. This is that primitive.
For every billing window you point this at, the tool produces two artifacts:
draft.md— the markdown record of proposed time entries. Every row isaccept/edit/reject— the lawyer is the gate.draft.audit.html— a self-contained, print-ready audit packet with the matter and attorney identity stamped, the AI-disclosure language stamped, a SHA-256 chain of evidence for every source file and the artifact itself, and a hand-signature block at the end. Open in any browser, print to PDF, sign, attach to the bill.
Both artifacts are reproducible from the same inputs. Both carry the artifact's own SHA-256 so post-generation tampering is detectable.
- Never auto-bill. The output is a draft. The lawyer is the only thing that turns a draft into a billed entry. The web version's "Generate" button does not have a "Send to Clio" twin and won't.
- Never infer matter assignment from file contents. Only
matter.yml.routes[](cwd-prefix matching). The tool will not read a.docxand guess "this looks like an Acme matter." That's the malpractice surface this tool was designed to avoid. - Never rewrite narratives with an LLM. Verbs are deterministic and content-aware — derived from filenames, directory shape, and tool names. The artifact is reproducible byte-for-byte from the same inputs. Adding an LLM rewrite breaks the audit chain.
- Verbatim prompt text is OFF by default. Claude history is typically shared across matters and side projects. Use
--include-prompt-snippetonly on a single-matter machine where you have confirmed every session in the window belongs to the same matter. - A
verified: falsedisclosure pack cannot ship a--strictartifact. The pack is starter language; the lawyer's bar admission is what makes it canonical. Flipverified: true(with your bar ID inverified_by) only after reading the source opinion yourself.
node draft-entries.mjs \
--session ~/.claude/projects/<cwd-slug>/ \
--matter ./examples/matter.yml \
--since 2026-05-15 \
--until 2026-05-17 \
--out out/draft.mdRequired flags: --session, --matter. Run --help for the full list.
Two operating modes:
- Default (iteration) — generates with warnings. You read the draft, fix
matter.yml, re-run. --strict(audit-final) — refuses to generate if any audit invariant fails. Use this on the run you're about to sign.
--strict refuses on:
- Broad routes (
$HOME,/, or 1–2 path segments) - AI disclosure required but no usable
disclosure_text(matter override or pack canonical) disclosure_packreferenced is invaliddisclosure_packis the active source AND markedverified: falsematter.attorney.name/bar_id/bar_jurisdictionmissing
matter:
id: "2026-0427" # billing-system ID
client: "Acme Holdings Ltd"
caption: "Acme v. Smith"
jurisdiction: "FL"
practice_area: "litigation"
attorney: # required in --strict
name: "Jane Doe"
bar_id: "FL-1234567"
bar_jurisdiction: "FL"
billing:
rate_per_hour: 450
rounding: "nearest_tenth"
minimum_increment_hours: 0.1
ethics:
ai_disclosure_required: true
disclosure_pack: "fl-24-1" # loads disclosures/fl-24-1.yml
# disclosure_text: ~ # optional lawyer override
routes:
- "~/Documents/Matters/acme-v-smith"See examples/matter.yml and examples/test-matter-strict.yml.
disclosures/ ships starter language keyed to known bar opinions. Reference one from matter.yml:
ethics:
disclosure_pack: "fl-24-1" # or aba-512, ca-2023, ny-2024, dc-388Every pack entry ships verified: false. That is intentional. The maintainers of this repo are not your bar counsel. Read the source opinion, flip verified: true, sign your bar ID into verified_by. See disclosures/README.md for the contract.
--strict refuses to ship the artifact if the active disclosure is sourced from a verified: false pack.
Matter assignment is the actual hard problem. Claude session logs aren't tagged. v1 uses cwd-prefix matching only — no file-content heuristics, no PII risk, no inference.
- If
routes[]matches$HOME,/, or a 1–2 segment path, the artifact carries a non-removable warning banner.--strictrefuses. - Off-matter cwds appear in the Excluded section with a concrete fix: the exact
routes:line to add if that cwd belongs to this matter.
Every artifact embeds:
- Tool version + UTC generation timestamp
- SHA-256 of each source JSONL (path + bytes + hex digest)
- SHA-256 of
matter.ymlat generation - SHA-256 of the active disclosure pack (if used)
- Self-hash of the artifact itself — replace the embedded hash with the literal sentinel
PENDING_SELF_HASH_REPLACE_AT_RENDERand re-sha256the document to verify it has not been altered since generation - Inline
matter.ymlsnapshot (verbatim)
The audit packet HTML carries the same chain and a hand-signature block.
Self-contained browser port at web/index.html — single file, no build, no backend. Open directly or serve web/ from any static server. The JSONL never leaves the page.
A polished UX is being scaffolded on Lovable (https://lovable.dev/projects/732d1712-27ea-4db5-ab1e-9aa8030a7cce); paste-ready brief at web/LOVABLE_PROMPT.md. The bare web/index.html is the canonical fallback if Lovable drifts on the contract.
out/sample-draft.md— broad-route case (intentionally badtest-matter.yml). Shows the warning banner in context.out/sample-draft-strict.md— strict-clean case (narrow routes, attorney info, disclosure override). Shows a real chain of evidence.out/sample-draft-strict.audit.html— open in a browser to see the print-ready audit packet.
- Not a Clio API integration. Deliberately. Push-to-Clio is the malpractice-shaped feature most "AI billing" tools start with; this one ends there, after the lawyer has reviewed and signed.
- Not legal advice on any jurisdiction's rules. The pack is starter language; verification is the lawyer's job.
- Not an LLM-rewrite tool. Narratives are deterministic; the lawyer rewrites.
- Not a timer. This reconstructs time after the fact from existing session logs.
v0.2.0 — audit-defense rewrite. v1 spec in CONTINUE.md; current todo in tasks/todo.md.
AGPL-3.0. The workflow is the public methodology; closed vendors that bake it into a product must open-source the derivative.