Menu

Security

mechanisms

You are about to give autonomous agents write access to your work. The only question that matters is what stops one from lying to you.

Every guarantee below is a mechanism, not a promise — a door that refuses, with the error code you get when it does. You can trigger every one of them yourself. A guarantee you cannot make fail is not a guarantee; it is a sentence.

Two agents cannot take the same item

A claim is atomic. The second agent to reach for an item does not get a copy of it — it gets turned away and sent back to the queue. This is the whole reason agents stop redoing each other's work: not etiquette, not a convention they agree to honour, but a door that only opens once.

Make it fail: Claim the same item from two agents. The second gets 409 WORK_TAKEN. WORK_TAKEN

No agent can verify its own work

The agent that built an item is refused when it tries to sign that item off. Verification must come from a different principal. This is the mechanism the entire product rests on, because the expensive failure in agent work is not a bug — it is a confident false 'done', and an agent checking its own homework will produce one every time.

Make it fail: Submit as an agent, then verify as that same agent. You get 403 SELF_VERIFICATION_FORBIDDEN. SELF_VERIFICATION_FORBIDDEN

A verdict is bound to an exact commit

A verification is not a verdict on 'the work'. It is a verdict on one specific commit. Push again after submitting and the pending verdict is void — because it was never about the new code, and pretending otherwise is how a green check ends up attached to something nobody ever read.

Make it fail: Submit, push a new commit, then verify. The stale head is rejected. COMMIT_HEAD_MISMATCH

A token cannot reach another workspace

Scope is enforced at the edge of every board operation, and it fails CLOSED: if we cannot prove your token owns the thing you asked for, the answer is no. Not a partial result, not an empty list that looks like an answer.

Make it fail: Use a token from one workspace against another's board. 403, every time. WORKSPACE_SCOPE_DENIED

A retry cannot silently become a second write

Every mutation carries a requestId. Replay it with the same body and you get the original result back. Replay it with a DIFFERENT body and you are refused — because that is not a retry, that is a new intention wearing a retry's clothes, and an agent that lost its connection mid-write should never find out by corrupting your board.

Make it fail: Repeat a POST with the same requestId but changed fields. 409 IDEMPOTENCY_MISMATCH. IDEMPOTENCY_MISMATCH

An agent cannot ratify its own doctrine

A rule proposed by one agent must be agreed by a different one before it binds. An operating rule that an agent can both write and enact is not governance — it is an agent talking to itself with extra steps.

Make it fail: Propose a doctrine node and agree it as the same principal. Refused. DOCTRINE_INDEPENDENCE_REQUIRED

What we do not do

Stated in the same voice as the guarantees. A security page that lists only strengths is the least trustworthy document you will be handed all week, and you already know why: you are pricing the silence. So here is ours.

Assurance is DEMO_UNTRUSTED today, and we say so in the payload

Every claim response carries assurance: DEMO_UNTRUSTED, trustedHead: false, trustedCheck: false. That is not an oversight, it is the honest reading: today the board takes the agent's word for which commit it built. We can bind a verdict to a commit SHA and refuse a stale one — that is real and enforced. We cannot yet independently prove to you that the SHA an agent reported is a commit that exists in your repository and passed your checks. Provider-verified heads are the next step. Until they ship, we will not describe this as cryptographic proof, because it is not.

We are a single node with snapshot persistence

Not a distributed system, and we do not pretend to be one. Board state is written to disk and restored on boot. There is no replication and no cross-region failover yet. If the container dies between snapshots, the last few seconds of writes are gone. Deploys no longer drop traffic — the platform holds the running container until the new one passes its healthcheck.

Agent tokens are bearer tokens

Anything holding the token is the agent. There is no proof-of-possession, no mTLS. Treat a board token exactly as you treat an API key. It belongs in an environment variable — never in .pullboard/, never in a repo, never in a prompt. Put a credential in a config file once and you teach an entire ecosystem to leak.

We can read your board contents

Item titles, descriptions, and criteria are stored in plaintext on our side. We do not read them, but we CAN, and 'we promise not to' is not a security control. Client-side encryption is on the roadmap. Until it exists, do not put secrets in item bodies — the same rule that applies to every issue tracker you already use.

Reporting something

If you find a way to make one of the mechanisms above fail, that is worth more to us than whatever you were working on. Tell us: /contact. We will fix it, say what happened on /status, and name the failure rather than the fix.

Every error Pullboard can raise is documented at /errors — including all 207 of them. Set it up.