GET /api/governor/proposals — #708 K-08a: list EVERY open (draft) profile-version proposal across the workspace's profiles (the workspace-wide owner review inbox that backs the unified Inbox governor feed; the per-profile `/api/agent-profiles/{id}/proposals` backs the profile page). Owner-gated, reusing the SAME `proposals::list_open_for_workspace` service the chat `/governor` command calls.
const url = 'https://example.com/api/governor/proposals';const options = {method: 'GET', headers: {cookie: 'supacloud_session=<supacloud_session>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://example.com/api/governor/proposals \ --cookie supacloud_session=<supacloud_session>Authorizations
Section titled “Authorizations”Responses
Section titled “Responses”Open (draft) profile-version proposals across the workspace
A profile-version change proposal (migration 218 profile_version_proposal).
object
When the proposal was opened (#976 — union-inbox sort key).
The candidate config, stored in AgentProfileInput shape so approval reuses
the validated update_profile writer. Runtime stays serde_json::Value; the
spec types it as [AgentProfileInput] (the FE reads name / fixed_model /
model_policy off it).
object
ADR 0045 §3.6 — default reasoning effort
(minimal | low | medium | high | max). Optional; preserves the current
value on update, leaves None (inherit the runner default) on create.
Issue #364 / ADR 0039 (D7); #708 who-3 — normal | workflow (ultracode
RETIRED to the effort axis). Optional; preserves the current value on update,
defaults to normal on create.
ADR 0045 §3.2 — opt this profile into the interactive tool-approval gate
(resolve_interactive_approvals_for_run). Optional; preserves the current
value on update, defaults to false on create. #708 W5 wired this WRITE
path (it was read-only before — the create/update never persisted it).
#1018 — per-profile DEFAULT for the harness turn limit (migration 340,
positive). DOUBLE-Option: absent preserves the current value on update / leaves
NULL (no default — the runner’s 500 applies) on create; an explicit null
clears it; a value sets it. “Absent = unchanged” is load-bearing — the
simple profiles tab sends a partial payload, and it must never null a
stored default (the #858 W4a ops-cap pattern).
ADR 0049 (#547 / #548) — opt-in gate for the agent memory.create MCP
tool. Optional; preserves the current value on update, defaults to false
(fail-closed) on create. A workspace admin sets this on the profile editor
to open the unreviewed direct-write path.
#858 W4a — per-profile override of the profile-hourly MCP Ops budget
(migration 320; range 1–1000). Same DOUBLE-Option semantics as
mcp_ops_per_task_cap. The workspace-daily Ops ceiling stays fixed.
#858 W4a — per-profile override of the per-task/per-tool MCP Ops budget
(migration 320; range 1–500). DOUBLE-Option: absent preserves the current
value on update / leaves NULL (the ADR 0028 default, 10) on create; an
explicit null clears the override back to the default; a value sets it.
Admin-gated — the profile PUT already requires workspace admin.
The script-run allowlist. Optional; absent preserves the current value on update
/ leaves None (OPEN — every script allowed) on create; a value (incl. [],
fail-closed) sets it. Mirrors capability_allowlist. #708 W9 wired this so a
workspace manifest round-trips it — the manifest apply supplies a fail-closed
Some([]) default (never the open None) when the manifest omits it.
Examplegenerated
[ { "agent_profile_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "created_at": "2026-04-15T12:00:00Z", "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "proposed_config": { "avatar_kind": "example", "avatar_value": "example", "capability_allowlist": [ "example" ], "color": "example", "default_agent_type": "example", "description": "example", "effort_default": "example", "enabled": true, "execution_mode": "example", "fixed_model": "example", "interactive_approval": true, "max_turns": 1, "mcp_memory_create": true, "mcp_ops_per_hour_cap": 1, "mcp_ops_per_task_cap": 1, "memory_policy": "example", "model_policy": "example", "name": "example", "persona_prompt": "example", "post_flight_checks": "example", "pr_template": "example", "pre_flight_checks": "example", "retry_policy": "example", "review_required": true, "script_allowlist": [ "example" ], "slug": "example", "tags": [ "example" ] }, "rationale": "example", "status": "example" }]Authentication required
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Permission denied
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Structured server error
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}