Skip to content

A guided track · Architect & tech lead

The decision is in a thread, the rationale is in a doc, and a PR is quietly contradicting both.

The decision was made in a thread. Somebody summarised it in a document. The document is now eleven months old, three of its claims have quietly stopped being true, and the pull request in front of you contradicts one of them without anybody involved knowing the constraint existed.

None of that is a discipline problem. It is a storage problem: the decision, the constraint it was made under, the work that upholds it and the document that describes it are four different systems, so nothing can notice when they stop agreeing. Here they are four kinds of node in one graph, and noticing is a query.

Every step is one move, on three surfaces: the shell, a chat client over MCP, and the browser console vrek-api serves. Pick whichever you would actually touch — the choice holds for the rest of the track. Where a surface genuinely cannot do a step, it says so rather than pretending.

01

Raise the question with what each answer costs

An option is choice|consequence, written when the context is in someone's head rather than reconstructed from a thread later. --guided-by names the principles the answer must not contradict without an argument, and --serves names the goal it would advance. The question blocks the work it is about, so it is answered rather than outlived.

On the command line

the fork, recorded as a fork
$ vrek ask "Postgres or SQLite for the shared server?" \
$     --option "postgres|a service to run from day one" \
$     --option "sqlite|single binary, one writer, no ops" \
$     --guided-by pri-4kd92mv --serves gol-9wbe2ch \
$     --blocks iss-3bg971s --owner mike --revisit 2026-10-01

In Claude, or any client that speaks MCP

an agent that reads the constraints first vrek over MCP
you

Plan the shared server. Storage first.

vrek_principles tool call
{ "items": [
    { "id": "pri-4kd92mv", "title": "Runtime code depends on nothing outside Node stdlib",
      "weight": 0.9 } ], "total": 11 }
claude

One of the eleven bears on this directly, and it is weighted 0.9. Postgres contradicts it; SQLite keeps it and costs you a single writer. That is a trade you make, not one I make quietly inside a plan.

vrek_ask tool call
question: "Postgres or SQLite for the shared server?"
options: [{ option: "postgres", consequence: "a service to run from day one" },
           { option: "sqlite", consequence: "single binary, one writer, no ops" }]
guided_by: ["pri-4kd92mv"]
serves: ["gol-9wbe2ch"]
blocks: ["iss-3bg971s"]
owner: "mike"
revisit: "2026-10-01"
{ "id": "que-8k3m1qp", "status": "open", "blocks": ["iss-3bg971s"] }

In the console

Not this surface

Raising the question belongs to whoever was about to guess, and that is the shell or the agent. What the console adds is the check you would want before answering: the question's page carries its guided by and serves edges as links, so the principle the answer must not contradict is one click from the answer, not in a thread somebody would have to remember.

02

Attach the decision to the question it answers

A decision is not a paragraph in a folder. It answers a specific question, it can supersede an earlier decision, and work upholds it. show walks all of that: what this replaced, what replaced it, and what is currently standing on it — which is the thing you actually want when someone asks why it is like this.

On the command line

the trail, both directions
$ vrek decide "SQLite in-process; a shared server is a later, separate problem" \
$     --answers que-8k3m1qp

$ vrek show dec-3s57zg1
supersedes ▪ The public site is hand-written HTML with no build step
upheld by  ◐ Build and deploy the vrek site on Cloudflare Workers

In Claude, or any client that speaks MCP

why it is like this, asked six months later vrek over MCP
you

Why is this SQLite? Somebody is about to argue for Postgres again.

vrek_show tool call
id: "dec-3s57zg1"
{ "kind": "decision", "title": "SQLite in-process; a shared server is a later, separate problem",
  "edges": [
    { "kind": "answers", "other": { "id": "que-8k3m1qp", "title": "Postgres or SQLite…" } },
    { "kind": "supersedes", "other": { "id": "dec-vck585y", "title": "The UI is a live console…" } },
    { "kind": "upholds", "direction": "in", "other": { "id": "iss-3bg971s" } } ] }
claude

It answers que-8k3m1qp, which was asked under pri-4kd92mv, and one open issue is standing on it. Nothing has superseded it. If the argument for Postgres is new information, the move is a finding and a new decision that supersedes this one — not an edit, because then the issue standing on it would be standing on nothing.

In the console

both directions, from the log vrek-api
vrek console #/node/dec-3s57zg1 live

Connections

every edge kind, both directions
  • answers que-8k3m1qp · Postgres or SQLite for the shared server?
  • supersedes dec-vck585y · The UI is a live console
  • upheld by iss-3bg971s · Build the shared server
03

State the constraint once, and weight it

A principle is a standing constraint the workspace has already decided — not advice, and not a style guide. It guides the nodes it is linked to, it carries a weight so that two principles in conflict are not automatically equal, and an agent reads the principles in force before it proposes a design. Contradicting one needs an argument rather than an oversight.

On the command line

constraints in force
$ vrek principle "Runtime code depends on nothing outside Node stdlib" \
$     --guides iss-3bg971s,dec-3s57zg1
pri-4kd92mv

# unset is not zero: a principle with no weight is not weightless
$ vrek weight pri-4kd92mv 0.9
$ vrek principles

In Claude, or any client that speaks MCP

what the agent is reading before it designs anything vrek over MCP
you

Write down that runtime code depends on nothing outside Node's standard library, and link it to the shared-server work.

vrek_add_principle tool call
title: "Runtime code depends on nothing outside Node stdlib"
guides: ["iss-3bg971s", "dec-3s57zg1"]
weight: 0.9
{ "id": "pri-4kd92mv", "status": "active", "weight": 0.9 }
claude

Recorded and weighted. This is the list I read at the start of a design task — so the next agent on this workspace, in a session neither of us is in, is constrained by it without anybody remembering to paste it into a prompt.

In the console

the one judgement a console is better at vrek-api
vrek console #/principles live

Active

11
  • Runtime code depends on nothing outside Node stdlib weight 0.9 · guides 2
  • The API is the product: every surface is a client of it weight 0.8 · guides 14

New principle

04

Ask what is pulling against what

tensions is the query that has nowhere to live in a wiki: work that serves a goal while breaching a principle. It does not resolve anything for you — the trade may well be the right one — it just refuses to let the trade happen without anyone seeing it. And a violation can always be recorded: violation is never refused, because a system that cannot record being broken teaches people to stop telling it.

On the command line

where the goal and the constraint disagree
$ vrek tensions
◐ iss-3bg971s  serves gol-9wbe2ch (0.7)
breaches ▪ Runtime code depends on nothing outside Node stdlib (0.9)

$ vrek violation iss-3bg971s pri-4kd92mv

In Claude, or any client that speaks MCP

recording the breach rather than arguing it away vrek over MCP
you

We are doing it anyway — the shared server needs Postgres. Record that honestly.

vrek_record_violation tool call
node: "iss-3bg971s"
principle: "pri-4kd92mv"
{ "node": "iss-3bg971s", "principle": "pri-4kd92mv", "recorded": true }
vrek_tensions tool call
{ "items": [
    { "node": { "id": "iss-3bg971s" }, "serves": ["gol-9wbe2ch"],
      "against": ["pri-4kd92mv"] } ], "total": 1 }
claude

Recorded — this call is never refused, on purpose. The work still serves the goal; it now also breaches a 0.9 principle, and both facts are in the same row rather than one being in the log and the other in somebody's memory of the meeting.

In the console

a trade, arguable rather than discovered later vrek-api
vrek console #/tensions live

Tensions

1
  • Build the shared server on Postgres serves: An engagement's reasoning survives · works against: Runtime code depends on nothing outside Node stdlib

Violations

05

Write documents that cannot go stale

A document here is a list of blocks, and a block can be a node or a query rather than text. It resolves when it is read, so the section listing open work against a component is right at the moment you look at it. What is left — the prose you wrote — is what you vouch for with ack, and drift tells you which of those documents something has moved under since.

On the command line

a view over facts, not a copy of them
$ vrek doc "Storage architecture"
$ vrek block doc-k2m9x1p --text "SQLite in-process, one writer. See dec-3s57zg1."
$ vrek block doc-k2m9x1p --node dec-3s57zg1
$ vrek block doc-k2m9x1p --query kind=issue,status=open

$ vrek render doc-k2m9x1p   # resolves against now
$ vrek ack doc-k2m9x1p      # I vouch for this, as of this moment
$ vrek drift                # what has moved under one since

In Claude, or any client that speaks MCP

context an agent reads, rather than a page it copies vrek over MCP
you

Give the next agent the storage picture.

vrek_add_doc tool call
title: "Storage architecture"
blocks: [{ type: "text", text: "SQLite in-process, one writer. See dec-3s57zg1." },
          { type: "node", id: "dec-3s57zg1" },
          { type: "query", query: { kind: "issue", status: "open" } }]
{ "id": "doc-k2m9x1p", "blocks": 3 }
vrek_render_doc tool call
id: "doc-k2m9x1p"
{ "resolved_at_seq": 3640,
  "blocks": [ { "type": "text", … },
              { "type": "node", "node": { "id": "dec-3s57zg1", "status": "recorded" } },
              { "type": "query", "items": [ … 7 open issues … ] } ],
  "drift": { "acknowledged_at_seq": null } }
claude

Two of the three blocks resolved just now, so they cannot be out of date — only the sentence I wrote can be wrong. It has never been acknowledged, which is what drift reports until a human vouches for it.

In the console

what its blocks resolve to as you look at it vrek-api
vrek console #/node/doc-k2m9x1p live

Resolved now

3 blocks
  • SQLite in-process, one writer. See dec-3s57zg1. text · the only part that can go out of date
  • SQLite in-process; a shared server is a later, separate problem node · recorded · resolved on load
  • kind=issue, status=open query · 7 items · re-run every read
  • Something has moved under it since it was last acknowledged. and Drift lists every document in that state, with the covered node that moved
06

Draw the system, then check the plan adds up

Components are things that exist, with what they depend on and how often they fail on their own account. A flow is an ordered set of calls over them, each with a latency budget, a per-call failure rate and a call count. flow-budget composes those and tells you where the plan does not add up — before it is built, which is the only time that answer is cheap.

On the command line

a sequence diagram that is checked, not drawn
$ vrek component "search-api" --depends-on cmp-3j1vq8d,cmp-p04zxwe \
$     --failure-rate 0.1%
cmp-91ks7dz

$ vrek flow "Search request" --serves gol-9wbe2ch
flo-2p6xk9r
$ vrek flow-step flo-2p6xk9r --from cmp-tt6b1nq --to cmp-91ks7dz \
$     --budget 200 --self 15
$ vrek flow-step flo-2p6xk9r --from cmp-91ks7dz --to cmp-3j1vq8d \
$     --budget 120 --count 3

$ vrek flow-budget flo-2p6xk9r
search-api: self 15 + contributors 360 = 375ms against a 200ms budget

$ vrek flow-diagram flo-2p6xk9r --out docs/search.mmd   # mermaid

In Claude, or any client that speaks MCP

the arithmetic, before anything is built vrek over MCP
you

Search: browser to the API, the API queries postgres three times. 200ms end to end. Does that work?

vrek_set_flow_steps tool call
id: "flo-2p6xk9r"
steps: [{ from: "cmp-tt6b1nq", to: "cmp-91ks7dz", budgetMs: 200, selfMs: 15 },
         { from: "cmp-91ks7dz", to: "cmp-3j1vq8d", budgetMs: 120, count: 3, protocol: "SQL" }]
{ "id": "flo-2p6xk9r", "steps": 2 }
vrek_flow_budget tool call
id: "flo-2p6xk9r"
{ "over": [ { "step": "search-api", "budgetMs": 200,
    "selfMs": 15, "contributors": 360, "totalMs": 375 } ] }
claude

No. Three sequential 120ms queries plus 15ms of its own work is 375ms against a 200ms budget. The cheap answers are a smaller count, a smaller per-query budget, or a bigger end-to-end one — but the plan as stated does not add up, and that is now recorded rather than discovered in staging.

In the console

drawn, and editable in place vrek-api
vrek console #/flow/flo-2p6xk9r live

Steps

2 · Search request
  • browser → search-api call · budget 200ms · self 15ms
  • search-api → postgres call · SQL · budget 120ms · ×3
  • Diagram copy the mermaid source, or download .mmd, SVG or PNG

Alternate flows

A finding is not an opinion

A fact from outside — what a benchmark showed, what a vendor's limit is — is vrek finding with its sources and the date it was true. One with no source is refused. One that stops being true is superseded rather than edited, so the decision that rested on it still shows what it rested on.

Software is the first domain, not the only one

Nothing in the graph knows it is describing code. Requirements gathering and analysis run the same loop, and what an agent is told on connect belongs to the workspace rather than to a file in a repository.