Skip to content

governance://

Producer-only gate that consults a registered governance.Stack (kill switches → rings → policy → audit) and either lets the exchange continue or marks it failed with ErrGovernanceBlocked. Drop one into a route's steps to gate a non-agent tool call, an HTTP API path, or a Kafka write — anywhere you'd consult kill switches / rings / policy.

Use governance:// when you want policy enforcement at any seam in a workflow, not just on agent:// calls.

Producer-only — CreateConsumer returns ErrConsumerNotSupported (governance is a gate, not an event source).

URI shape

governance://<stack-name>?action=...&agent=...&tenant=...

The <stack-name> must be registered with the component via RegisterStack(name, *governance.Stack) before any route reaches the endpoint; an unregistered name fails the producer call (deny-by-default at the boundary).

Parameters

Param Type Default Producer/Consumer/Both Description
(path) stack-name string required Producer Stack registration key.
action string exchange FromURI() Producer Action / tool name to evaluate.
agent string exchange WorkflowID() Producer Agent ID for the decision.
tenant string X-Tenant-ID header Producer Tenant ID exposed to Starlang predicates as ctx["tenant"].
agentHeader string helix.governance.agent Producer Per-exchange override header for agent. Header wins over URI param.
actionHeader string helix.governance.action Producer Per-exchange override header for action. Header wins over URI param.

Headers

Read by the producer

Header Description
<agentHeader> Per-exchange agent override (default header: helix.governance.agent).
<actionHeader> Per-exchange action override (default header: helix.governance.action).
X-Tenant-ID Tenant fallback when the tenant URI param is unset.

Set via ex.SetProperty(...)

Property Description
helix.governance.decision allow on pass; one of deny, review, etc. on block.
helix.governance.blocked_by When blocked: which rule/policy fired.

On block, ex.SetException(...) is called with a wrapped ErrGovernanceBlocked so the standard error-handler path handles the response. Process always returns nil — the deny semantics are exchange-level, not router-level, which keeps the gate cheap.

Examples

Gate a database write:

workflows:
  - id: customer-update
    trigger: { uri: http-server://0.0.0.0:8080/update }
    steps:
      - target: governance://prod?action=db.write&agent=customer-update
      - target: postgres://customers?command=UPDATE&dsn=${DSN}

Gate an outbound HTTP call by tenant:

- set-header:
    name: helix.governance.action
    starlang: 'header("X-Endpoint")'
- target: governance://prod?tenant={{ headers["X-Tenant"] }}
- target: http://payments-api/charge

Wire up the stack programmatically:

import (
  govcomp "github.com/arvenza/helix/pkg/component/governance"
  "github.com/arvenza/helix/pkg/governance"
)

stack := governance.NewStack(...).
  WithKillSwitch(redisKillSwitch).
  WithRing(productionRing).
  WithPolicy(billingPolicy)

govComp := govcomp.New()
govComp.RegisterStack("prod", stack)

Behavior notes

  • Deny by default at the boundary — governance://unknown fails immediately with ErrGovernanceBlocked (no stack registered). This is deliberate: forgetting to register a stack should block traffic, not silently pass it.
  • Error vs exception — Process returns nil even when blocked; the block is recorded on the exchange via SetException(...) and helix.governance.decision = "deny". The route's standard error-handling path picks it up. Returning a hard error here would short-circuit at engine level (heavier).
  • Hot-swap policy — RegisterStack(name, ...) overwrites a prior binding. Existing endpoints transparently pick up the new stack on the next call.
  • No goroutines or external connections — lifecycle is owned by the governance.Stack. Start / Stop on this component are no-ops.

Source

pkg/component/governance/governance.go, pkg/governance/...

See also

  • agent — agents have built-in pause / kill-switch / budget controls; governance:// adds policy at non-agent seams.
  • tool — combine with governance:// to gate specific tool calls.
  • Governance package: pkg/governance/ for Stack, Ring, Policy, kill-switch implementations.