Larkspur MSA
Read Larkspur_MSA_v4.pdf 42 pages · 18 clauses
Checked against SaaS vendor v3 15 ok · 3 off
§ 9.2 Liability cap vs market
1 dot = 2 SaaS MSAs
- Their draft 3 mo · p4
- Redline 12 mo · p49
- Below playbook
Drafting § 12.4 Indemnity 2 of 3
Choose your reading theme.
An AI contract review card: steps tick off, a market swarm places their draft and the redline, and the next redline drafts below.
redline-review/redline-review.tsxRead Larkspur_MSA_v4.pdf 42 pages · 18 clauses
Checked against SaaS vendor v3 15 ok · 3 off
1 dot = 2 SaaS MSAs
Drafting § 12.4 Indemnity 2 of 3
The live component, numbered part by part. Every measurement is read from it as it is drawn. Point at a row to outline its part, or at a part to find its row.
When to use
When not to use
You can add this component with the shadcn CLI or by hand:
Into components/redline-review of any React project, with no setup:
npx shadcn@latest add https://brunodelorence.com/r/redline-review.jsonCopy these files into one folder of your project, keeping their relative imports together, or download them as a ZIP:
As shown under Usage, below.
Either way it needs React 19 and a bundler that supports CSS Modules, such as Next.js or Vite. It has a dark colour scheme: it follows your page’s color-scheme, light unless the page sets one, or its colorScheme prop, with nothing to configure. Browsers without light-dark() show it light.
import { RedlineReview } from './redline-review';export function ContractReview() { return ( <RedlineReview title="Larkspur MSA" draftMonths={3} redlineMonths={12} onDecision={(decision) => console.log(decision)} onSend={(prompt, mode) => console.log(mode, prompt)} /> );}Each state below is a live instance, locked so you can study it.
The pieces it is built from, each with its measurements read live.
An agent reads a contract, checks it against a playbook and finds three clauses off. The liability cap shows where it stands in the market: a swarm of past contracts, their draft far down the left, the playbook minimum as a dashed line and the redline lit on it, with percentiles counted from the data. Accept or reject it, watch the next redline draft, and give the drafter your own instruction.
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | 'Larkspur MSA' | The contract’s name, over its version, length and playbook. |
file | string | 'Larkspur_MSA_v4.pdf' | The file the agent read, in the first step. |
playbook | string | 'SaaS vendor v3' | The playbook the clauses were checked against. |
draftMonths | number | 3 | Their draft’s liability cap in months (0 to 25): where the red ring sits. |
redlineMonths | number | 12 | The redline’s cap in months: where the lit dot sits, and where the arc ends. |
playbookMonths | number | 12 | The playbook minimum in months: the dashed line, with grey contracts below it. |
defaultPrompt | string | — | What the composer holds at first. |
onDecision | (decision: 'open' | 'accepted' | 'rejected') => void | — | Called when the redline is accepted, rejected or opened again with Undo. |
onSend | (prompt: string, mode: 'redline' | 'compare') => void | — | Called with the composer’s text and mode when it is sent (the button or Enter). |
autoplay | boolean | true | While on screen and untouched, a demo plays the review from the start, over and over. Any real input hands control to the reader for six seconds. |
defaultState | { steps?: 1 | 2 | 3; tab?: 'review' | 'redlines'; decision?: 'open' | 'accepted' | 'rejected'; mode?: 'redline' | 'compare'; drafting?: 'running' | 'stopped' | 'done'; hoverMonths?: number } | — | Opens in this state, with the demo off: the steps still reading (1) or checking (2), a tab, a settled decision, the composer’s mode, the drafting line stopped or done, or the chart’s tooltip on the column nearest hoverMonths. |
colorScheme | 'light' | 'dark' | 'system' | — | Light or dark colours, or the reader’s; without it, the page’s color-scheme. |
className | string | — | Added to the stage. |
The complete source behind this demo. Open source under the MIT license, © 2026 Bruno Delorence: copy it, change it, ship it.
// Copyright (c) 2026 Bruno Delorence. MIT License.'use client';import { memo, useEffect, useEffectEvent, useId, useRef, useState, type CSSProperties, type FormEvent, type KeyboardEvent as ReactKeyboardEvent, type PointerEvent as ReactPointerEvent,} from 'react';import { AXIS_Y, COLUMNS, DOT_R, DOTS, PER_DOT, PITCH, PX_PER_MONTH,// Copyright (c) 2026 Bruno Delorence. MIT License./* * The market the liability cap is weighed against: 1,458 invented SaaS master agreements, one dot * for every two, stacked in columns along a 0 to 26 month axis. Each column stands for a sliver of * months (the dots' pitch over the axis' scale) and stacks above and below the axis line. * * Everything here is in the chart's own units: the drawing is VIEW_W × VIEW_H and the SVG scales * it to the card's width. *//** The drawing's size, and where its axis runs. */export const VIEW_W = 527;export const VIEW_H = 118;export const AXIS_Y = 61.75;/** Px per month along the axis (0 months sits at x = 0), and the distance between dots. */export const PX_PER_MONTH = 20.333;export const PITCH = 4.6;export const DOT_R = 1.8;/** Contracts per dot. */export const PER_DOT = 2;/** * The columns, from 0.92 to 25.56 months, each a [dots above, dots below] pair besides the one on// Copyright (c) 2026 Bruno Delorence. MIT License.'use client';import { useCallback, useEffect, useRef, useState } from 'react';/* * When a demo may play on its own: while part of it is on screen and the tab is visible, never * under reduced motion, and not while the reader is using it. `take()` hands it to the reader; it * takes back over `idle` ms after their last input. `live` is the same without the reader: what * moves by itself (a progress bar) may move then. */export function useAutoplay<T extends HTMLElement>(idle = 6000) { const ref = useRef<T>(null); const [visible, setVisible] = useState(false); const [reduced, setReduced] = useState(true); const [taken, setTaken] = useState(false); const timer = useRef(0); useEffect(() => { const element = ref.current; if (!element) return; let onScreen = false; const update = () => setVisible(onScreen && !document.hidden);/* Redline review (redline-review.tsx): a graphite stage with the card in its middle, 582 px at most, near-black at night and white by day; inside it a darker well for the chart and a grey tray for the drafting line and the composer. Colours are the tokens below, light-dark(light, dark): the component takes the color-scheme it inherits from the page (light unless the page says otherwise), or the one its colorScheme prop sets (data-color-scheme). Motion is transforms and opacity: the dots fall by a translate, the arc draws through a mask's dash offset, the markers pop by a scale and the progress line stretches by scaleX. */.root { /* The stage, the card, the chart's well, the drafting tray and the composer. */ --stage: #ececec; --card: #fff; --card-ring: rgb(0 0 0 / 0.07); --well: #fafafa; --well-line: #ececec; --tray: #f4f4f4; --tray-line: #e6e6e6; --composer-top: #fff; --composer-bottom: #f7f7f7; --composer-line: #e4e4e4; --composer-edge: #d9d9d9;