Skip to main content

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_create
  • weekly_update
  • email_draft
  • scope_flag
  • sow_estimate
  • sow_draft
  • client_readout
  • scope_change
  • deliverable_release
  • prompt_update
  • prompt_base_update
  • skill_update
  • board_update
  • kickoff_brief
  • calendar_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.