Control Plane (Portal)¶
An optional client that pulls published policy from a central control plane and forwards audit records to it.
Off by default. Local and single-team use never needs it: the runtime is a local binary governed by local files, and nothing on this page is required to run anything.
The control plane server is not publicly available yet
The runtime ships the client — the portal: config block, the
runtime portal commands, and the uplink behaviour described here. The
server it talks to is a separate component that has not been released.
This page exists because the config block, the environment variables and
the runtime portal verb are all visible in a stock install, and you
should know what they are and that leaving them off costs you nothing.
What it does, and what it deliberately does not¶
When enabled, exactly three things cross the network:
| Direction | Call | When |
|---|---|---|
| Runtime → portal | POST /api/v1/audit |
After every local audit write, best-effort |
| Runtime ← portal | GET /api/v1/policies?active=true |
On runtime portal sync only — never implicitly |
| Runtime → portal | POST /api/v1/fleet/heartbeat |
Once per process |
What it is not matters more than what it is. Each of these preserves a property the runtime already had:
| Not this | Because |
|---|---|
| Not a replacement for the audit log | logs/audit.log is written first, and its failure is fatal. The uplink is best-effort and its failure is discarded — enabling a portal cannot make a successful operation report as failed, and cannot lose your local trace |
| Not remote policy evaluation | portal sync writes a local file and stops. Every decision is still made locally against that file, so a portal outage cannot change, widen, or block what a command may do |
| Not a second execution path | No operation runs through the portal and no capability can address it. The only verbs are portal status and portal sync |
| Not automatic | Policy is pulled only when you run portal sync. Bootstrap does not sync, and neither does any other command |
Configuration¶
| Key | Type | Default | Meaning |
|---|---|---|---|
portal.enabled |
bool | false |
Whether the client runs at all. When false, no control-plane request is ever made |
portal.base_url |
string | "" |
Control-plane origin, no trailing slash. Empty disables the client even when enabled: true |
portal.timeout_seconds |
int | 5 |
Bounds every portal call. Also the worst case an unreachable portal can add to a command — see Failure behaviour |
Or without editing the file:
export RUNTIME_PORTAL_ENABLED=true
export RUNTIME_PORTAL_BASE_URL=http://localhost:8080
export RUNTIME_PORTAL_TIMEOUT_SECONDS=5
These three are the whole portal environment surface — see Environment Variables. Policy content always arrives over the API and is written to the policy file; there is no environment variable that injects a rule.
runtime portal status¶
A health check, like runtime auth status: no network request, no audit
record. It answers "is this runtime pointed at a control plane, and which
published policy is it running?"
Portal: disabled (Community / local mode)
Enable in config.yaml:
portal:
enabled: true
base_url: http://localhost:8080
Or:
export RUNTIME_PORTAL_ENABLED=true
export RUNTIME_PORTAL_BASE_URL=http://localhost:8080
Once enabled and synced:
Portal: enabled
base_url: http://localhost:8080
runtime: engineering-runtime
timeout: 5s
policy: v42
{
"base_url": "http://localhost:8080",
"configured": true,
"enabled": true,
"policy_version": "v42",
"runtime": "engineering-runtime",
"timeout_seconds": 5
}
configured is enabled && base_url != "" — the single condition that decides
whether any request is attempted.
runtime portal sync¶
Fetches the published policy and writes it over your policy file, reporting the version applied and the path actually written.
Synced policy v42 → /Users/you/.engineering-runtime/policy-config.yaml
Local evaluation uses this file; a portal outage won't block commands.
The path is the real destination, so it follows
RUNTIME_POLICY_FILE when a
pipeline has relocated policy:
Sync replaces your policy file — it does not merge
The published policy overwrites policy-config.yaml wholesale. Local
rules are not merged in, no backup is taken, and turning the portal
off afterwards does not restore the old file. Back it up first:
The sync is audited¶
Unlike portal status, portal sync writes an audit record — on success and
on failure:
[2026-02-11T18:41:31+05:30] success consumer=human context= transport=- command=portal.sync 2ms applied portal policy v42 to /Users/you/.engineering-runtime/policy-config.yaml
This is deliberate. portal sync rewrites the rules every later command is
judged against, from a network source — and it is the one thing allowed to
write policy-config.yaml, which
the File Engine otherwise refuses precisely
so an ordinary command cannot leave the next one ungoverned. The operation that
changes what governance means is not allowed to be the one operation with no
trace.
Failure behaviour¶
A portal problem never fails your command. The operation runs, the local audit record is written, and only the uplink is lost.
The cost of an unreachable portal is bounded twice over:
| Bound | Effect |
|---|---|
timeout_seconds (default 5) |
No single portal call can hang longer than this |
| Per-process circuit breaker | The first transport failure disables the uplink for the rest of that command |
So a configured-but-down portal costs at most one timeout per command, not one per operation — a 20-step capability stalls once, not twenty times. Lower it further if that still matters in CI:
The circuit breaker applies only to the automatic uplink. portal status and
portal sync always try and report the real error, because you asked for them
explicitly.
There is no durable retry: records lost to an outage stay in your local audit log and are not resent later.
Security¶
There is no portal authentication yet
The client sends no API key and does not verify the server's identity.
Anything answering base_url can replace your entire local policy on the
next runtime portal sync.
Treat base_url as security-relevant configuration: point it only at a
control plane you trust, prefer https outside local testing, and be
aware that anyone able to set RUNTIME_PORTAL_BASE_URL in your
environment can redirect where policy comes from.
Audit records leave your machine when the portal is enabled. They carry the command, the runtime context, the executor, status and result message — the same fields as your local log. Credentials are never included; the runtime does not store them and never logs full tokens.
Verifying where your policy came from¶
A synced policy file looks identical on disk to one you edited yourself, so
runtime config validate names the source:
Config: /Users/you/.engineering-runtime/config.yaml
Policy: /Users/you/.engineering-runtime/policy-config.yaml
Context: /Users/you/.engineering-runtime/context.yaml (active: default)
Capabilities: /Users/you/.engineering-runtime/capabilities
Portal: http://localhost:8080 (policy: v42)
With the portal off:
That line is read from configuration and the portal-policy-version marker in
the Runtime Home — config validate makes no
network call.
Turning it off¶
unset RUNTIME_PORTAL_ENABLED RUNTIME_PORTAL_BASE_URL RUNTIME_PORTAL_TIMEOUT_SECONDS
runtime portal status
Or in config.yaml:
Local audit continues exactly as before and nothing is sent anywhere.
Turning the portal off does not revert a synced policy
The file on disk stays whatever the last sync wrote. Restore your backup if you want the previous rules back.