[Source-available · Built on Shape Up]

The hard part of building software moved from how to what.

AI made shipping cheap. The scarce skill now is deciding what to build, and in what order, in a backlog that fills faster than anyone can read it. Cairn is the PM agent that does the sorting — read, deduplicate, shape, route — so your judgment goes to the decision, not the pile.

[One Node process · One SQLite file · Zero telemetry]
cairn — backlog
FeatureStatusAppetiteShapers
Merge duplicate signals at capture
Building
6 weeks
NT
Grep the repo before shaping
Bet
6 weeks
L
Quorum before a table is validated
Shaped
2 weeks
M
Discard noise without deleting it
Shaped
1 week
MT
Activity log in your language
Done
2 weeks
N
[The loop]

You don’t fill a backlog. Signals bubble up.

01
Raw signal

A Slack thread, a bug report, a whole transcript. Stored verbatim, hashed and embedded — even the noise, which is archived rather than destroyed.

02
Shaped
Shaped

The agent turns it into a pitch: a real problem, a fixed appetite, rabbit holes, no-gos. Not a reworded request.

03
Betting table

A scored menu of what is worth doing. Members vote, the owner validates. Nothing is ever bet automatically.

04
Bet
Hill

The bet opens a cycle and scope freezes: from here, no signal can attach itself to work already in flight.

05
Done
Done

No reopening. A new need shapes a fresh iteration that supersedes the old one, and says so.

[Intake]

An agent, not a form.

Paste a Slack thread, a bug report, a whole meeting transcript. The agent splits it into the distinct signals it actually contains, dedupes each one against the backlog, and argues for where it belongs. Nothing is written until you confirm.
cairn — intake
[Pasted · #product-feedback · 41 messages]

“…honestly the backlog is unusable, half of it is the same request three times. Also we keep re-filing the dedupe thing. And Ops asked again for a CSV export before Friday…”

3 distinct signals extracted · 1 duplicate merged
Bulk-archive stale signals
New — no match in the backlog.
Shaped
Merge duplicate signals at capture
Duplicate of #24 — routed there, not created.
Building
Export the roadmap as CSV
New — split out of the same thread.
Shaped
[Routing]

Every signal ends in one of four decisions.

create_feature
No candidate is the same feature.

Inserts a shaped feature. Creating is a deliberate act — the agent has to justify a new one, because duplicates are what kill a backlog.

append
A shaped candidate addresses the same problem.

Refines the existing pitch instead of forking it, attaches the signal to it, and resets the staleness clock.

merge
“X is a duplicate of Y.”

Feedback, decisions, PR links and history all repatriate onto the survivor. The absorbed feature is archived, never destroyed.

discard
True noise, or a duplicate that adds nothing.

The raw signal is still stored and archived — nothing is lost. A bug report is never discarded, whatever it looks like.

[Code-aware]

Grounded in the code you already shipped.

Link your product repo — read-only GitHub App or a local path — and the agent checks what is actually built before it shapes. It dedupes against reality, citing file:line rather than a stale ticket. The repo is grepped locally and never leaves your box.
cairn — product context
grep -r "dedupe" acme/product
server/gateway/intake.ts:142
export async function dedupeAgainstBacklog(
server/db/softDelete.ts:31
export function discardSignal(id: string) {

Already shipped. Dedupe-on-capture exists at server/gateway/intake.ts:142. Routed the signal onto feature #24 instead of opening a duplicate.

[Dedup]

Deduplication isn’t a feature. It’s the floor.

topCandidates()
Semantic — on every turn

Cosine similarity against shaped features only. The score is a hint, not a rule: the agent is the judge, and it appends when a candidate addresses the same underlying problem — even when the two share not one word.

content_hash
Exact — at commit

sha256 of the normalised signal. If it has already been routed, the commit is an idempotent no-op. Paste the same thread twice and nothing is written twice.

anti-echo guard
On every append

A pitch field is never overwritten by the raw instruction that triggered it. A shaped pitch cannot be degraded back into a reworded request.

[Shape Up]

The method is the product.

Pitches with a real problem and a fixed appetite. A betting table where members vote and the owner validates. Hills that track in-flight work, with scope frozen once the bet is placed. No artificial caps, no vanity metrics — the backlog is meant to stay small.
cairn — pitch

Merge duplicate signals at capture

Bet
Appetite
6 weeks
Hill
Cycle 12
Builders
NT
Problem

The same request lands three times from three channels. Whoever triages last has no way to know it is already in the backlog.

No-gos

No silent auto-merge. The agent proposes, a human confirms — writing only ever happens on confirmation.

Whatever isn’t bet on goes stale — and has to be re-defended.

There is no infinite backlog to hide in. A shaped feature nobody bets on is marked stale and has to earn its place again. The pile doesn’t grow — it gets defended, merged, or dropped.

[Self-hosted]

You own the data. There is no “us” in the loop.

One container backed by an embedded SQLite file. No external database, no telemetry, no account on someone else’s server. The agent runs on your own Anthropic key.
~/cairn
docker run -d --name cairn \
  -p 3000:3000 \
  -v cairn_data:/data \
  -e NUXT_SESSION_PASSWORD="$(openssl rand -base64 32)" \
  -e ANTHROPIC_API_KEY="sk-ant-…" \
  ghcr.io/cairnpm/cairn:latest
[Ethos]

No telemetry. No detour. No lock-in.

Zero-egress

No telemetry, no phone-home. A linked product repo is grepped on your own disk and never uploaded anywhere.

Bring your own key

The agent runs on your Anthropic key. There is no data detour through us, because there is no “us” in the loop.

One process, one file

Node and an embedded SQLite file. No external database, no queue, no account on someone else’s server.

Source-available

FSL-1.1-ALv2: read every line, audit it, run it free forever. Each release turns Apache-2.0 two years after it ships.

[FAQ]

Questions people ask first.