Approvals
Approvals are SABLE's human-in-the-loop control surface. They live in the Supabase approvals table and are surfaced by Home through /api/inbox and /api/approvals.
Status Model
The API prevents terminal statuses from being regressed into approved.
Approval Kinds
Current approval kinds:
asana_task_createweekly_updateemail_draftscope_flagsow_estimatesow_draftclient_readoutscope_changedeliverable_releaseprompt_updateprompt_base_updateskill_updateboard_updatekickoff_briefcalendar_event_create,calendar_event_update,calendar_event_cancel
asana_task_create and the three calendar_event_* kinds are the ones that execute an external
write, each behind its own operator switch. Asana proposals are currently paused at source — see
SPINE_DISABLED_PROPOSAL_KINDS.
Several kinds apply inside SABLE the moment they are approved, with no Execute step:
board_update appends a board_state row (the per-project status line get_board reads on every
later run); prompt_update folds a learned rule into the live prompt; prompt_base_update promotes a
new base prompt; skill_update rewrites a skill body; kickoff_brief attaches the discovery headline
to the project. Approving those is the change, not a record that someone agreed with it.
Drafting approval kinds publish or release
inside the SABLE portal only: weekly_update and scope_change insert published client_updates;
sow_draft and client_readout create internal deliverables; deliverable_release makes an existing
deliverable visible to the client. prompt_update is a lead-reviewed learned rule for Prompt Control; when
approved, SABLE folds it into the managed rules block on the live agent prompt.
API
List approvals:
GET /api/approvals?status=pending
Approve one:
{ "action": "approve", "id": "approval-uuid" }
Approve and execute an external write:
{ "action": "approve_and_execute", "id": "approval-uuid" }
Reject one:
{ "action": "reject", "id": "approval-uuid", "reason": "not needed" }
Edit one:
{ "action": "edit", "id": "approval-uuid", "payload": { "due": "2026-07-01" } }
Batch approve:
{ "action": "batch_approve", "ids": ["a", "b", "c"] }
Execute:
{ "action": "execute", "id": "approval-uuid" }
Execution Gate
Executing an Asana proposal calls the Supabase Edge Function asana-act. The function requires:
- Valid Supabase JWT.
- Admin/lead caller.
- Approval belongs to caller org.
- Approval status is
approved. - Approval kind is
asana_task_create. ASANA_ACT_WRITES_ENABLED=true.
Audit
Approved/rejected/edited actions log to board_feedback. Executed external writes log to audit.