
Vision & what the app does
If you build with Kiro's spec workflow you end up with a lot of markdown. Every feature leaves behind a `requirements.md`, a `design.md`, and a `tasks.md` sitting in `.kiro/specs/`. Six months and four repos later you've written a small book about your own system and you can't see any of it. The files just sit in folders nobody opens twice.
Spec Library is a librarian for that pile. It scans local and remote Git repos for `.kiro/specs/` directories, pulls the artifacts into a catalog, and then draws the collection so you can look at it.
There are two views:
- The **Relationship Observatory** is a dark graph canvas. Every spec is a node, dropped into one of five lifecycle columns (new, scoped, refined, in-flight, done) and sorted into theme lanes. Solid edges are relationships you've confirmed: depends on, blocks, supersedes, duplicates, related. Dashed ones are suggestions the app came up with on its own, sitting there until you accept or reject them. Watching a few months of work resolve into lanes and dependency chains turned out to be the most useful picture I've ever had of my own project, which I honestly didn't expect going in.

- The **Archive Ledger** is the other half. It's a light chronological table of finished specs grouped by month, each one an immutable SHA-256 snapshot. The graph shows what's alive, the ledger shows what's done.

I gave the thing a mascot too, since a library ought to have a librarian. The Spectral Librarian is a ghost in reading glasses. It's also the name of the agent that ships with the app, trained for reading and analyzing spec plan documents.
How I built it
Spec-first, which felt like the only honest way to build an app about specs. I wrote requirements, design, and tasks documents for the app itself before writing any code, then had Kiro build from them. By Sunday it was indexing its own specs. If you clone the repo you'll find
.kiro/specs/spec-library-crew-app/ in there, plus a later bugfix spec for a SQL injection problem I turned up in an IN clause.That loop closing on itself was cute, but the actually useful part was what it did to code review. When an agent implements from a written design, the review that matters happens on the design. Vague sentences turn into wrong code fast, so you learn pretty quickly to stop writing vague sentences. Fifty commits over two days, about 12,000 lines of TypeScript across four Bun workspaces, and I spent more time editing prose than editing code.
I skipped the LLM for relationship suggestions. The obvious move is to ask a model which specs are related. I used in-process TF-IDF with cosine similarity instead [ADR-003 ], scoring across five reasons: content similarity, shared tags, shared theme, markdown links between documents, and repository proximity. Same input has to give the same output every time. If the graph quietly rearranges itself between sessions you stop trusting it, and then the whole app is pointless. Suggestions have to clear a 0.3 confidence threshold, cap out at five per spec, and remember what you've rejected.
Property tests earned their keep. I wrote 18 correctness properties and ran them under
fast-check at 100+ iterations each. One asserted that cosine similarity always lands between 0 and 1. It failed. Floating point rounding in the dot product let identical vectors score a hair above 1.0. No hand-written test case I'd have thought to write would have hit that, and it would have shown up eventually as a "102% similar" in the UI. Took seconds to find with generated inputs. I'll be reaching for this on any scoring code from now on.The agent came last and it's on a short leash. The Spectral Librarian can propose things but it can't write. Its four MCP tools are
list_sources, search_specs, get_spec_context, and submit_metadata_proposal, and that last one drops into a pending queue where a human approves it. The MCP server wants a token and caps responses at 64 KB. Letting it read the whole catalog is handy. Letting it quietly rewrite things seemed like a problem I'd rather not have.Last thing: it's built with Kiro Crew, for Kiro Crew, and it still runs on its own. The Crew manifest registers the UI, backend, MCP server, and agent as one installable app, but
npx kiro-spec-library serves the same backend and UI on a single port against the same SQLite directory, no Crew needed. Supporting both was mostly a routing headache, which I solved with a small gateway adapter that builds proxy paths under Crew and falls back to direct paths in dev [ADR-008 ].AWS services used / architecture overview
Amazon Bedrock, by way of Kiro.
Spec Library has no AWS SDK in its dependencies and makes no direct AWS API calls. The data plane is all local. The AWS dependency runs through Kiro, and Kiro's docs put it plainly: "Kiro is powered by Amazon Bedrock, which uses cross-region inference to distribute requests across the Regions within a geography."
That shows up in two places:
- While building. Every spec session that produced this codebase (the requirements and design docs, the implementation passes, the ADRs) ran against a Bedrock-hosted model through Kiro.
- While running. The
spectral-librarianagent that ships with the app declares"model": "auto", which is Kiro's Bedrock-backed routing picking a model per task. Ask the Librarian to find your under-documented specs and that reasoning happens on Bedrock. The app's MCP server is just the set of tools it calls.
The rest is local on purpose. Bun and Elysia with TypeBox validation,
bun:sqlite in WAL mode over 12 tables and 10 migrations, contentless FTS5 indexes with BM25 ranking for search, 27 route handlers across nine modules, React 19 with @xyflow/react driving the canvas. No cloud data plane, no telemetry, no account. For a tool that indexes your team's internal engineering specs, I'd rather they never left the machine.What I learned
The main thing is to write the spec until there's no ambiguity left in it, then get out of the way. Agents don't really fail by writing bad code. They write sensible code for the underspecified thing you described, which is harder to spot. All my rework this weekend traced back to a sentence in
design.md that could be read two ways.On anything numeric I'll use generated tests now. The cosine similarity bug made that case better than I could.
I'd also underrated MCP as a way of deciding what an agent can't reach. Ruling out writes to accepted state shaped the design more than any tool I added.
And the picture mattered more than the database. Cataloguing was the easy part. The graph is what finally got me to look at my own specs.
Link
Repo: https://github.com/stevenjmiklovic/kiro-spec-library , Apache-2.0,
v0.2.0, tagged and public.Install it into Kiro Crew from the manifest, or just run:
npx kiro-spec-libraryPoint it at any repo with a
.kiro/specs/ directory and it'll index itself in about a second.Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article