Skip to main content
No change ships without sign-off. RStack gates planning, requirements, and architecture by default, and lets you enforce stricter, role-based policy.

How approvals work

When a task reaches a gate, the run blocks and records an approval_gate_blocked event. A human resolves it:
The approver is recorded as the resolved identity (git config or RSTACK_USER) — not a generic placeholder. Resolving from the Business Hub is also possible (see the token below).

Enforce policy — .rstack/policy.json

Make selected stages require approval in every mode, including express runs:
  • required_approvals — task id → artifacts that must be approved before that task can run. Enforced in interactive and express mode.
  • required_stage_approvals — canonical stage id (00-environment14-cost-estimation) → artifacts that must be approved before any task entering that stage can run. No task ids needed. Enforced in every mode.
  • approvals.every_stage — blanket human gate: every task must have a stage-approval:<stage-id> artifact approved for each canonical stage it enters (e.g. sdlc_approve(artifact="stage-approval:07-code", ...)). Approving a stage once unblocks all tasks entering that stage for the rest of the run. Enforced in every mode.
  • enforce_in_express — also apply the default interactive gates to express runs.
  • managers — only these people may resolve approvals (see below).

Manager allow-list

When a manager list is configured (via policy.json managers[] or the RSTACK_MANAGER_USERS env var, comma-separated), only those identities can resolve a gate. Anyone else is rejected. With no list configured, any identified user may approve.

Dashboard approval token

Approving from the browser requires a signed token so a manager’s identity can’t be spoofed from an unauthenticated request:
  • With the token set, the dashboard sends it as a header; approvals also require a same-origin request and Content-Type: application/json.
  • Without the token set, browser approvals are disabled (the secure default) — approve via sdlc_approve instead.
  • Every dashboard approval records audit-proof actor evidence, not just a name.
The CLI path (sdlc_approve) always enforces the manager allow-list. The token specifically protects the dashboard endpoint from spoofed requests.

Everyone gets paged when a gate blocks

A blocked gate fires a notification to every configured channel (webhooks) and pops a browser notification in the hub — so the manager doesn’t have to be watching the dashboard to know work is waiting.

Email approval notifications

Register your team once and the right person gets an email the moment a gate blocks — the manager for guardrail overrides, the team lead for code-stage sign-offs, the release pair for release-readiness.json. Email is a notification layer only: the claim gate stays the enforcement, and the approval itself is always recorded through RStack’s audited, token-verified path — never from the email. Sending uses Azure Communication Services Email (REST + HMAC access-key signing, implemented with Node built-ins — no new dependencies). 1. The secret stays in the environment — never in any .rstack/*.json file (credential-shaped keys there are a hard validation error):
2. The committable half lives in .rstack/notifications.json — sender address, people, and routing:
Role names are free-form. Routing patterns resolve in precedence order: exact artifact namekind wildcard (guardrail-override:*, stage-approval:*, destructive-action:*) → canonical stage id of the blocked task. An artifact with no route falls back to the people named in policy.json managers[] (matched by role, name, or email); if nobody matches, the block is logged as “no email recipients resolved”. A route whose roles don’t exist in recipients is flagged at config-validation time — “this route resolves to nobody” — so a typo can’t silently mute approvals. The channel activates only when both the environment connection string and channels.email.sender are present (rstack-agents doctor reports exactly which half is missing). Each resolved person gets their own email (To only — recipient lists never leak) naming the run, task, blocked artifact, and why, plus a deep link to the Business Hub approvals page (http://localhost:3008/?page=approvals; port follows RSTACK_BUSINESS_PORT).
Why a deep link instead of Approve/Reject buttons in the email: Outlook HTML approval buttons do not reliably return the approver’s identity — only the selected option — so an email-button approval could not carry the actor evidence RStack’s audit trail requires. Microsoft’s supported identity-capturing path (Logic Apps / Power Automate Approvals) lives inside M365, outside RStack’s audited approval records. v1 therefore links you to the Business Hub approval card, where the existing token-verified path records who approved. Signed one-time approval links are a v2 candidate.