Sync
Sync is the one-way signed channel from the TapPass control plane to every governed agent.
It delivers Compiled Policy updates within seconds. It is unidirectional by design — there is no upward channel from agent to control plane that could be used for escalation.
Per governed-agents.md §12. Sync is what makes "live policy" usable at scale: the operator changes a Rego rule, every governed agent's enforcement updates within seconds, and any drift gets detected and re-pushed.
At a glance
Section titled “At a glance”| Direction | Control plane → data plane (one-way) |
| Modes | Push (SSE) · Pull (HTTP fetch) · Reconcile (background loop) |
| Carries | Signed, monotonic Compiled Policy payloads |
| Triggered by | Operator policy change · agent boot · agent reconnect · periodic heartbeat · drift detection |
| Latency | < 5 seconds for a typical enterprise footprint (push path) |
| Failure mode | Fail-closed — capability tokens expire within 5 min if Sync stops working |
The three modes
Section titled “The three modes”| Mode | Direction | Use case |
|---|---|---|
| Push | Control plane → data plane (SSE bus) | Compiled Policy version bumps; broadcast to all connected agents; expect ACK within seconds. The primary path for live updates. |
| Pull | Data plane → control plane (HTTP fetch) | Agent boots and fetches its assigned Compiled Policy. Agent reconnects after offline and catches up. Periodic heartbeat verifies version match. Resilience and bootstrap. |
| Reconcile | Control plane internal (background loop) | Compares desired Compiled Policy version per agent against last-ACK'd version. Re-pushes where ACKs are missing. Marks drifted agents. Surfaces stale or disconnected agents. |
All three run continuously. Push is the fast path; Pull is the resilient path; Reconcile is the integrity check.
The sync flow
Section titled “The sync flow”[Operator changes Policy at any cascade level] │ ▼[TapPass cascade-merges + re-compiles every stale Compiled Policy] │ ├──▶ updates Compiled Policy rows server-side ├──▶ revokes old gateway_token / mcp_session_token if scope narrowed └──▶ pushes signed payload over sync_url │ ▼ [tappass-host validates signature + monotonic policy_version, atomic-renames `keyring.json` file, applies provider changes] │ ▼ [Agent observes via inotify; tappass-agent rebinds clients] │ ▼ [Host ACKs new policy_version → control plane] │ ▼ [Reconciler clears the stale flag]Signed, monotonic, replay-resistant payload
Section titled “Signed, monotonic, replay-resistant payload”{ "sandbox_id": "sbx_a1b2c3", "policy_version": 17, "issued_at": "2026-05-08T10:00:00Z", "expires_at": "2026-05-08T10:05:00Z", "compiled_policy": { network: {…}, filesystem: {…}, tools: {…}, interpreter: {…}, budget: {…}, compliance_tags: […] }, "signature": "ed25519:<TapPass key>:<sig>"}The host validates:
- Signature — Ed25519 against the publicly-pinned TapPass signing key
- Monotonic version —
policy_versionmust be strictly greater than the currently-applied version - Sandbox match —
sandbox_idmust match this host's enrollment - Freshness —
expires_atnot in the past
If any check fails, the payload is rejected and the host stays on its current Compiled Policy.
Per-target update semantics
Section titled “Per-target update semantics”Every Provider has its own update model. The host runtime supervisor encapsulates these:
| Provider | Update model |
|---|---|
| OpenShell network | Hot-reload via L7 proxy reconfiguration (no restart) |
| OpenShell FS / exec | Restart container with new profile; supervisor handles state |
| nono | Restart-only — supervisor uses --supervised mode (parent stays unsandboxed; child restarts under new flags) |
Claude Code settings.json | File rewrite; harness reloads on next prompt |
| Monty manifest | Re-imported on next interpreter boot |
| K8s NetworkPolicy | kube-apiserver picks up live; no pod restart needed |
| LLM Gateway capability tokens | Token rotation in-place; old tokens revoked at expiry |
| MCP Broker capability tokens | Same as gateway |
The user-visible promise — "policy updates apply within seconds" — holds across all of them. The supervisor library makes the per-target nuance invisible.
Fail-closed token TTLs
Section titled “Fail-closed token TTLs”| Token | TTL | Renewed by |
|---|---|---|
gateway_token | 5 min | sync push |
mcp_session_token | 5 min | sync push |
| Host mTLS cert | 1 hour | tappass-host re-auth |
| Bootstrap URL | 15 min, single-use | (burned on consumption) |
If sync stops working, every capability token expires within minutes and the agent stops being able to act. Fail closed.
Drift detection
Section titled “Drift detection”The pre-deployment evaluation establishes a baseline (what the agent should do under this Policy); the runtime emits behavioral metrics; the dashboard learns the baseline and alerts on drift.
| Drift signal | What it catches |
|---|---|
| Tool-call distribution shift | Agent calls delete_* 10× more than baseline |
| Argument-shape drift | Args that don't match pre-deployment patterns |
| Session-length anomalies | Sessions running far longer than typical |
| Detection-rate spikes | detect_pii or detect_secrets firing more — possibly a prompt-injection campaign |
| Unenrolled-tool discovery rate | Surge in discovered rows = agent reaching for tools it hasn't before |
| Cross-sandbox correlation | Same drift signal across multiple sandboxes = upstream change (LLM provider behavior shift, new prompt template) |
Drift signals raise dashboard alerts with: which baseline metric, current vs. expected, audit replay link, recommended action (re-evaluate? tighten policy? approve as new normal?).
Why Sync is unidirectional
Section titled “Why Sync is unidirectional”This is a hard architectural property, not a soft preference. Without it, the same channel that delivers Policy updates would be a vector for the agent to influence its own Compiled Policy.
Enforced by:
- Package design:
tappass-agentexposes no client classes for admin endpoints. - Transport: kernel-ring egress allowlist blocks anything not in the Compiled Policy's URL set.
- Authentication: the agent's tokens have no admin scope.
A first-class attacker who owns the agent process cannot: modify the Compiled Policy, forge a sync payload, reach admin endpoints, replay older Compiled Policy versions, read other sandboxes.
Engines that operate on Sync
Section titled “Engines that operate on Sync”| Engine | What it does | Status |
|---|---|---|
| Push channel | SSE broadcast on Compiled Policy change | concept (Q3 2026 — critical-path M) |
| Pull endpoint | HTTP fetch; heartbeat | concept (Q3 2026, parallel) |
| Reconciler | Background loop closing on the agent registry | concept (Q3 2026) |
| Token rotation | Issues new capability tokens on Policy change | concept (extends shipped gateway) |
| Drift monitor | Behavioral baseline + alerts | concept (Q4 2026) |
Surfaces
Section titled “Surfaces”| Persona | Surface | What you see |
|---|---|---|
| Operator | Dashboard sandbox list | Per-sandbox: desired vs. applied Compiled Policy version; last ACK time; drift state |
| Operator | tappass sync status | Same data via CLI |
| Operator | Drift alerts | Dashboard notification + optional email/Slack |
| Host owner | tappass-host status | Local sandbox status: applied version, last sync, mTLS cert health |
| Agent | (none — read-only) | Inotify on keyring.json triggers client rebind |
Related concepts
Section titled “Related concepts”- delivers → Compiled Policy (the artifact pushed/pulled)
- between → control plane (server) ↔ data plane (host) — never the other way
- authenticated by → Identity (host mTLS; agent capability tokens)
- detects drift against → Probe baselines + audit metrics
- applied by → host runtime supervisor invoking each Provider
Authoritative docs
Section titled “Authoritative docs”| Topic | File |
|---|---|
| Vision | governed-agents.md §12 — sync flow + drift |
| Privsep model | governed-agents.md §13 |
| Component (push) | live-policy-push-channel |
| Component (drift) | behavior-drift-monitor |
Common confusions
Section titled “Common confusions”- Sync ≠ HTTP polling. Sync is signed and monotonic. A polling agent that fetches "the latest config" without signature checks would be a forgery vector. Every payload TapPass delivers is Ed25519-signed against a publicly-pinned key.
- Sync ≠ sync (the bash command). This is the architectural channel between control plane and data plane, not a filesystem operation.
- Push and pull are not mutually exclusive. They cover different conditions. Push is fast; pull is resilient. Both are first-class.
- Sync is one-way. There is no "agent requests more scope" path. That's the architectural property that makes live policy usable.