Archibald312 clears the runway for audit logging

A sprawling, single-file pile of AI tools gets broken into tidy pieces - and the real prize is what that makes possible next.

infrastructurecompliance

Every action the AI can take - reading a document, making an edit - used to live in one enormous file that was painful to change. Archibald312 split it apart so each capability sits on its own, with a central switchboard that every request now flows through.

That switchboard is the point. Because every AI action passes through one place, the fork can now record what the assistant did, when, and on which document - without rewiring each individual feature. It's the plumbing a real audit trail needs, laid before the audit trail itself. The cleanup also flagged two pre-existing test problems (a logout redirect and a missing user-profile setup) that predate this work, so nobody mistakes them for new breakage.

So what If you care whether your legal AI can prove what it touched, this is the unglamorous groundwork that makes that possible.

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
eb461a39 refactor(backend): split chatTools.ts into per-tool registry (#2) Archibald312 2026-05-14 ↗ GitHub
commit body
Move every tool the LLM can call into its own file under
backend/src/lib/tools/, dispatched through a typed registry. chatTools.ts
shrinks from 3,284 to 976 lines and contains only orchestration
(SYSTEM_PROMPT, runLLMStream, citation parsing, message-building, doc
context, workflow store).

Why: a single 3K-line monolith made every tool change risky, every new
tool an exercise in pattern-matching against existing branches, and the
schema/dispatch split (TOOLS/PROJECT_EXTRA_TOOLS/TABULAR_TOOLS/WORKFLOW_TOOLS
arrays composed by callers, mirrored by a giant if/else in runToolCalls)
left two places that had to stay in sync. Adding a tool now requires
one new file plus one line in the registry - no edits to the monolith.

Structure:
  tools/types.ts          ToolDefinition / ToolContext / ToolExecutionResult,
                          plus the tool-result types (EditAnnotation,
                          DocCreatedResult, DocReplicatedResult,
                          DocEditedResult, TurnEditState)
  tools/registry.ts       TOOL_REGISTRY (as const, typed-literal names),
                          buildAvailableToolSchemas, runToolCalls dispatcher
  tools/<toolName>.ts     One ToolDefinition per file (10 tools)
  tools/shared/           Helpers used by multiple tools
                          (documentReading, generateDocx, runEditDocument)

Per-tool availability is declared via `availableWhen(ctx)` predicates,
replacing the previous route-shaped tool composition. The registry
filters schemas per turn, so the model never sees tools that can't run.

The legacy arrays TOOLS, PROJECT_EXTRA_TOOLS, TABULAR_TOOLS,
WORKFLOW_TOOLS are deleted (callers in routes/tabular.ts and
routes/projectChat.ts lose the `extraTools:` pass-through accordingly).

Verified: tsc --noEmit clean, 57/57 unit tests pass. Behavior-preserving:
schemas reproduced verbatim, side-effect aggregation shape unchanged,
SSE events emitted identically.

TECHDEBT.md picks up two e2e findings surfaced (not caused) by this
work: the log-out test now times out, and the test Supabase project is
missing the user_profiles migration.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

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-419.md from inside the repo you want the changes in.

⬇ Download capture-thread-419.md