Looom
Monitor your spec and code. If they drift, Looom will tell you.
Inspiration
Every project I've worked on eventually hits the same wall: the docs say one thing, the code does another, and nobody knows which one to trust. Specs rot instantly. We treat them as a one-time artifact - write it, ship it, forget it - while the code keeps moving. I wanted to change that: make the specification the living source of truth and let the code prove it still matches. That's where Looom came from - a tool that treats "the spec and the code disagree" as a bug you can actually see and fix.
What it does
Looom links your specification to your code and watches for drift between them.
You connect a GitHub repo, bring in your spec, and map spec segments to exact spans of code - either by hand or by AI. From then on, Looom keeps those mappings alive. When code changes on a new commit, or when you publish a new spec version, it re-anchors the mappings and runs a drift check automatically. If the two sides diverge, it shows a drift finding that points at exactly what changed and enable you to resolve it - update the spec, update the mapping, or accept a new baseline. No more guessing whether the doc still describes reality.
How we built it
The stack is a TypeScript monorepo:
- Frontend: React 19 + Vite, TanStack Router and Query for state, tRPC for a fully typed API boundary, CodeMirror for the mapping/annotation editor, and Shiki for syntax-highlighted code views.
- Backend: NestJS on Express with tRPC and Zod for end-to-end type safety, and jose for auth token handling. Auth0 handles identity.
- The spec itself: Looom is built on its own methodology. Requirements follow an SRS structure, decisions follow MADR 4.0 ADRs, and every requirement traces back to the decisions that shaped it. We mandates to keep the spec in sync with code: the product's spec repo is the source of truth for the product.
The hard part lives in the mapping engine - anchoring a spec segment to a code range that survives edits, re-anchoring when the code moves, and running drift checks on every commit and every spec save without duplicating findings.
Challenges we ran into
- Anchoring that survives change.: A mapping is only useful if it holds when the code around it shifts. Getting ranges to re-anchor and relocate across commits tooks most of our design & implemntation time.
- Drift without noise.: Re-running a check shouldn't spam you with the same finding. We had to give findings a real lifecycle so unchanged ones don't duplicate and resolved ones stay resolved.
- AI candidates you can trust.: We kept AI-suggested mappings browser-local until a human approves them, so nothing speculative ever pollutes the source of truth. Designing that atomic, all-or-nothing approval flow was fiddly.
- Keeping ourselves honest.: Because we specced Looom in Looom, every sloppy requirement bit us immediately. Slower up front, worth it.
Accomplishments that we're proud of
- End-to-end drift detection that actually triggers on its own: on push and on spec save, not just when you remember to click a button.
- Mappings that re-anchor and relocate as code moves, so traceability doesn't shatter on the first refactor.
- A clean, append-only decision history (ADRs) that made the project auditable from day one.
- A fully typed pipeline from database to UI, so a change in the contract shows up as a compile error, not a runtime surprise.
What we learned
Traceability is a data problem, not a documentation problem. The value isn't in writing the spec, it's in keeping the link between spec and code trustworthy over time. We also learned that spec-driven development only works if the spec is genuinely easier to edit than the code; the moment it's a chore, people route around it. A lot of our design energy went into making the spec the path of least resistance.
What's next for Looom
- Deeper AI triage that not only spots drift but proposes the exact spec or code edit to close it.
- Developer extension, for developer, by developer. I originally plan it, but the drift mechanism takes too long.
- MCP Server and AI skill. The evaluation can be offload to an AI agent. I think we can be free from the paperwork, and just fixing when needed.
- Support for more spec formats and languages, and richer code-mapping beyond line ranges.
- Team workflows — review, approvals, and notifications when drift opens on shared projects.
- CI integration, so a pull request that drifts from the spec fails the check before it merges.
Built With
- auth0
- codemirror
- github
- jose
- nestjs
- node.js
- playwright
- react
- react-markdown
- shiki
- tanstack-query
- tanstack-router
- trpc
- typescript
- vite
- vitest
- vscode
- zod
Log in or sign up for Devpost to join the conversation.