SLW / devportal Production apps Signing in…
The kit

What we have already built.

The reusable half of the fleet β€” how we pull structure out of a document, and how we show it. Every kit rides into every repo, so Claude reaches for it the moment someone starts the work. Nobody has to know it exists.

This page is generated from the kits themselves β€” the same files Claude reads in a Codespace. There is no second copy to drift, because a confident wrong answer costs more than no answer.

document-extraction

Claude reaches for this when someone says: extract, parse, ingest, upload, PDF, PPTX, deck, filing, 10-K, S-1, prospectus, OCR, "break down this document".

Do not build a parser. We already have a working one. This describes the shape it has and where the reference implementation lives, so a new document type is a few hundred lines on top, not a rebuild.

Reference implementation: Ford (rivent-dev/slw-idea-atlas) β†’ lib/pipeline/ (ingest.ts Β· readers/ Β· ocr.ts Β· filer.ts Β· analyze.ts Β· delta.ts Β· commit.ts). Read those before you design anything. If your version ends up better, say so β€” the pointer moves to yours (see Evolving the kit).

The pipeline, in order

  1. Archive the original, untouched. Before anything reads it. Every fact we later show has to be checkable against the file as it arrived.
  2. Hash for duplicates. Content hash, checked before review β€” not after someone has spent ten minutes approving rows we already have.
  3. Read by extension, via a registry. One file per format (readers/pptx.ts, docx.ts, xlsx.ts, PDF inline). Adding a format means adding a file; nothing downstream changes. Legacy binaries (.ppt, .doc, .xls) are recognised and rejected honestly, not silently mangled.
  4. Split into segments, one per page or slide β€” index, kind, heading, text, ocr flag. Segments are the unit everything downstream cites.
  5. OCR fallback when the text layer is a lie. Under ~20 characters per page on average, or zero pages back from a real PDF, means a scan wearing a PDF suit. Mark it for OCR rather than failing β€” filings and bank PDFs hit this constantly.
  6. File it with AI, and keep per-field confidence. Title, type, tier, publisher, date, company, sector β€” each with a 0–1 score. Anything under 0.70 gets flagged in the UI, not hidden.
  7. Analyse into the house format (see below).
  8. Delta the proposed facts against what we already know β€” never a silent overwrite.
  9. Commit as a batch, undoable as a unit, with follow-up jobs queued (page images, analysis, version detection).

The analysis contract

A document decomposes into 3–5 angles, most important first. Each angle:

  • Takeaway β€” the net conclusion, ≀25 words.
  • 3–6 finding bullets, one declarative sentence each, figure first when there is one, every bullet carrying the page numbers it came from.
  • Exactly one Counterpoint when the document holds challenging evidence β€” the strongest honest case against. Not a hedge, and not optional when the evidence exists.
  • Implication β€” what it means for the firm, ≀25 words.
  • 4–10 verbatim quotes behind the angle, each with page and a stance of supports / challenges / context.

Quotes are verified by code, not trusted from the model. A quote the page text actually contains is direct; anything else is kept but marked inferred. This is the single most important line in the kit β€” it is what makes the output citable rather than plausible.

Non-negotiables

  • Every fact keeps a page-level provenance link. No orphan numbers. A datapoint that can't be traced to a page is a rumour with good styling.
  • Never throw per file. Record the outcome on that item and move to the next; one bad PDF in a batch of eighty cannot take the batch down.
  • Nothing goes live until a human commits it. Staged β†’ extracted β†’ reviewed β†’ committed, undoable as a unit.
  • Failure is visible. If the text layer couldn't be read, the page says so and offers the original. A silent blank is the worst outcome β€” it reads as "nothing in this document", which is a lie.

The delta pass

Every proposed fact lands as new Β· confirms Β· updates Β· conflicts:

  • updates marks the old row superseded but keeps it.
  • conflicts keeps both sides visible for a human to settle.
  • Nothing is silently overwritten, ever.

Attribute and value comparison is canonicalised (case, punctuation, ~/β‰ˆ, thousands separators, trailing .0), and recency is scored from loose as-of strings β€” "Jun 2026", "2026-06-30" and "Q2 26" all resolve.

Adding a new document type (10-K, S-1, credit agreement…)

You are almost certainly not adding a parser. Work down this list and stop at the first that fits:

  1. Format already read? (PDF/PPTX/DOCX/XLSX β€” yes for every SEC filing.) Then no reader work at all.
  2. New analysis profile. A 10-K and an S-1 want different angles than a bank sector report β€” segment economics, risk-factor movement, MD&A claims vs. the numbers. That's a prompt/profile, not a pipeline.
  3. New attributes on the sector schema for the figures you want comparable across companies.
  4. Only then, if the format genuinely isn't readable, add a reader file.

Filings are one job, not several. A 10-K, an S-1, a 20-F and a 10-Q are the same shape: audited financial statements, segment tables, risk factors, MD&A. Build the filing profile once and pick the document type up as a variant. If someone else on the team is already working a filing type, join that work rather than starting a second one β€” check the catalog at https://rivent.dev/kit first.

Where the prompt lives β€” not in the code

An extraction profile is tuned, not written once. Getting a filing profile right takes twenty passes over a real document, and if the prompt is a string constant, each of those passes is a commit, a review and a deploy. That kills the iteration before the profile is any good.

Put the prompt and its rules in a config store the app can edit at runtime:

  • In-code defaults ship with the app, so a fresh install works and the intended behaviour is reviewable in the repo.
  • The live config overrides them, persisted in one row/key, loaded into an in-memory store at startup, and editable from an admin screen. Edits apply without a redeploy and survive restarts.
  • Keep a version and a reset, so a bad edit is one click back and you can tell which profile produced an existing result.
  • Fold the winner back into the code defaults once it settles. The live store is for iterating, not a permanent shadow copy of your logic.

Reference implementation: rivent-dev/Terminal β†’ artifacts/api-server/ (src/routes/prompts.ts, src/routes/system-rules.ts, src/lib/systemRules.ts). Terminal splits it usefully in two, and a document profile usually wants both:

  • Prompts β€” the AI half: what to look for, how to phrase the analysis.
  • System rules β€” the deterministic half applied after extraction: routing, classification, tagging. Cheaper, faster and more predictable than asking a model to be consistent about something a rule can decide outright.

Ford's analysis prompt is currently a constant in lib/pipeline/analyze.ts β€” fine while there was one profile, the wrong shape the moment there are several. Adding a second document type is the point to port this pattern over.

Evolving the kit

This kit is a pattern plus a pointer to the best working implementation. It is deliberately not a shared library:

  • Copy the pattern into your app and adapt it locally.
  • When your version is genuinely better, update the pointer in this file to yours in the same PR β€” with one line on what changed and why.
  • Never fork the code into this kit. A third copy nobody maintains is worse than no kit at all.

See also: visual-breakdown β€” how the extracted result is displayed.

visual-breakdown

Claude reaches for this when someone says: display, render, show, visualize, breakdown, dashboard, artifact page, exhibits, key slides, citations, charts for extracted data.

We already render broken-down documents in production. Match this grammar before inventing a layout; the parts below exist because each one was needed.

Reference implementations:

  • Ford (rivent-dev/slw-idea-atlas) β†’ app/artifacts/[id]/page.tsx β€” the canonical document breakdown, top to bottom. Start here.
  • Quill (rivent-dev/slw-workspace-hub) β†’ components/ThemeExhibits.tsx, MagellanShelf.tsx (the filename still carries the old name) β€” how a second app consumes and re-displays another's breakdown.

The page, in order

  1. Header card β€” format badge Β· title Β· credibility tier Β· byline Β· page/slide count Β· sector and topic chips Β· links to both the source and the archived original Β· other versions of the same document.
  2. AI summary, visually marked as AI (see house rule below).
  3. Pipeline status band β€” "Processing β€” OCR still running", or an "Extraction incomplete" band naming what failed and offering the original. Scanned-document waits get an honest estimate ("a few minutes, up to an hour at worst"). Never a silent blank.
  4. "What the document says" β€” overview paragraph, then each angle as a collapsible block: Takeaway β†’ finding bullets, each with clickable p.12 citations β†’ Counterpoint in-line where one exists β†’ Implication β†’ a collapsed "the N quotes behind this" drawer.
  5. Key slides β€” starred exhibits in a thumbnail grid, each with a label and a one-line why, badged AI pick or You. Anyone can star or unstar a page.
  6. Pages / slides grid β€” every page as a thumbnail with its index and heading, an OCR badge where OCR was used, and a star on hover.
  7. Datapoints table β€” company Β· attribute Β· value Β· as-of, sub-headed with "every one keeps its provenance link here", plus an inline add form.
  8. Filed as β€” the AI's filing decisions with confidence per field; anything under 0.70 shown in warning colour with a ⚠, never hidden.
  9. Companies mentioned β€” with the page range each was found on and a quoted line of how the document characterises them.

Rules that make it trustworthy

  • Every claim is clickable back to its page. p.7 opens the page viewer on page 7; the URL carries ?p=7 so a citation can be linked from anywhere, including another app.
  • Mark what the AI did. AI-generated blocks carry the violet AI accent and a ✦ label. A reader must never have to guess whether a sentence came from the document or from a model.
  • Show confidence, don't launder it. Low-confidence fields are flagged in place. A quote we couldn't find verbatim in the page text is still shown β€” marked inferred, with a tooltip saying it's the model's reading.
  • Empty and failure states are written, not blank. Each panel has real copy for "nothing yet", "still running", and "couldn't be read", and the copy says what to do next.
  • Consumers cite, they don't copy. When another app displays these exhibits it stores the citation (artifact + page), never the image β€” image URLs are signed for an hour and re-requested on each render, so a card whose picture has expired still cites correctly.
  • Counts everywhere. "12 extracted Β· 3 via OCR", "5 tagged Β· 2 AI picks". Density beats decoration; the reader should be able to audit at a glance.

Charts β€” the honest gap

The grammar above covers evidence display: pages, quotes, citations, datapoints. It does not yet cover charts β€” there is no house standard for a revenue bridge, a segment breakdown, a cash-flow waterfall or a YoY comparison, because nothing has needed one yet.

If you are the first to need charts (a 10-K or S-1 breakdown will be):

  • Use the dataviz skill for the chart mechanics β€” palette, form, axes, legends, accessible light/dark.
  • Inherit this file's rules regardless: every plotted figure stays clickable back to the page it was extracted from, AI-derived series stay marked, and a missing figure shows as a gap rather than a zero.
  • Then write what you chose back into this file in the same PR. You are setting the standard, so leave it stated rather than buried in one app.

Filings get a tear sheet, not an artifact page

Locked with Shawn, 2026-08-04 β€” and shipped. Ford generates this for any filing; it is not a design to re-litigate. Renderer: rivent-dev/slw-idea-atlas β†’ app/artifacts/[id]/tear-sheet.tsx. Builder: lib/pipeline/filing-sheet.ts. Reference rendering: mockups/filing-breakdown.html. Guarded by lib/pipeline/filing-format.test.ts.

A filing β€” S-1, 424B4, 10-K, prospectus β€” does not get the page-and-quote grammar above. It gets an analyst tear sheet: a written argument with the evidence attached, in the shape a research note takes.

  1. One-row nav. A Guide pill on the left, the numbered sections beside it on the same line, document identity (400pp Β· read in full) pinned right. The whole nav is the height of the pill; with more sections than fit, the strip scrolls sideways rather than wrapping to a second line β€” a nav that grows a row pushes the sheet down the page. No left rail and no document guide: both were built and cut. The per-finding page citations are the route into the document; a table of contents on top of them is noise.
  2. Header carries a thesis, not a summary. An eyebrow, form badges, one headline sentence that states the argument ("Starlink pays for everything. The IPO pays for the AI."), then a paragraph of the case with the load- bearing figures bolded.
  3. Terms as a stat row β€” price, shares, proceeds, implied value, float, founder vote. Six cells, value large, qualifier small underneath.
  4. A three-column verdict: genuinely working / should worry a buyer / unresolved at filing. This is the part a reader takes away, so it sits above everything else.
  5. Numbered sections of finding cards, charts, and pro/con grids.
  6. Nugget callouts for buried admissions β€” the clause in a risk factor that gives away a fact the marketing sections avoid. A filing's real disclosure lives in these, and they need their own visual treatment or they read as body text.
  7. What I'd push on β€” open questions as a table, each with where to look.
  8. A sourcing footer that separates disclosed from derived. Every computed figure is marked. This is what makes the sheet quotable.

Charts earn their place by shape

| Form | Use for | Why | |---|---|---| | Diverging bars around a zero line | Segment operating income | The series crosses zero; profit vs loss must read as direction, not colour alone | | Stacked bars, one per period | Revenue mix over time | The mix change is the story; totals are secondary | | Column comparison against a baseline | Dilution arithmetic | Several related per-share figures read against one reference | | Ranked bars | Risk-factor count by group | The ordering is the finding |

Colour is semantic and fixed: one hue per segment, held across every chart; loss and profit are separate hues used nowhere else. Numbers are tabular figures throughout.

What the pipeline must extract to fill it

The sheet is the specification. Producing it needs more than prose findings:

  • Segment financials as structured series β€” revenue and operating income per segment per period, reconciled to consolidated totals.
  • Offer terms β€” price, share counts by class, proceeds, greenshoe, voting power.
  • Derived metrics β€” implied value, multiples, free cash flow, dilution. These are arithmetic between disclosed numbers that can sit a hundred pages apart, and no reader should have to do it.

Both passes are built. Sections are read in parallel on page boundaries, each returning findings, figures as numbers, offering terms and buried admissions; one merge pass then holds every figure at once, writes the sheet, and computes the derived metrics. A section that fails is retried once and counted, and the build aborts if more than a third fail β€” a tear sheet on a partial read is the failure this exists to end.

Measured on a real 400-page prospectus: 23 sections, 400 of 400 pages, about four minutes, roughly $3.

Before you design

Build the mockup first and publish it β€” the reviewer reads in a browser, not in a repo. Match the existing app's palette and tokens; the grammar is shared, the skin is not.

Mockups are light theme only β€” no dark variants. One theme to review keeps the feedback about the layout. Dark mode belongs in the production build, not in the thing being approved.

No fixed-width type. Every Rivent surface is sans-serif, including code-ish labels, filenames and page numbers. --mono is aliased to --sans on purpose in the portal β€” do not "fix" it. The full rule is in the portal's AGENTS.md.

See also: document-extraction β€” how the material on this page is produced.

Edit a kit at dev-portal/standards/kit/, run python3 standards/build-kit-page.py, then ./sync-team-rules.sh to open a PR into every repo. A kit is a pattern plus a pointer to the best working implementation β€” never a forked copy of the code.