The deploy button
The problem: you have a dangerous action — deploy to production, publish the release, run the migration — and you want a big friendly button with a real permission model around it. Traditionally: an internal tool plus an IAM policy plus an audit trail.
The pattern: make pressing the button write a document, and make the access function decide who may write it. The capability is the ACL.
js// access.js — the press capability
export default function (doc, oldDoc, user, ctx) {
if (doc.kind === "press") {
if (!user) throw { forbidden: "sign in to ship" };
if (!user.isOwner) ctx.requireAccess("crew"); // the deploy crew channel
return { channels: ["crew"], grant: { public: ["status"] } };
}
// …status docs, config, etc.
}
Grant the crew channel to the humans allowed to ship. Everyone else sees
the button render LOCKED — the UI reads its own capability with
useVibe("presses").can.create and tells the truth, because the same rule
runs server-side on the actual write. There's nothing to bypass: the button
is just a doc write, and the doc write is gated.
Downstream, the press doc enters a doc state machine: a watcher (a CI lane or the backend itself) sees the press, triggers the real deploy, and writes status back — which the button page renders live as the deploy progresses. The press ledger is the audit trail, with author, timestamp, and outcome on every doc.
In production: jchris/ship-button
The platform ships itself with this pattern:
jchris/ship-button fronts the
release fan-out workflow. Its dashboard reads the repo's tag streams and CI
runs client-side, ctx.callAI summarizes "what's about to ship" from the
pending commits (the story), and the glowing SHIP IT
is crew-gated exactly as above.
A detail worth stealing: when the platform's own operator opened it while browsing under an alt handle of the same account, the button rendered LOCKED — crew grants are handle-based, and even the owner's other handle doesn't inherit the press capability. The access model didn't special-case anybody; that screenshot ended up in the launch post because the lock telling the owner "no" is the whole pattern working.
Where it generalizes
Any privileged action wrapped as a doc write inherits the full stack: roles and channels for who, the state machine for what happened, the operator console for watching it, and live sync so the person who pressed and the person who watches see the same truth. Approve-the-expense, publish-the-newsletter, unlock-the-door — same button, different verb.