Sign-off
Where a decision stands and what you can do about it: who needs to weigh in, how each person has responded, the recorded call — and, scoped to you, the actions you can take right now.
A decision is a Droplet wearing the decision Type (see the Decisions concept). Its sign-off is the live state of that decision: the RAPID roster, each approver's response, and the decider's recorded call. There is no separate "decision" object — the Droplet holds the content, the Type makes it a decision, and this resource is how you read and drive its sign-off.
The read (get) is affordance-bearing. It returns the current state and the actions available to you, each with a reason when it isn't (e.g. "only the decider can record the call"). A person — or an agent — can act on what's available without having to know the rules.
What you can do:
cast— record a response as an approver: agree, agree with a condition, or disagree (a comment is required for the latter two). PassonBehalfOfto record someone else's position — see Recording for someone else below.clear— remove a recorded response while sign-off is still open. Yours, or (as a facilitator) one you recorded for someone.finalize— the decider records the call: approve → decided, block → blocked. (In practice the decider's owncastrecords it.)reopen— clear a recorded call and return the decision to open.open/close— an editor or facilitator turns sign-off on (draft → in flight) or back off (→ draft); responses are retained either way. To take the decision off the Droplet altogether, clear its Type (droplet.clearType) — that discards the roster, the responses and the call, and reports what it took.set-proposition— an editor or facilitator sets "what you're signing off on", the statement shown above the roster.mine— across every decision you can reach, the ones waiting on you.list— every decision you can see, each with its sign-off state; filter byphase, yourrole, ortag. (The query behind the Decisions dashboard.)
Recording for someone else. Decisions get made in rooms, and the person running the room is often not the person holding the role. Members of the @drop-facilitators group (and editors on the Droplet) can pass onBehalfOf to cast and clear, and can drive the lifecycle — open, close, set-proposition, and the roster — on any decision they can already read. Group membership grants no access of its own, and never unlocks editing the Droplet itself.
A proxied response carries castBy on the roster row, and the event log records both who acted and who it was for. The subject overwrites it by casting themselves, which clears castBy and makes the row self-affirmed again. Recording the decider's response records the call, exactly as their own cast would — attributed to them, and reopenable by them.
Everything else is scoped to the calling identity: you only see and act on decisions you can access, in the roles you actually hold. The behavior is generic — a Type declares which of its user-list fields carry the approver and decider roles and which status values gate the flow — so the same surface works for any sign-off-shaped Type. A RAPID decision is the first one.
The Sign-off object
Every Sign-off carries these attributes.
Attributes
draft (not yet open), open (collecting sign-offs), decided, or blocked.isApprover marks the roles that cast sign-offs. Members are people or teams; a team in an approver role carries a tally of how its members voted.{ email, name, vote (agree|condition|disagree|null), comment, castBy }. vote: null = hasn't weighed in. castBy names the facilitator who recorded it for them, and is null when they recorded it themselves.{ outcome (approved|blocked), summary, decidedBy, decidedAt }. Null while open.{ email, isApprover, isDecider, vote, comment, canManage, canFacilitate, castBy }. canManage = editor on the Droplet. canFacilitate = may drive this decision (record for others, open/close, proposition, roster) — true for editors and for @drop-facilitators members who can read it. castBy is set when your own response was recorded by someone else.{ name (cast|clear|finalize|reopen|cast-for-others), available, reason? }. Act on available; surface reason when blocked. cast-for-others answers "may I record someone else's position", which cast (your own) does not.{
"configured": true,
"phase": "open",
"status": "in-flight",
"proposition": "Adopt RDS Proxy in front of the SSR fleet to end burst-time connection storms.",
"roster": [
{
"key": "recommend",
"label": "Recommend",
"isApprover": false,
"members": [
{
"kind": "user",
"email": "kate@himarley.com",
"name": "Kate Horning"
}
]
},
{
"key": "agree",
"label": "Agree",
"isApprover": true,
"members": [
{
"kind": "group",
"slug": "platform-team",
"name": "Platform Team",
"memberCount": 3,
"hasViewer": true,
"tally": {
"agree": 1,
"condition": 1,
"disagree": 0,
"pending": 1
}
}
]
},
{
"key": "decide",
"label": "Decide",
"isApprover": false,
"members": [
{
"kind": "user",
"email": "will@himarley.com",
"name": "Will Sherlin"
}
]
}
],
"approvers": [
{
"email": "you@himarley.com",
"name": "You",
"vote": null,
"comment": ""
},
{
"email": "sarah@himarley.com",
"name": "Sarah Lee",
"vote": "condition",
"comment": "Confirm the rollback plan first",
"castBy": "kate@himarley.com"
}
],
"signedCount": 1,
"totalApprovers": 3,
"verdict": null,
"openedAt": "2026-08-05T14:00:00.000Z",
"viewer": {
"email": "you@himarley.com",
"isApprover": true,
"isDecider": false,
"vote": null,
"canManage": false,
"canFacilitate": false,
"castBy": null
},
"canClose": false,
"actions": [
{
"name": "cast",
"available": true
},
{
"name": "clear",
"available": false,
"reason": "you have not signed off yet"
},
{
"name": "finalize",
"available": false,
"reason": "only the decider can record the call"
},
{
"name": "reopen",
"available": false,
"reason": "nothing to reopen — no verdict recorded"
},
{
"name": "cast-for-others",
"available": false,
"reason": "you are not a facilitator or editor on this decision"
}
]
}Methods
Endpoints to operate on a Sign-off. The example switches between curl, drop CLI, and MCP via the dropdown — your choice persists across the page.
Get sign-off
Read a Droplet's sign-off state — roles, responses, verdict, status — plus the actions available to you (an affordance-bearing read). Blocked actions carry a reason. Everything is scoped to the calling identity: you only see what you can act on.
drop signoff get migrate-drop-to-ai{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Cast sign-off
Record a response as an approver: agree, condition (agree with a condition), or disagree. A comment is required for condition and disagree. Approver-gated — the subject must hold an approver or decider role on the Droplet's Type. Casting again updates the response; use clear to remove it.
Pass onBehalfOf to record someone else's position, which is what a facilitator does live in a meeting. The response is attributed (castBy), the event log records both who acted and who it was for, and the subject can overwrite it themselves at any time — which clears the attribution.
drop signoff cast migrate-drop-to-ai --vote agree{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Clear sign-off
Remove a recorded sign-off response while the decision is still open. Clears your own by default; a facilitator can pass onBehalfOf to remove a response they recorded for someone. Finalized decisions must be reopened before responses can change.
drop signoff clear migrate-drop-to-ai{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Finalize sign-off
Record the decider's call and advance the Droplet's status (approve → decided, block → blocked). Decider-gated — the caller must hold the decider role. A summary is required.
drop signoff finalize migrate-drop-to-ai --outcome approved --summary "Approved — migrate to himarley.ai over two weeks."{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Reopen sign-off
Clear a recorded verdict and return the Droplet to the open status so approvers can sign off again. Open to the decider AND to facilitators — a facilitator can record the decider's call, so they have to be able to unmake it, or proxying a verdict would be a one-way door.
drop signoff reopen migrate-drop-to-ai{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Open for sign-off
Open a draft decision for sign-off — flips its status to the open value so approvers can respond. Facilitator-gated: editors on the Droplet, plus @drop-facilitators members who can read it. Backs the "Enable sign-off" author action and the rapid agent opening the room after staffing.
drop signoff open migrate-drop-to-ai{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Close (un-enable) sign-off
Un-enable sign-off — return an open decision to draft. Facilitator-gated: editors on the Droplet, plus @drop-facilitators members who can read it. The inverse of signoff.open; retains responses so re-opening keeps prior sign-offs.
drop signoff close migrate-drop-to-ai{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Set the proposition
Set "what you're signing off on" — the succinct statement shown above the sign-off. Facilitator-gated (canFacilitateSignoff): editors on the Droplet, plus @drop-facilitators members who can read it. The tray's inline editor and the rapid agent both drive this; pass an empty string to clear it.
drop signoff set-proposition migrate-drop-to-ai --proposition "Adopt RDS Proxy in front of the SSR fleet to end burst-time connection storms."{
"configured": false,
"status": "example",
"phase": "draft",
"proposition": "example",
"roster": [],
"approvers": [],
"signedCount": 0,
"totalApprovers": 0,
"responseCount": 0,
"verdict": {
"outcome": "approved",
"summary": "example",
"decidedBy": "example",
"decidedAt": "example"
},
"openedAt": "example",
"viewer": {
"email": "example",
"isApprover": false,
"isDecider": false,
"vote": "agree",
"comment": "example",
"canManage": false,
"canFacilitate": false,
"castBy": "example",
"castByName": "example"
},
"canClose": false,
"blockedApprovers": [],
"actions": []
}Sign-offs awaiting me
List the sign-offs across all Droplets you can reach where you hold a role — filtered to those awaiting your action. Powers a personal "decisions awaiting your sign-off" inbox and lets an agent ask "what's blocked on me?"
drop signoff mine{
"items": []
}List decisions
List every decision you can see, each with its sign-off state (phase, who decides, how far along). Optionally filter by phase, your role (decider|approver), or tag. This is the query behind the /decisions dashboard — the answer to "list all in-flight decisions and where each stands" or "decisions where I'm the decider".
drop signoff list{
"items": []
}