AKS Full Grammar Reference
This is the authoritative grammar specification for AKS (Architecture Knowledge Syntax).
Every ```aks example in this document is validated against the real parser by
crates/archkit-frontend/tests/docs_aks_conformance.rs — if it’s written here, it parses.
Grammar style: off-side rule (indentation-sensitive) with explicit end <keyword> block closers.
Parser: hand-written lexer + recursive-descent parser in crates/archkit-frontend/src/aks/.
1. High-Level Structure
Every AKS file contains exactly one workspace block. The workspace name must be a quoted string. Nine kinds of declaration may appear inside, in any order.
workspace "Commerce"
module commerce@v1
shape Service
id: String
end shape
entity checkout_api: Service
has tag critical
end entity
end workspace
Rules:
- Must start with
workspace "name"(quoted string, not a bare identifier) - Optional
module <name>@<version>immediately after the header - Declarations:
shape,event,entity,relationship,lattice,policy,operation,project,view - Every block closes with
end <keyword>, includingend workspace - Indentation is significant: spaces only, one level per block
2. Module Declaration (Optional)
workspace "Demo"
module archkit_core@v2.0
end workspace
Rules:
- Optional; appears immediately after the
workspaceheader - Syntax:
module <identifier>@<version>— the version is free text to end of line (v1,2.0,1.2.3-betaall work) and must be non-empty end moduleis optional
3. Shapes (Data Structures)
shape Account
id: String
email: String
balance: Float?
tags: String[]
fallbacks: String?[]
metadata: Json
end shape
shape EmptyShape
end shape
Rules:
shape <identifier>followed by newline- Fields are
name: TypeExpr, one per line, indented end shaperequired; empty shapes allowed
Type expressions (implemented):
| Syntax | Meaning |
|---|---|
Name | named type (String, Int, Float, Bool, or any shape name — names are not validated at parse time) |
Json | untyped JSON (the only special-cased type name) |
T? | optional |
T[] | list |
| suffix stacking | String?[] = list of optionals |
Not implemented (do not use): [T] prefix lists, {k: T} map types,
(T1, T2) tuples, T1 | T2 unions. The AST reserves nodes for map/tuple/union,
but no surface syntax produces them.
4. Events
Events use identical field syntax to shapes; the keyword marks async message/event semantics.
event OrderPlaced
order_id: String
customer_id: String
amount: Float
end event
5. Entities (Instances / Nodes)
Header forms
entity plain_node
end entity
entity account1: Account
end entity
entity payments_db database
end entity
entity stripe external system
end entity
entity <id>— generic kindentity <id>: <ShapeName>— with shape referenceentity <id> <kind>— with element kind. Kind vocabulary:database,queue,container,component,person, and the two-word phraseexternal system. Any other word in kind position is a parse error.
Body
entity checkout_api: Service
has tag critical
has tag revenue_path
has owner: payments_team
has sla: "4 hour response"
has config: {timeout: 30, retries: 3}
has regions: ["us-east", "eu-central"]
derived from: "service-catalog:checkout_api"
verified by: "arch-review:AR-2026-041"
edge payment_service calls
has protocol: https
verified by: "trace:prod:checkout/payment"
end edge
edge notification_queue sends data to
has async: true
end edge
end entity
Body items (all optional, repeatable):
has tag <identifier>— attach a taghas <key>: <value>— attach a property (thehaskeyword is required; barekey: valuelines are not valid in entity bodies)- provenance clauses (§7)
edge <target> <phrase> … end edge— local edges (§6 phrase vocabulary); edge bodies takehasproperties and provenance clausesexpands to <kind> … end <kind>— sub-language blocks (§12)
6. Relationships (Global Edges)
relationship user uses api
end relationship
relationship frontend calls backend
has protocol: "JSON-RPC"
has timeout_ms: 5000
end relationship
relationship db serves api
evidenced by: "trace:prod:db-query"
verified by: "test:integration"
end relationship
Rules:
relationship <from> <phrase> <to>followed by newline- Body (optional):
has <key>: <value>properties and provenance clauses end relationshiprequired
Edge phrase vocabulary — these normalize to a closed EdgeKind set:
- Multi-word (pre-tokenized by the lexer):
depends on,sends data to,receives data from,reads from,writes to,connects to,owned by,contained by,extended by,implemented by,used by,provided by,served by,cached by,monitored by - Single-word:
calls,publishes,subscribes,precedes,follows,triggers,owns,contains,extends,implements,uses,produces,consumes,exports,imports,serves,caches,monitors - Any other single word is accepted as a custom phrase (
EdgeKind::Custom). Custom multi-word phrases are not possible.
7. Provenance (Evidence Tracking)
Provenance clauses may appear in entity, edge, and relationship bodies:
entity user_service
derived from: "doc:requirements"
evidenced by: "trace:prod:user-table"
observed in: "runbook:user-mgmt"
verified by: "test:user-factory"
deprecated by: "doc:migration-2026"
end entity
Verbs (closed set, pre-tokenized): derived from, evidenced by,
observed in, verified by, deprecated by.
Format: <verb>: <value> where value is a string or identifier; repeatable.
replacesis not a provenance verb. Express supersession as a property:has replaces: "old_notification_queue".
8. Lattices (Ordered Domains)
Only chain lattices are implemented:
lattice Criticality
order low < medium < high
end lattice
lattice Severity
order minor < moderate < major < critical
bottom minor
top critical
end lattice
Rules:
lattice <identifier>followed by newlineorder a < b < c— a single ascending chain- Optional
bottom <element>(must be the chain’s first element) andtop <element>(must be the last) end latticerequired- Lowering computes the reflexive-transitive closure automatically
Explicitly rejected (reserved for future partial orders): level, covers,
join, meet, incomparable — using them is a parse error, not a silent no-op.
9. Policies (Governance Rules)
policy revenue_reliability
applies to tag: revenue_path
when source.env: prod
unless source.experimental: true
requires monitoring.enabled
must have owner
forbids tier: best_effort
requires reaches via depends on where target.owner: platform
end policy
Structure:
policy <identifier>followed by newline- Selector (required):
applies to tag: <tag>|applies to entity: <id>|applies to shape: <name>|applies to relationship: <phrase> - Conditions (optional, repeatable):
when <predicate>,unless <predicate> - Requirements (optional, repeatable):
requires <predicate>,forbids <predicate>,must have <predicate>(alias ofrequires),must not <predicate>(alias offorbids) end policyrequired
Predicates:
- Free text to end of line (
monitoring.enabled,source.owner: platform) — captured as a simple predicate and interpreted during evaluation - Lattice comparisons:
<expr> at least <expr>,<expr> at most <expr>,<expr> above <expr>,<expr> below <expr> - Reachability:
reaches via <edge-phrase>with optionalwhere <predicate>(nestable). Reachability predicates currently lower as advisory (info) diagnostics — they parse and are preserved, but are not evaluated against the graph yet.
10. Operations (Behavior Property Bags)
operation DataSync
action: "synchronize replicas"
timeout_sec: 3600
retry: 3
end operation
Rules: operation <identifier>, body is bare key: value lines
(no has prefix here), schema is user-defined. end operation required.
11. Projects (Bundles)
project checkout_system
includes entity user
includes entity api
has team: payments
deployment: production
end project
Rules:
project <identifier>followed by newline- Body may contain, in any order:
includes <free text>— repeatable; stored asincludes_<n>propertieshas <key>: <value>or bare<key>: <value>— both accepted here
end projectrequired
12. Views (Projections)
view revenue_overview
kind: system
schema: c4
include: tag: revenue_path
include: entity: payments_db
exclude: tag: experimental
focuses_on: checkout_api
layout
rankdir: LR
fontsize: 12
end view
Body keywords:
kind: <identifier>— view type (defaults tosystem)schema: <identifier>— rendering schema (defaults toc4)include: <selector>/exclude: <selector>— repeatablefocuses_on: <entity>— highlight one entity (note the spelling:focuses_on, notfocus_on)layout— bare keyword, no colon, followed by an indented block ofkey: valuepairs; the block ends at dedent (there is noend layout)end viewrequired
Selectors: entity: <name>, tag: <tag>, relationship: <phrase>.
No other selector types exist.
13. Sub-Language Blocks (expands to)
Entities can embed domain-specific sub-language blocks:
entity pricing_rules
expands to expression
o quantity
end expression
end entity
Rules:
expands to <kind>followed by newline and an indented block- The block body is captured as a raw token stream (it must still lex as AKS:
tokens like
*,=,+are rejected by the lexer) - Closed by
end <kind>at the parent indentation
The expression sub-language:
o <name>— variable reference;o 42/o "lit"— constants<> <op>withleft:/right:ports — operation trees. Known limitation: operation trees currently parse but fail lowering (“unexpected end in operation”); only variable/constant expressions survive the full pipeline today. Track before relying on<>forms.
14. Property Values
Values in has k: v, operation/project/layout bodies:
| Form | Example |
|---|---|
| string | "4 hour response" (double quotes only; escapes \n \t \" \\) |
| integer | 5000 (no negative literals, no exponents) |
| float | 3.14 |
| boolean | true, false |
| identifier | https, payments_team (colon-joined idents like a:b also parse) |
| list | ["us-east", "eu-central"], [1, 2, 3] |
| object | {timeout: 30, retries: 3, cache: true} (nestable) |
15. EBNF Summary
workspace = "workspace" STRING newline module? decl* "end" "workspace"
module = "module" IDENT "@" line_text newline ("end" "module")?
decl = shape | event | entity | relationship | lattice
| policy | operation | project | view
shape = "shape" IDENT newline (indent field* dedent)? "end" "shape"
event = "event" IDENT newline (indent field* dedent)? "end" "event"
field = IDENT ":" type_expr newline
type_expr = ("Json" | IDENT) ("?" | "[" "]")*
entity = "entity" IDENT ((":" IDENT) | kind_phrase)? newline
(indent entity_item* dedent)? "end" "entity"
kind_phrase = "database" | "queue" | "container" | "component"
| "person" | "external system"
entity_item = "has" "tag" IDENT newline
| "has" IDENT ":" value newline
| provenance
| edge
| expands_to
edge = "edge" IDENT edge_phrase newline
(indent (has_prop | provenance)* dedent)? "end" "edge"
expands_to = "expands" "to" IDENT newline indent raw_tokens dedent "end" IDENT
relationship = "relationship" IDENT edge_phrase IDENT newline
(indent (has_prop | provenance)* dedent)? "end" "relationship"
edge_phrase = EDGE_PHRASE_TOKEN | IDENT (* see §6 vocabulary *)
provenance = PROVENANCE_VERB ":" line_text newline (* see §7 verbs *)
lattice = "lattice" IDENT newline indent
"order" IDENT ("<" IDENT)+ newline
("bottom" IDENT newline)? ("top" IDENT newline)?
dedent "end" "lattice"
policy = "policy" IDENT newline indent
("applies" "to" selector newline)
(("when" | "unless") predicate newline)*
(("requires" | "forbids" | "must have" | "must not") predicate newline)*
dedent "end" "policy"
selector = ("tag" | "entity" | "shape" | "relationship") ":" value
operation = "operation" IDENT newline (indent kv* dedent)? "end" "operation"
project = "project" IDENT newline
(indent ("includes" line_text | has_prop | kv)* dedent)? "end" "project"
view = "view" IDENT newline (indent view_item* dedent)? "end" "view"
view_item = ("kind" | "schema") ":" IDENT newline
| ("include" | "exclude") ":" selector_type ":" IDENT newline
| "focuses_on" ":" IDENT newline
| "layout" newline indent kv* dedent
selector_type = "entity" | "tag" | "relationship"
has_prop = "has" IDENT ":" value newline
kv = IDENT ":" value newline
value = STRING | INT | FLOAT | BOOL | IDENT
| "[" (value ("," value)*)? "]"
| "{" (IDENT ":" value ("," IDENT ":" value)*)? "}"
16. Common Errors
Missing end marker — every block needs its closer:
entity user
has tag actor
# error: expected 'end entity'
Mismatched end:
entity user
end shape # error: expected 'end entity', found 'end shape'
Bare property in entity body (entity bodies require has):
entity user
role: storage # error: expected newline — write `has role: storage`
end entity
Unquoted workspace name:
workspace Ecommerce # error: expected string — write workspace "Ecommerce"
Tabs in indentation — the lexer rejects tabs outright.
17. Reserved Words
Reserved (cannot be used as bare identifiers in most positions):
workspace module shape event entity relationship lattice policy
operation project view end edge has tag with includes excludes
focuses on renders shows hides groups orders by expands
when unless requires forbids above below
order level top bottom join meet covers incomparable
Notes:
with,renders,shows,hides,groups,orders,by,on,focuses,excludesare reserved but currently consumed by no grammar rule (reserved for future view syntax)at least,at most,must have,must not,applies to, the edge phrases (§6), the provenance verbs (§7), andexternal systemare pre-tokenized multi-word phrases
18. Related
- Lexical detail (tokens, indentation, phrase tables): LEXICAL_RULES.md
- Working examples (validated in CI): ../examples/
- Overlay files (
annotateblocks) are a separate dialect handled byarchkit-project, not this grammar — seedocs/guides/PROJECT_SYSTEM.md - Parser source:
crates/archkit-frontend/src/aks/parser/ - Lexer source:
crates/archkit-frontend/src/aks/lexer/ - Conformance test:
crates/archkit-frontend/tests/docs_aks_conformance.rs