Archibald312 wires in an audit trail the app can't rewrite

A new activity log records who did what, and the database itself refuses to let anyone quietly edit or delete the history.

compliancesecurity

Every action in this fork - each tool the system runs, each AI call it makes - now lands as a row in a permanent log: who acted, when, how long it took, and whether the step succeeded, failed, or was blocked. The protection sits in the database, not the software, so even a hijacked app login can only add records, never alter or erase them.

Two caveats worth flagging. The log keeps the actor's email even after that user's account is deleted - a deliberate forensic call, but one to weigh against data-minimisation rules before adopting. And the table has no built-in cleanup, so it grows forever unless an operator adds their own archiving. There's also no admin view yet; for now each person sees only their own activity.

So what Anyone in a regulated practice who needs to prove what their AI did, and when, should look hard at how this fork handles the record.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

1 commit from Archibald312/GordonOSS, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
d523a644 Phase 6: audit logging for LLM + tool invocations (#6) Archibald312 2026-05-15 ↗ GitHub
commit body
- New audit_log table with immutability triggers (UPDATE/DELETE blocked
  at the DB layer); migration in backend/migrations/audit_log.sql and
  appended to backend/schema.sql.
- backend/src/lib/audit.ts: AuditEntry shape, recordAudit() fire-and-forget
  insert, hashContent() SHA-256 helper, AUDIT_LOG_ENABLED feature flag.
- Tool dispatcher (lib/tools/registry.ts) records a tool_call row per
  invocation with duration, input/output hashes, and resolved document
  IDs from args + side effects; errors are recorded then re-thrown.
- streamChatWithTools wraps the per-provider stream and records an
  llm_call row on success or error. Audit context flows through
  runLLMStream and the tabular generate path.
- GET /audit-log returns the caller's own entries with filters
  (project_id, event_type, from, to, limit, offset).
- Unit tests cover hashContent determinism, recordAudit insert shape,
  feature-flag no-op, and error swallowing.

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-425.md from inside the repo you want the changes in.

⬇ Download capture-thread-425.md