The accountability model
Autonomous agents are only usable in serious settings if you can answer two questions after the fact: what did the agent do, and can you trust that record. Apollia's accountability model exists to answer both, and to keep a human in control while the agent runs. This page explains how the pieces fit together and what they are, and are not, meant to provide.
The problem
An agent that reasons and acts on its own is powerful and, without controls, opaque and irreversible. In regulated settings that is disqualifying. The answer is not to make the agent less autonomous but to wrap its autonomy in governance: bound what it can do, record everything it does in a way that cannot be quietly altered, and keep a person in the loop on consequential actions. Those controls are built into the runtime rather than left to each agent to implement, so an agent author cannot forget them and an operator cannot be surprised by their absence.
The building blocks
A signed, tamper-evident trail
Every governed action an agent takes is written to an append-only journal. The journal is a hash chain, and it is signed as it grows, so any later alteration breaks the chain and is detectable. Each entry is linked twice: to the previous entry of its own run, and to the previous entry of any run, so the journal is one continuous sequence across every run, not a set of independent per-run logs. This is what turns "the agent says it did X" into "here is the recorded, verifiable sequence of what happened." The trail captures tool calls and, in the run journal, the model's own completions, so the reasoning behind an action is inspectable, not just its effect.
Verification of that trail
A record is only as good as your ability to trust it. Verifying the journal checks its hash chains and signatures and tells you whether the sequence has been altered since it was written. Because entries are chained across all runs, verification detects not only a mutated entry but also a run whose tail was truncated or a whole run that was deleted: either leaves a gap the chain exposes. Accountability rests on a record you can independently confirm, not on trusting the process that produced it.
The honest scope matters. This is tamper-evidence, not tamper-proofing: it detects alteration after the fact, it does not prevent it. The guarantee holds as long as the signing key is uncompromised. A party who holds the key can recompute and re-sign a shorter, consistent chain, so the runtime also exposes the head of the chain as an anchor you can export and store off-machine. Comparing a run against an externally held anchor is what defends against truncation of the most recent activity even when the key itself is at risk.
For the commands behind these two, see Audit and verify a run.
Undoing what an agent wrote is deliberately absent. A reversible journal exists in the codebase, but nothing installs it on the tools that write files, so no install records anything to undo. Shipping the command anyway would have been worse than shipping nothing: an empty result is indistinguishable from a clean session, so an operator would read "nothing to revert" as a working safety net and delegate accordingly. Treat every filesystem change an agent makes as final, and grant it for writing only folders you are willing to lose.
Permissions and human oversight
Before a tool call of an agent runs, one decision answers it, wherever the call is made: a conversation, a task, a step of a plan, an item of a batch. The organisation policy and a deny rule refuse it, a tool that only reads runs, a guard keeps a rule from covering a shell command that chains or redirects, and anything sensitive that no standing consent covers raises an approval request that a person resolves with one of three answers: once, always for this agent, or refuse with an optional reason the agent reads. An "always" is granted to one agent for one family of actions, never to a tool name, a project or a session.
The decision itself is written down: the answer to a consent prompt, a refusal by the organisation policy and a refusal by a rule each become an entry of the signed journal, naming the agent, the tool and its family of action, never the argument of the call. The journal also keeps the call the decision let through, since the loop of the agent captures the tool call and its output.
Every decision waiting for a person is listed in one place and answered from
it. GET /api/v1/pending-decisions lists the tool consents of the
conversations and of the runs outside any conversation, the pauses of tasks,
the batch items stopped on an access and the questions asked of the user, and
POST /api/v1/pending-decisions/decide answers one, through the very call that
answers it where it was born. The desktop reads the same list, so a decision is
the same decision whether it is given there or over the API. In a
conversation, a consent left five minutes without an answer is refused.
One boundary worth stating plainly. The decision governs the tool calls of agents. It does not see inside the Python of a package: a package tool is decided when an agent calls it, and what its code then does runs with the rights of the runtime process. The agent trust model explains why installing a package is the act of trust, and what covers it.
Autonomy tiers
An autonomy tier moves four things and no others: the suggested step budget, the post-run verification pass, the system-prompt profile, and the plan gate. It moves no permission rule and no human checkpoint on a tool call, so a higher tier does not widen what an agent is allowed to touch. It widens how far a run goes before it stops to ask.
The plan gate is the conditional one. The tier decides it only when the run
carries no per-run override, and apollia-os run always sends one, so on that
path --plan decides and the tier does not. The tier of an agent is the one
its package recommends, then the override of the person
(apollia-os agent set <AGENT_ID> autonomy <tier>), then the global default,
and apollia-os run takes --autonomy for one run. apollia.toml has no
[autonomy] section the runtime reads, and the desktop offers no control that
changes the tier. Free chat does not vary it
either, every exchange running at the default tier.
Non-negotiable safeguards
The runtime enforces a step budget on every autonomous run: a ceiling on reasoning steps, on tool calls, and on wall-clock time. It is enforced by the runtime itself and cannot be bypassed by an agent, so a run cannot loop or spend without bound. This is the guarantee that autonomy has a hard edge.
Shell command screening
Shell commands are screened before execution: a syntax check rejects what will
not parse, and a pattern filter can refuse a command outright. That filter ships
with empty pattern lists, and nothing fills them: the constructor that takes
patterns has no production caller, and no apollia.toml section reaches it, so
the filter blocks no command in the shipped runtime. When a standing prefix
rule is consulted for a code executor, a stricter guard refuses any command
that chains, pipes, redirects or substitutes, so an authorisation granted for
one command cannot smuggle a second; outside a matching rule, every code
executor invocation requires its own approval.
This screens shell injection. Apollia ships no defence against prompt injection, and nothing here should be read as one.
Self-checking on the orchestrated path
On the orchestrated execution path, a completed run can be verified by a critic before its result is accepted, gated by the autonomy tier. The verdict is emitted as a runtime event and lands in the signed journal, so the check is part of the record. On a failing verdict the engine can re-plan and re-run within a bounded number of attempts, under the same shared budget, which is how an orchestrated agent corrects itself without escaping its ceiling.
One honest limit: this pass runs the LLM critic, and no shell check is run on behalf of an agent. The critic is active; a deterministic shell check is not part of the pass.
How it maps to the EU AI Act
The controls above line up with obligations the EU AI Act places on high-risk AI systems. Apollia provides the technical primitives that support these requirements. It does not make you compliant and it certifies nothing: compliance is a judgment made by your organisation and its auditors about your whole system and process, not a property a runtime can grant.
With that framing, the mapping is direct:
| Requirement (theme) | Apollia primitive |
|---|---|
| Article 10, data provenance and quality | the signed, hash-chained audit trail plus verification, which records and lets you confirm what data and actions a run touched |
| Article 14, human oversight | the governance decision on every tool call of an agent (organisation policy, rules, consent by family of action, human approval), the code-executor guard, and autonomy tiers, which keep a person in control of consequential actions. The Python of an installed package is outside this loop, see above |
| Article 16, documentation and traceability | the audit journal and run trace, which document what happened |
The value is that these are wired into the runtime and demonstrable today, not promised. What remains a human responsibility is deciding whether your use of them, in your context, meets the obligation. Apollia gives you the mechanism; the compliance judgment stays with you.
Why this is the point
Autonomy without accountability is a liability, and accountability bolted on after the fact is not credible. Apollia's position is that the governance is part of the runtime: bounded by budgets, recorded in a signed trail you can verify, and supervised by permissions and tiers. That is what makes delegating real work to an autonomous agent defensible.
Related
- Audit and verify a run for the hands-on workflow.
- Embed Apollia via federation (MCP + REST) for how these controls travel into a host integration.
- The CLI reference for the audit and permissions commands.