Skip to main content
Safety gates are the core enforcement mechanism of Forge governance. Before any workflow step reaches a gateway, it passes through a sequential pipeline of pure gate functions. Each gate evaluates one specific aspect of the dispatch context and returns one of three outcomes: pass, block, or skip. The pipeline is fail-fast: the first gate that blocks terminates evaluation, and remaining gates are marked as skipped. This keeps evaluation fast while ensuring that the most critical checks (gateway health, agent status) run first.

🛡️ Gate Pipeline

DISPATCH GATE SEQUENCE

Infrastructure / TrustResourcePolicy
1. Gateway Health. Infrastructure

Is the target gateway online? Blocks if offline. Warns if degraded.

2. Agent Status. Lifecycle

Is the agent dispatchable? Blocks if paused, terminated, or in error.

3. Concurrency. Resource Limit

Within concurrent step limit? Skipped for delegated runs.

4. Rate Limit. Throughput

Exceeded dispatch rate limit? Sliding window check.

5. Agent Budget. Cost Control

Monthly budget exhausted? Role-derived or agent-level ceiling.

6. Envelope Budgets. Cost Control

All budget envelopes within limits? Global, gateway, agent scopes.

7. Trust Level. Access Control

Agent trust meets gateway minimum? Default trust level 1.

8. Context Trust. Provenance

Source class, freshness, and environment eligibility checks.

9. Policy Rules. Declarative

Evaluate conditions against agent, gateway, run, and role fields.

10. Approval Required. Human-in-the-Loop

Approval needed by policy? Check for existing approval grant.

Pass all 10 gates = Allow | Any gate blocks = Block | Gate 10 hold = Hold for approval

🔍 Gate Details

1. Gateway Health

Verifies that the target gateway is operational before attempting dispatch.
OutcomeCondition
PassGateway status is healthy or degraded
BlockGateway status is offline
SkipNever skipped — always evaluated first
  • Error Code: gateway_unreachable
  • Retryable: No. An offline gateway requires infrastructure intervention.
  • Degraded Behavior: A degraded gateway logs a warning but allows dispatch. This lets operations continue during partial outages while maintaining visibility.
If the gateway document is not found in the registry at all, the pipeline returns an immediate block with gateway_unreachable before evaluating any other gates.

2. Agent Status

Checks the agent’s lifecycle status to ensure it is in a dispatchable state.
OutcomeCondition
PassAgent status is idle, running, or any status other than paused/terminated/error
BlockAgent status is paused, terminated, or error
SkipAgent document not found (all remaining gates are also skipped)
  • Error Code: agent_unavailable
  • Retryable: Only when the agent is paused — a human can unpause it. Terminated and error states require manual intervention.

3. Concurrency

Enforces the maximum number of concurrent steps an agent can execute simultaneously.
OutcomeCondition
PassRunning step count below max concurrent limit
BlockRunning step count at or above max concurrent limit
SkipDispatch type is delegated_run (delegated runs manage sub-step concurrency independently)
  • Error Code: agent_busy
  • Retryable: Yes. Running steps will eventually complete, freeing capacity.
  • Limit Resolution: The effective limit comes from the agent’s resolved authority bounds (role-derived), falling back to maxConcurrentSteps on the agent definition, defaulting to 1.

4. Rate Limit

Enforces per-agent dispatch rate limits using a sliding window mechanism.
OutcomeCondition
PassAgent is within its rate limit window
BlockAgent has exceeded the allowed dispatch rate
  • Error Code: RATE_LIMITED or rate_limit_exceeded
  • Retryable: Yes. Rate limit windows are time-based and will naturally reset.
  • Pre-check: A token-based rate limit pre-check runs before the full pipeline. If the agent’s LLM rate limit window is exceeded, the pipeline short-circuits immediately.

5. Agent Budget

Checks whether the agent has exhausted its monthly spend ceiling.
OutcomeCondition
PassAgent’s spent cents below budget limit, or no budget is configured
BlockAgent’s spent cents at or above budget limit
  • Error Code: budget_exceeded or budget_insufficient
  • Retryable: No. Budget limits require an operator to increase the ceiling or wait for period reset.
  • Delegated Run Behavior: For delegated runs with maxCostCents guardrails, the gate also checks whether the agent’s remaining budget can cover the run ceiling. This prevents launching runs that would inevitably exceed the budget mid-execution.

6. Envelope Budgets

Checks all applicable budget envelopes from the budgets table. Multiple envelopes may apply to a single dispatch (global + gateway-scoped + agent-scoped), and the tightest constraint wins.
OutcomeCondition
PassAll applicable envelopes have remaining budget
BlockAny single envelope is exhausted
  • Error Code: budget_exceeded
  • Retryable: No.
  • Message Format: Includes the scope, period, and spend ratio (e.g., agent:agent-123 daily budget exhausted (500/500 cents)).

7. Trust Level

Verifies that the agent’s trust level meets the minimum required by the target gateway.
OutcomeCondition
PassAgent trust level at or above gateway minimum, or gateway has no minimum set
BlockAgent trust level below gateway minimum
  • Error Code: trust_level_insufficient
  • Retryable: No. Trust levels are configured by operators.
  • Defaults: Agents default to trust level 1 (most restrictive) when no trust level is explicitly set. Gateways with no minTrustLevel allow all agents.

8. Context Trust

Validates that the dispatch context provenance meets the requirements defined by the agent’s assigned role.
OutcomeCondition
PassNo role trust config, or context meets all requirements
BlockSource class not accepted, context is stale, or environment not eligible
SkipNo role assigned to the agent (permissive default)
This gate enforces three distinct checks:
The role defines which context source classes it accepts (e.g., internal_verified). If the dispatch context’s source class is not in the accepted list, the gate blocks.
  • Error Code: context_source_rejected
  • Retryable: No.
When a role requires fresh context (requireFreshness: true), the gate checks:
  • Context freshness must not be stale or unknown
  • If collectedAt is available, the context age must be within the role’s maxFreshnessMinutes (default: 30 minutes)
  • Error Code: context_freshness_blocked
  • Retryable: Yes. Context can be refreshed.
When a role specifies allowed environments and the gateway has an environment set, the gateway’s environment must be in the role’s allowed list.
  • Error Code: environment_not_eligible
  • Retryable: No.

9. Policy Rules

Evaluates all enabled declarative policies scoped to the target gateway. Policies are evaluated by category (trust_boundary, budget, run_creation) and matched against the dispatch context.
OutcomeCondition
PassNo matching policies, or matched policies are warn/log only
BlockA policy with action: block and enforcement: hard matches
  • Error Code: policy_blocked
  • Retryable: No. Policy conditions are deterministic.
  • See Policies for full details on the policy engine.

10. Approval Required

Determines whether human approval is required and whether one has already been granted.
OutcomeCondition
PassNo approval required, or an existing approval has been granted
HoldApproval required by policy but no approval exists yet
  • Error Code: approval_required
  • Retryable: No. Requires human action.
  • Disposition: This gate produces a hold disposition (not block), which pauses execution and creates an approval request. See Approvals for the full approval lifecycle.

🔄 Dispatch-Level Retries

When a gate returns a retryable block (concurrency or rate limit), the dispatch layer retries the full governance evaluation up to 3 times with exponential backoff:
AttemptDelay
11 second
22 seconds
34 seconds
If all 3 attempts are blocked, the step is marked as failed with the final gate’s error code.
Non-retryable blocks (budget exhausted, trust insufficient, policy blocked) fail immediately without retry. Only transient conditions like concurrency limits and rate limits are retried.

🎯 Action Type Variations

The governance engine supports three action types, each with slightly different gate behavior:
The standard path for individual workflow steps. Runs the full 10-gate sequence.
  • Concurrency gate is active — enforces per-agent step limits
  • Agent budget checks monthly ceiling against spentMonthlyCents
  • All policy categories are evaluated

🔒 Edge Agent Governance

Convex-native agents (Factory Manager, Task Manager, Copilot) that run inside Convex rather than through an external gateway use a variant of the governance pipeline:
  • When no real gateway is provided, a synthetic healthy gateway is used so the gateway health gate passes trivially
  • Gateway-scoped policies are skipped (no real gateway to scope against)
  • Budget, concurrency, agent lifecycle, role trust, and context provenance gates run unchanged
  • Rate limit pre-checks still apply
This ensures that Convex-native agents receive the same budget, concurrency, and trust enforcement as gateway-dispatched agents, while avoiding false blocks from gateway-specific checks.

🏗️ Gate Architecture

All gate functions in convex/lib/gates.ts are pure functions — they take pre-fetched context and return a result with no side effects or database access. This design provides:
  • Testability: Every gate can be unit tested with synthetic inputs
  • Composability: Gates can be combined into different sequences for different action types
  • Performance: No database queries during gate evaluation (all data is pre-fetched)
Async operations (concurrency counts, rate limit checks, policy evaluation) are handled through hooks — callback functions injected by the caller that bind database context into closures. The engine calls hooks at the right point in the sequence without needing direct database access.
In Burgundy: Gate failures appear in the run detail timeline with error codes, retry status, and unblock hints.