Specs and agents, kept in step

Name it true.

Konjir is where product people and developers say what software should do, once and precisely. Agents work from that statement. When one can’t tell what you meant, it asks instead of guessing.

A field at first light: fog over the grass, power lines crossing toward an amber horizon, a thin moon above.
stale kj:password-reset-pg@2#B9

PR8 changed in version 3. This element was written against the old text.

At most 5 3 reset requests per email address per hour.

The fog

Most specs are out of date by the time anyone builds from them.

Intent lives in too many places

A wiki page says one thing, a ticket another, the code a third. Nobody can say which one is true.

Changes don’t reach what depends on them

A requirement changes in a document. The code written against it never hears.

Agents fill gaps with guesses

Hand an agent an ambiguous ticket and it picks an answer and keeps going. You find out in review, or in production.

How it works

Say it once. Everything that depends on it hears.

  1. 01

    Write the intent

    A functional spec in plain words. Every requirement gets a true name that keeps pointing at it, through every edit.

    kj:checkout@3#R1
  2. 02

    Bind it

    Engineers, or their agents, write the technical binding. Each element links to the requirement it serves, pinned to the exact text it was checked against.

    kj:checkout-stripe@1#C2
  3. 03

    Change it

    Edit a requirement and only what was written against that line is marked stale, with a word-by-word diff of what changed.

  4. 04

    Settle it

    Whoever owns the binding checks the change. It still holds, or it gets revised. Nothing stays quietly out of date.

A change lands exactly where it matters

Lee tightened a rate limit from 5 to 3 requests an hour. One binding element relied on it, so that one element was marked. Twelve others weren’t touched.

B8 Revoke sessions from before the reset: delete them and set sessions_valid_after. holds
B9 Rate limit: a sliding window allowing 5 requests per normalized email per hour. stale

kj:password-reset#PR8 changed in version 3.

At most 5 3 reset requests per email address per hour. Requests over the limit get the same response as PR3.

B10 The request always returns 202 with the same body. holds

Roles

Every agent works inside its circle.

Product writes intent. Engineering writes the binding. An agent in one layer can’t edit the other, so when it needs something across that line, it asks.

Every commit passes a review gate first. If a requirement starts to read like implementation, the gate raises a question instead of letting it slide. Answers are kept as precedent, so a settled question isn’t asked twice.

asks eng-agent asked about kj:password-reset@3#PR3
PR3 says the response is the same whether or not the email belongs to an account. Should the response time be indistinguishable too? Today the 202 returns faster for unknown emails, which can still reveal whether an account exists.

Waiting on the product layer. The engineer agent keeps working on everything else.

Bring your own harness

Your agents connect with the subscriptions you already have.

Konjir runs as Kolab, an MCP server. Connect Claude Code, or any client that speaks MCP, and your agents read specs, resolve addresses, submit drafts and ask questions as you.

Kolab never runs a model. Review and the heavy thinking happen in your harness, on your plan, under its terms. The rules come down the connection, so there is nothing to configure per agent.

Terminal
# connect an agent once
claude mcp add --transport http konjir \
  https://kolab.konjir.com/mcp \
  --header "Authorization: Bearer $KONJIR_TOKEN"

# or work from any shell
konjir resolve kj:checkout@3#R1
konjir stale
konjir queries

Kolabs

One project, one hard edge.

A kolab holds one project: its spec, the bindings built on it, their links and questions. Agents that connect to it see only what is inside it, so the one working on checkout never wanders into accounts.

Accounts

accounts

Sign-in, sign-up and account recovery.

kj:password-reset@3kj:password-reset-pg@2
stale1 binding element asks1 waiting on you

Checkout

checkout

Cart to receipt: pricing, payment and the confirmation email.

kj:checkout@2kj:checkout-stripe@1
holdsEverything holds

What it replaces

One place for intent, implementation and the questions between them.

The wiki page
A spec where every line has an address and a version, and knows what was built from it.
The ticket
A stale mark that names exactly what changed, shows the diff, and clears when someone settles it.
The comment thread
A question routed to whoever owns the answer, kept as precedent for every agent that comes after.

Konjir is in early testing.

We’re working with teams who build with agents every day. Sign up with your GitHub account, then connect your agents.