Skip to main content
Artifacts, kinds and relations | AEPWhat an artifact is, the kinds AEP knows and the ones you add, the relation vocabulary, blockers, and which fields are yours to edit.AEPexplanationaepexplanationadopterdevelopertry-spec-driven-developmentunderstand-safe-agentic-codingreference

Artifacts, kinds and relations

An artifact is one item of the plan: a vision, an epic, a story, a task, a design, a review, a blocker. It is one Markdown file with YAML front matter, and its id says where the file lives:

story:pay-by-card → .engineering/planning/story/pay-by-card.md

Kinds​

The kind is the part of the id before the colon. aep plan artifact kinds lists what can be created in this project:

$ aep plan artifact kinds
vision planning
product-requirements planning
initiative planning
epic planning
story planning
task planning
specification output
…
review-result output
…
executable-system-specification output
blocker planning (this store's lifecycles declare it)
obligation output (this store's lifecycles declare it)
outbound-claim output (this store's lifecycles declare it)
<type>-blocker planning (open family: credential-blocker, decision-blocker, …)

Planning kinds describe work to be done. Output kinds are what work produces. The list merges three sources: the kinds compiled into AEP, every kind your document tree declares a lifecycle for, and the open <type>-blocker family.

A kind is open to authors but not to typos. Any kebab-case name is a valid kind, and a kind with no lifecycle of its own takes the lifecycle of the kind it specialises. The parent is named by the last hyphen segment, so weekly-digest is a digest. A status is not open in the same way. Only the statuses the kind's lifecycle declares are accepted, and validate reports any other.

Some kinds have aliases: new adr … creates an architecture-decision-record.

Relations​

Edges between artifacts come from a fixed vocabulary. aep plan artifact relations prints it:

$ aep plan artifact relations
informed_by Shaped by, without being derived from — read and taken into account.
derived_from Produced from a higher-level artifact, whose intent it carries down.
decomposes Breaks a larger artifact into smaller work.
specifies States the required behaviour of something.
designs Proposes how to satisfy something.
implements Realises something in the system.
decides Records a decision taken within something.
reviews Assesses something.
verifies Establishes that something holds.
blocks Prevents progress on something.
depends_on Needs something else first.
supersedes Replaces something, which becomes superseded.
delivers Produces the outcome something asked for.
serves Moves an objective the collection has set — a `vision` artifact — and says which.

An edge is written on the artifact it starts at. You can add one at creation (new … --relate decomposes:epic:guest-checkout), later (relate story:x depends_on story:y), and take it back (unrelate). relate refuses an edge whose target the plan does not hold, and validate reports a dangling edge, a cycle and a duplicate id.

Four relations are read by other commands:

RelationRead byEffect
blockslist, board, blockedthe target is marked blocked: <type> until the blocker reaches the end of its own lifecycle
depends_onwavesa story is never placed in the same wave as something it depends on, or in an earlier one
reviewsfindings, review-value, evidence --kind review_outcomejoins a review-result to the artifact it reviews
specifiesaep observe specification evidencefinds the approved specification that applies to a task's work

Blockers​

A blocker is an artifact of kind <type>-blocker: decision-blocker, credential-blocker, or a type of your own such as procurement-blocker. The type names what would clear it. Its lifecycle is open → cleared:

$ aep plan artifact new decision-blocker card-vault-provider \
--title "Which card vault do we use?" --relate blocks:story:save-card
created decision-blocker:card-vault-provider (open) at …/planning/decision-blocker/card-vault-provider.md
$ aep plan artifact blocked
decision-blocker:card-vault-provider decision open Which card vault do we use?
blocks story:save-card draft Save a card for next time
$ aep plan artifact list --kind story
story:guest-receipt story draft Email a receipt to a guest
story:pay-by-card story implemented Pay by card as a guest
story:refund-guest story draft Refund a guest order
story:save-card story draft Save a card for next time blocked: decision

To unblock the story, move the blocker to cleared. That is a move, not an edit, so the plan keeps the record that the story was ever stuck. --withholds <evidence-kind> on a blocker records which evidence it is stopping somebody from producing. explain shows that on the blocked artifact.

Who writes which field​

FieldWritten byNotes
format, id, kindthe CLI at newidentity, fixed for the artifact's life
status, transitionsmove onlya move appends one transition; set --status is refused by name
revisionevery CLI writeone more per write to the file
title, summary, owner, tags, refsnew, setor a hand edit
relationsnew --relate, relate, unrelateor a hand edit; validate checks the result
scopescopestories only; read by waves
withholdsnew --withholdson a blocker
model_digestset --model-digestexecutable system specifications only
bodynew --from, bodyor a hand edit, except on immutable kinds such as review-result

The full format, with an annotated example, is in the artifact file.

External references​

--ref <provider>:<key> records the same work in another system, such as jira:EX-1. list --ref jira:EX-1 finds it again. When project.yaml sets a URL pattern under providers: (jira: https://tracker.example/browse/{key}), show prints the link beside the reference.