# Agentic AI Safeguards

> **Status:** Authoritative  
> **Reviewed:** 2026-06-12  
> **Applicable provisions:** EU AI Act Recitals 80, 97; Art. 50(2); Art. 14;  
> GDPR Art. 6, 32  
> **Scope:** All multi-agent, orchestrator/worker, and A2A features of CorvinOS

---

## Background — Why agentic AI gets its own document

The EU AI Act was primarily written for AI systems with a bounded, predictable
interaction model: a user asks, the AI responds. Agentic systems are different:
they chain models together, spawn worker processes autonomously, issue tool calls
to external APIs, and can produce side effects far beyond the chat window.

Recital 80 of the EU AI Act acknowledges this directly:

> "When an AI system is used as an agentic system, the deployer should take
> appropriate measures to ensure appropriate human oversight over the AI system."

Recital 97 addresses GPAI models used as agents:

> "The possibility for AI systems to operate as agentic systems calls for specific
> attention to the risks arising from the use of such systems."

This document maps every agentic feature in CorvinOS to the safeguards in place
and identifies where structural controls enforce the regulatory obligations.

---

## Agentic features in CorvinOS

| Feature | Layers | Description |
|---|---|---|
| Orchestrator / worker delegation | L22, L29 | `delegate_claude_code`, `delegate_hermes`, `delegate_opencode`, `delegate_codex`, `delegate_copilot` — ClaudeCode spawns workers for subtasks |
| Multi-model routing | L5, L22 | `auto_routing` selects a persona/model based on user message; `orchestrator-haiku` persona switches engine dynamically |
| Forge MCP tools | L6 | Runtime tool generation; tools call external APIs, read/write filesystem, run Python |
| SkillForge auto-promotion | L7 | Skills auto-promoted from `task` → `session` → `project` → `user` scope via grading |
| A2A RemoteTrigger | L38 | Agent-to-agent task envelopes between CorvinOS instances over HTTPS; bilateral HMAC authentication |
| CorvinFed social fabric | L39 | Federated actor network; actors can delegate to remote peers via A2A |
| Multi-turn task execution | L21 | `Proposals` queue (`/propose` + `/go`) — the LLM processes a stack of tasks in one session |

---

## Safeguard 1 — Human oversight preserved (Art. 14)

### Problem

An agentic system that operates autonomously with no mechanism for human
intervention violates Art. 14 of the EU AI Act, which requires deployers to
implement human oversight measures appropriate to the risk level.

### CorvinOS controls

**Consent gate (L16 Phase 4):** No processing occurs without explicit per-user
consent. This is the primary human-in-the-loop gate: without `/consent on` or
`/join`, the pipeline halts unconditionally. Agentic sub-tasks cannot self-grant
consent on behalf of the initiating user.

**Disclosure gate (L19):** Every new user receives the AI-nature disclosure card
before any interaction — including interactions initiated by an orchestrated agent.

**Output cap:** Worker engines are capped at 64 KB of output per spawn (L29.1).
The cap is structural — it cannot be overridden by a worker instruction.

**`/btw` mid-stream injection (L13):** Users can interrupt a running agentic
pipeline with a steering note at any point during execution. The note is injected
into the live stream context, allowing course corrections without abandoning the
session.

**Proposals gate (L21):** The `/propose` + `/go` mechanism requires human
initiation for every multi-task batch. The LLM does not autonomously queue or
execute proposals; the user triggers `/go` explicitly.

**`human_oversight.override` audit event:** Any operator-level disable of an
oversight control emits a CRITICAL audit event to the hash chain. This makes
bypasses visible and non-repudiable.

---

## Safeguard 2 — Agent identity transparency (Art. 50(2))

### Problem

Art. 50(2) requires that AI systems that are capable of generating content do not
create confusion about the AI-nature of that content. In an orchestrated pipeline,
content generated by a worker agent must be attributable to an AI system, not to
a human.

### CorvinOS controls

**Provenance block on every final message:** The `_envelope()` wrapper in
`adapter.py` injects `{"ai_generated": True, "persona": ..., "generator_id": "corvin_os"}`
into every final message. This applies to orchestrator and worker outputs alike:
only the orchestrator's final response reaches the user, and it always carries
the provenance block.

**Worker output is not delivered directly:** Worker engine output is consumed
by the orchestrator, not delivered directly to the user chat. The user sees
the orchestrated result. The orchestrator's final response carries provenance.
There is no code path where raw worker output reaches the user without
passing through the `_envelope()` wrapper.

**A2A response attribution:** `ResponseEnvelope` (L38) carries the receiver's
`instance_id` and is HMAC-signed. Any downstream system can verify that the
response came from a specific CorvinOS instance, not a human operator.

---

## Safeguard 3 — Prompt injection defense (L29.1, L38)

### Problem

Agentic systems that pass content between models are vulnerable to prompt
injection: a malicious payload in one step's input can hijack the next step's
behavior. This is the primary security risk specific to agentic architectures.

### CorvinOS controls

**L38 A2A framing block:** Every inbound A2A instruction is sanitized (NFKC
normalize, 16 KB cap, control-char strip, literal `</a2a_instruction>` rejected,
empty rejected), then wrapped in a structured framing block:

```xml
<a2a_instruction origin="<escaped_origin>" task_id="<escaped_id>">
  ...sanitized instruction text...
</a2a_instruction>
```

The worker spawn includes a system prompt that declares this framing block as
the ONLY authoritative source. Instructions appearing outside the block are
treated as user content, not operator instructions.

**L29.1 output cap:** Worker output is capped at 64 KB. An injected payload
cannot return unbounded content to the orchestrator.

**L29.2 hermetic tempdir:** Each worker spawn gets a fresh, private tempdir
(mode 0700). Workers cannot access each other's state or prior-turn workspace.

**L16 NFKC normalization:** The linter in SkillForge applies NFKC normalization
to skill bodies, stripping Unicode look-alike attacks before injection into
downstream system prompts.

---

## Safeguard 4 — Scope isolation between agents (L29.2, L38)

### Problem

If worker agents can access the orchestrator's full context, state, or file
system, a compromised or misbehaving worker could exfiltrate data or modify
shared state in unintended ways.

### CorvinOS controls

**Hermetic tempdir (L29.2):** Each worker receives a private `tempdir` (mode
0700) at spawn time. The worker cannot read or write outside its tempdir
without an explicit `allow_write=true` grant in the spawn configuration.

**A2A scratch workspace (L38):** Inbound A2A tasks receive a private scratch
directory at `<scratch>/in/` (inputs, read-only after drop) and `<scratch>/out/`
(worker writes here). The receiver harvests only files matching
`result_schema.attachments_out_allowed`. The scratch directory is cleaned up
on every exit path (including exceptions).

**Worker has no bridge state:** Workers spawned via L29 have no access to the
bridge daemon's in-memory state, session data, or multi-user chat history.
They receive only the task prompt and the explicit env vars in the `env_passthrough`
allowlist.

**Per-engine env allowlist (L29.2):** `env_passthrough=false` is the default.
A worker engine inherits only the env vars the orchestrator explicitly passes.
Secrets from the vault are injected via bwrap env at spawn time, not via
environment inheritance.

---

## Safeguard 5 — SkillForge auto-promotion governance (L7)

### Problem

Skills that auto-promote from `task` scope to `user` scope could gradually
accumulate increasingly powerful instructions that were never explicitly reviewed
by an operator.

### CorvinOS controls

**Promotion gates:** Promotion from `task` to `session` requires ≥1 positive
grade. `session` to `project` requires ≥3 grades with mean ≥0.5. `project` to
`user` requires `force=True` (explicit operator action only). Auto-promotion
terminates at `project` scope.

**Linter (fail-closed):** Every skill body passes through the linter before
creation and promotion. The linter rejects:
- Prompt-injection patterns (persona-boundary phrases, "ignore previous instructions")
- Embedded secret values or credential patterns
- Oversized bodies (hard limit)

Linter failure is fail-closed: the skill is not created and not promoted.

**Slot-mirror scope-gate:** The operator's `operator/skill-forge/skills/dyn/`
slot mirror only receives `project` and `user` scope skills. `task` and
`session` skills do not appear in the slot mirror and are not injected into
subsequent turns after session reset.

**Audit trail:** Every skill creation, grade, and promotion event lands in
the L16 audit chain with the skill name, scope, and acting uid_hash. A skill
that was promoted despite low grades would be visible in the audit chain.

---

## Safeguard 6 — A2A trust and attestation (L38)

### Problem

In a federated agent network, a compromised node could impersonate a trusted
peer and send malicious task envelopes. Instance pinning and membership
attestation close this gap.

### CorvinOS controls

**HMAC-SHA256 verification (L38):** Every TaskEnvelope and ResponseEnvelope is
signed with HMAC-SHA256. Verification is constant-time. Unknown origins receive
no response (pre-HMAC failures are unsigned rejections, not oracles).

**Instance pinning:** Cloud-side senders pin the expected receiver `instance_id`
per endpoint. A CorvinOS instance that was replaced (different binary at the same
URL) fails the pin check.

**Replay-proof nonces:** Nonces are keyed to the envelope TTL and rejected after
the TTL window (±300 seconds). A replayed envelope with a valid HMAC is rejected
if the nonce was already consumed.

**A2A Network Membership Attestation:** Protocol v6 adds
`network_attestation` to TaskEnvelope (HMAC-covered, backward-compatible).
The attestation uses a cryptographic trust anchor (RS256 signed manifest).
Nodes without a valid membership credential are rejected at the receiver gate.
`--offline-pair` bypasses this for isolated networks (must be explicitly invoked;
there is no auto-fallback).

**Audit-first invariant:** `A2A.envelope_received` is written to the L16 hash
chain before any response or spawn. If the chain write fails, the request is
blocked.

---

## Safeguard 7 — Data classification at agent boundaries (L34)

### Problem

A multi-agent pipeline that crosses data classification tiers (e.g., an orchestrator
holding INTERNAL data spawning a worker that will egress to a cloud API) could
violate data residency or GDPR data minimisation requirements.

### CorvinOS controls

**Pre-spawn gate (`_run_pre_dispatch_gates()`):** Every non-ClaudeCode engine
spawn runs L30.1b + L34 + L35 gates before the worker is launched. The gate
fails-closed: if the engine's locality doesn't permit the current data
classification tier, the spawn is blocked and `data_flow.blocked` is emitted
to the audit chain.

**L34 DEFAULT_ENGINE_COMPLIANCE matrix:**

| Engine | Locality | Network egress |
|---|---|---|
| `claude_code` | eu_cloud | allowed |
| `hermes` | local | none |
| `codex` | us_cloud | allowed |
| `opencode` | us_cloud | allowed |
| `copilot` | us_cloud | allowed |

CONFIDENTIAL data can only reach `hermes` (local, egress-none) by default.
Any widening of this matrix requires an ADR.

**GDPR data minimisation (Art. 5(1)(c)):** Workers receive only the task prompt
— not the user's full conversation history, not session artifacts, not user model
content. The orchestrator decides what to pass; the default is minimal.

---

## Summary table

| Agentic risk | EU AI Act provision | CorvinOS control | Layer |
|---|---|---|---|
| No human oversight in autonomous pipeline | Art. 14 | Consent gate, `/btw` injection, proposals gate, output cap | L16/L21/L29 |
| AI-nature not disclosed for agent output | Art. 50(2) | Provenance block on all final messages | L19 / adapter |
| Prompt injection via chained models | Recital 80, Art. 14 | A2A framing block, NFKC normalization, output cap | L38/L16/L29 |
| Worker cross-contamination | Recital 80 | Hermetic tempdir, A2A scratch workspace, no bridge state | L29/L38 |
| Skill auto-escalation without review | Art. 14 | Promotion gates, linter fail-closed, slot-mirror scope-gate | L7 |
| Compromised peer in A2A network | Art. 14, GDPR Art. 32 | HMAC sign+verify, instance pinning, replay nonces, membership attestation | L38 |
| Data residency violation at agent boundary | GDPR Art. 5(1)(c), Art. 14 | Pre-spawn L34/L35 gate, data classification matrix | L34/L35 |

---

## Open items and monitoring obligations

1. **Art. 5(1)(f) at agentic boundaries:** If CorvinOS is deployed in a workplace
   with voice input AND uses multi-agent routing that processes voice content
   through multiple LLMs, the operator must assess whether the pipeline constitutes
   emotion recognition. The current architecture does not perform emotion
   classification, but the operator carries this assessment obligation.

2. **GPAI provider visibility:** The orchestrator delegates to third-party GPAI
   models. CorvinOS cannot inspect the internal behavior of those models. This is
   mitigated by the output cap and faithfulness judge (L29.3a) but remains a
   residual risk documented in the technical file.

3. **Agentic incident reporting (Art. 73):** Any serious incident involving an
   agentic pipeline (unexpected data exfiltration, unauthorized external API calls,
   worker producing harmful content) must be reported via the L39 incident tracker
   within 15 days. The IncidentAutoDetector raises CRITICAL for `data_flow.blocked`
   and `path_gate.denied` events, which auto-open incident records.

Next review: when a new engine is added to the allowlist, or when A2A Protocol v7
is defined.
