Skip to main content
Governed tasks | AEPThe document types, how a task resolves into a plan, how capabilities compose, how a workflow advances on evidence, and what actually runs the steps.AEPexplanationaepexplanationadopterdevelopertry-spec-driven-developmentunderstand-safe-agentic-codinggovern-work

Governed tasks

The engine half of AEP turns engineering methodology into documents a program executes: which capabilities an agent has on a task, what it owes, and when the task is complete. This page explains the document types and the resolution and evaluation model. For syntax, see the document reference; for hands-on use, see Govern a task.

The document types​

DocumentDeclaresExample
Protocolthe vocabulary: which capabilities, evidence kinds, verifiers, phases and observable fact families existaep/1 (base), adp/1 (development), aop/1 (operations)
Principleone enforceable rule: when it applies, what it requires, by when, and who may attest ittest-driven, approval-gates
Workflowa state machine whose transitions are guarded by predicates over evidenceadp/default
Profilea bundle: protocol + workflow + principles + capability policy + completion conditiondevelopment.standard
Artifact lifecyclewhich statuses an artifact kind may hold and how they may changearchitecture-decision-record
Step mapwhich program, model or person runs in each workflow statedevelopment/default, development/checks
Taskthe unit of work: objective, kind, profile, declared context facts, artifact manifestAUTH-142
Artifact manifestwhere the specs, designs and reviews live — references, not copiesartifacts.yaml

Documents are YAML, validated against generated JSON Schemas, and indexed by the id declared inside the file — never by filename. A team's own principles and profiles live beside the vendored upstream ones in the same tree.

Resolution: a task becomes a plan​

resolve (or Engine::initialize in the API) takes a task and produces a plan:

  1. The task names a profile; the profile's extends chain is merged. Extension can only tighten: completion conditions are conjoined, and a denied capability cannot be granted back.
  2. Each principle's applies_when is evaluated against the task's facts. A rule that does not apply is absent, not vacuously satisfied — so every check in a report meant something.
  3. Capabilities compose across protocol, profile, principles and workflow state, with the document responsible recorded for every entry.
  4. Obligations are collected and timed against workflow phases.
  5. The whole configuration is refused if any rule in it could never fire — a predicate reading an undeclared fact, an obligation timed against a phase no state declares, a task needing a capability the resolved policy denies.

The task states only what cannot be derived: its objective, its kind, and facts nothing can observe (for example change.database_schema: true). Everything else is derived, so it cannot drift.

Capabilities: default deny, with an approval floor​

A capability no document mentions is not granted. Three decision levels exist, and precedence is fixed: deny beats require_approval beats allow. A deny cannot be granted back by a later document, so a denial works as a safety envelope rather than a starting suggestion.

Two rules shape who may say what:

  • A principle may only restrict (deny or require approval). Only a profile or a protocol may grant.
  • The protocol holds an approval floor: aep/1 refuses to resolve any profile that puts production.write, deployment.create:production or network.read:private in its allow list. The mistake cannot be made, rather than being caught in review. A broad grant counts as granting what it covers, so allow: [network.read] is refused on its own and accepted beside deny: [network.read:private] — which is how a profile says read the public channels, never a direct message.

Every action an agent might take maps to exactly one capability (repository.write, tests.execute, secret.read, …), so authorisation is a lookup, not a judgement. The full list is in the vocabulary reference.

Workflows: evidence moves the state​

A workflow is a validated state machine: an initial state, terminal states, and transitions guarded by predicates over recorded facts. Validation refuses unreachable states, non-terminal dead ends, duplicate transitions for one from/to pair, and rollback policies that cannot state their precondition.

The engine advances a workflow only when the guard evaluates True against submitted evidence, and a blocked transition names exactly what is missing. When more than one transition is legal, the first in document order is taken and the rest are reported — a choice is visible, never a coin flip.

States can carry phase labels (intake, implementation, verification, …). Principles time their obligations against phases (before_implementation:), which is what lets one principle work across different workflows.

Step maps: something has to actually run the steps​

A workflow says which states exist and what moves between them. It does not say who does the work. A step map does: for each state, a list of steps, each of one of three kinds.

KindWhat runs
commanda program — a test suite, a linter, a build
llma model, in a headless session
operatora person; the run stops and waits

Two ship, one per shape of work this repository has. drivers/development/default.yaml (development/default) verifies with cargo; drivers/development/checks.yaml (development/checks) names no compiler and runs the checks a story carries, as one command. Both are written against adp/default/2, so an aep drive run with no --map is refused, naming both rather than picking one.

aep drive run walks command/operator maps. Model-backed maps use metaharness aep drive run; aep drive run refuses them before allocating a run. Both hosts ask the same neutral governor and retain AEP run records. The driver evaluates no gate itself. That restraint is the design: a driver that could decide whether a transition is permitted would be a second implementation of the protocol with none of the conformance suites behind it, and the first time the two disagreed, the one nobody tested would win. So the driver asks, the engine answers, and a blocked run prints the engine's reasons and exits non-zero.

A driven run needs a shell to reach the planning store, which is why development.driven exists: it extends development.standard with exactly one capability, command.execute, and says in the document why. The narrowing back down is a PreToolUse hook that refuses any shell call that is not one simple aep plan artifact or aep observe trace invocation. The profile states plainly that this is pattern-based and best-effort rather than claiming the capability is fully enforced.

Everything is recorded, including refusals​

This section is about the engine and the storage contract its backends implement. The Git-native planning store is simpler: a refused command prints its reason and writes nothing, and a successful one changes one file.

Every mutation of an engineering entity goes through one boundary — a command carrying actor and executor, correlation and causation, an idempotency key and an asserted revision. A retry is recognised; a stale write is refused rather than merged. There is no delete: ArchiveEntity and SupersedeEntity are the vocabulary.

Refusals are first-class: a refused command changes nothing and still lands in the audit trail, and authorize records the request and the answer even when the answer is no. "An agent tried to change production and was stopped, by this rule" is only worth something written down beside the changes that succeeded.

Approvals bind to revisions​

An approval names the revision it approved. An approval of version 3 of a design stops satisfying a review requirement once the design reaches version 7 — otherwise a reviewer's name ends up attached to a decision they never saw. Review requirements can demand fresh: true (the review covers the artifact's current version) and human: true.

What evaluation returns​

evaluate answers three questions at once: what is permitted now, what is owed and by which document, and whether the task is complete. Every requirement line names the document that asked for it, and every predicate outcome is three-valued — see Evidence and completion for why Unknown and False must stay distinct.

A requirement can also declare a horizon, after which the evidence that satisfied it stops counting and the requirement reads Unknown again. That is the same page's subject: a fact has a date, and an old fact is not a wrong one.


Sources. docs/guide/adopting.md; docs/guide/harness.md; docs/plan/document-authoring-brief.md; drivers/development/default.yaml, drivers/development/checks.yaml and crates/drive/aep-driver-spec/src/map.rs (the three step kinds); profiles/development-driven.yaml; AGENTS.md § Invariants ("Capability decisions default to deny", "The gate is offline except by an opted-in name", "A guard is mutation-tested before it is trusted"); protocols/aep/1.yaml (approval_floor).