Skip to content

Appendix D: Cheatsheet

For when you know what you want and need the syntax. Each line is a complete construct; chapters and other appendices are linked for full context.

A plain module is the default building block; a specific type (service, …) is sugar you reach for when it earns its keep.

module Orders { rest_create createOrder } // plain module — the default
service Orders { // a typed module (sugar)
aspect team: "Commerce"
rest_create createOrder
} // type + name + body
service #k7f2 Orders { ... } // with stable ID (random, meaningless)
service AuthService in Platform { ... } // attach to a parent declared elsewhere
service Notifications // empty body, no braces

See Ch 4.

A plain interface is the default connection; a wire-level type (rest_create, kafka, …) is sugar. Name interfaces after the protocol verb/resource.

interface authorize // plain interface — the default
rest_create authorize // typed leaf (sugar)
rest_create authorize { // with body
"Description"
timeout: "5s"
}
kafka paymentEvents // async event interface (no subscribes:)
// an event is an async interface reached by a normal `>` process edge — the edge IS the subscription

See Ch 5.

surface ordersResource { // generic surface
base: "/orders"
rest_create createOrder
}
resource ordersResource { base: "/orders" } // user-defined surface type
surface outer { surface inner { ... } } // nested surfaces

resource is a custom type teams define via type surface resource { ... }; the stdlib only ships generic surface. See Ch 6 and Ch 16.

process Checkout {
order = Customer > Orders.createOrder // step, with result binding
Orders > Payments.authorize(order) // step with arg list
| > Ledger.record // fan: owner = previous line's HEAD (Orders)
\ > Audit.log // snake: owner = previous line's TAIL (Ledger)
"wait for fraud review" // bare note step (no edge)
Orders "ops team double-checks the total" // actor-anchored note
Payments if "stripe-customer" { // exclusive conditional (free-form head)
Payments > Stripe.charge
} else {
Payments > PayPal.charge
}
Orders select "payment method" { // multi-way, inclusive (every match runs)
stripe: Payments > Ledger.record
applepay: Payments > Ledger.record
}
Shipping parallel race { // concurrent branches; race = first wins
branch: Shipping > Notifications.sendEmail
branch: Shipping > Notifications.sendSMS
}
Orders try { // error path (guard, continue forward)
Orders > Payments.authorize
} catch "declined" {
Orders > Notifications.sendEmail
}
Orders each item in order.items: Orders > Inventory.reserve(item) // iteration (one-liner body)
Order reversible { // saga: completed steps roll back
Order > Inventory.reserve unwind Order > Inventory.release // each step compensates itself
Order > Payments.charge unwind Order > Payments.refund
}
do NotifyCustomer(order) // splice subprocess (ownerless)
finish "checkout complete" // terminate: success
}
process Checkout in Orders { ... } // attach to a module
subprocess NotifyCustomer(arg) { Orders > Ledger.record } // reusable helper (args intent-only)

Anonymity — the draft floor (every anonymous piece is a TODO):

module Orders {
> Payments // bare step: anon process, implicit caller = Orders
> Cart.add // name the interface; caller still implicit
}
A > B. // trailing dot: B is a module, interface unspecified (TODO)
A > B.x > C.y // chain (ordered): desugars to A > B.x ; B > C.y

Bare steps are unordered (order comes only from a process { } wrapper); a chain is one ordered anonymous process; a module callee synthesizes an anonymous interface. Refer to modules, interfaces, and subprocesses that don’t exist yet — the compiler synthesizes a dashed stub and tracks each gap as a TODO (process-first drafting), rather than erroring. archlang validate --complete gates a zero-TODO model. See Ch 7.

view PaymentsLandscape {
"Description — first line is the header zone"
show @@domain:"Payments" or @@security.zone:"PCI" // union selectors; @@ = aspect axis
show in Payments or in Gateway // subtree membership
hide database // subtract after the show-union
group by @@team // cluster by an aspect getter (by VALUE)
group by in Payments // by CONTAINMENT — one frame per container
style * { color: colorize(@@security.zone) } // colour; explicit cast feeds the legend
style violating PciIsolation { color: crimson } // policy findings drive visuals
}
// one representation clause replaces the board:
// table { column @name; sort by @name }
// matrix { axis @@team; order by cluster } — or `rows`/`cols` for a rectangular one
// grid { rows @@team; cols @@security.zone; color @kind } — cross-tab, cells list modules
// flow <Proc> [sequence | bpmn] — `bpmn` opens { lane by @@team | pool by @@team | … }
// no layout clause — layout is the solver's; pin per node with `style X { pin <x>, <y> }`.

See Ch 8.

A story is a guided walk over the view — not a representation, so it composes with any of them, and it is inert until the viewer is opened with ?present=1:

view PaymentsStory {
show @@team:"payments"
story { // at most FIVE chapters (hard grammar rule)
chapter "Order comes in" {
"Leading string is the chapter's note — optional, and it must come first."
Web, Checkout, Orders // any node selector; written order IS the narration
}
chapter "Money moves" {
Payments, Bank, Ledger
}
}
}
// beats, the relation each crosses, the sentence, the camera window and the
// chapter handoff are all DERIVED. Doesn't compose with `focus`; one per view.

See Ch 36.

Fields = structured data. Aspects = cross-plane connections (a classification or a module membership). Descriptions = unstructured prose.

service Orders {
region: euWest // identifier value (a plain field)
repo.url: "https://..." // dotted key + string (structured property)
version: 2 // number
enabled: true // boolean
"Description goes here as a bare string."
aspect {
domain: "Orders" // string value = classification (a (key, value) tag)
broker: KafkaBroker // bare module ref = membership (KafkaBroker becomes a place)
}
}

See Ch 9.

"Plain markdown plus archlang extensions.
**bold**, *italic*, ~~strike~~, `code`, [link](https://...), tables, lists.
[[#stable_id]] / [[Name]] link to a declaration
[[@@key]] / [[@@key:value]] link to an aspect plane / a specific classification
[[Doc#section]] link to a heading inside an .md document
@@aspectPath substitute an aspect value from THIS node (descriptions only)
[[ref]]@@aspectPath read an aspect value on a REFERENCED node (works in .md too)"

Every element also gets automatic backlinks (“mentioned in”). .md files render with the same flavored markdown and are a first-class archspace surface. See Ch 10 and Ch 10a.

package: acme.shop // package root (opaque unit)
version: "1.0.0"
widgets: "./widgets.js"
repo: "https://github.com/acme/shop" // evidence pin — the repo `sources:` is checked against
commit: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0" // required whenever `repo:` is set
dependencies {
acme.shared: "../shared"
}
use database, frontend from arch.backend // explicit, pick-and-choose (never use *)
use relational_db as managed_db from acme.shared // local rename
export use payments_provider from acme.payments // re-export

A nested space manifest carries name: instead of package::

name: acme.shop.loans // a space within the package

See Ch 12.

Evidence bindings — an ordinary field naming the code that attests a module, checked against the package’s repo:/commit: pin:

module Checkout {
sources: "src/checkout/index.ts:12-88", "src/tax.ts:5-40", "src/whole-file.ts"
}
// entries are repo-root-relative; ranges are 1-based and INCLUSIVE.
// verdicts: verified | broken | unverified — `unverified` is never a pass and draws no badge.

See Ch 37.

IDs are meaningless and permanent — random, never domain-encoded, never changed (let tooling mint them).

service #q8m3 Payments { ... } // module ID
type #b9k1 module service { ... } // type ID
process #x4t7 Checkout { ... } // process ID
view #h2w5 Landscape { ... } // view ID
// Surfaces and interfaces do NOT carry IDs.

See Ch 13.

Plain modules/interfaces are the default — define a custom type only when you need to subtype, attach widgets, add custom fields/requirements, or assert a type.

type module service {
required cascade version // mandatory cascading blank field
required aspect domain // mandatory blank aspect
component metrics { rest_create emit } // pre-filled sub-declaration
required database PrimaryStore // mandatory blank sub-declaration
cascade widget: arch-service // default cascading field
append base // append-mode field (path/list/object compose)
}
type service paymentsService { version: "2.1" } // subtype
export type service internal_service { ... } // visible to importers

See Ch 15 and Ch 16.

// Two and only two ways to address an inherited `required` blank:
field: value // fulfill
drop field // remove entirely

See Ch 17.

ModifierBehavior
(none)localStays where set, doesn’t flow
cascadeFlows to descendants; override-on-walk
cascade *Declares a cascade-group root — sub-fields under the path participate in the same group; replacing the root drops the group; overriding a leaf keeps it
appendFlows and composes (paths concat, lists append, objects merge)

Cascade groups let you bundle related sub-fields (e.g. widget, widget.icon, widget.color) so that swapping the root tag automatically clears the inherited sub-fields, without per-leaf drop ceremony:

type module service {
cascade * widget: arch-module {
icon: service
color: info
}
}
type service custom {
widget: my-element // drops icon, color
}
type service tweaked {
widget.color: green // keeps icon
}

Aspects always cascade with override semantics; no modifier needed (or allowed) on aspects. See Ch 18.

Refinement / override / drop (uniform at type and instance level)

Section titled “Refinement / override / drop (uniform at type and instance level)”
// Refine — same type or subtype, merges:
component metrics { rest_create emitV2 }
// Override — switch to non-subtype type, requires keyword:
override database metrics { db_read read }
// Drop — remove entirely:
drop metrics
drop metrics.emit // remove a child

Move-set against an inherited required blank:

GoalSyntax
Refine to subtype type, keep blankrequired <subtype> Name
Refine to subtype type, fulfill<subtype> Name { ... }
Switch to non-subtype type, keep blankoverride required <new-type> Name
Switch to non-subtype type, fulfilloverride <new-type> Name { ... }
Fulfill keeping inherited typeName: value or Name { ... }
Remove entirelydrop Name

See Ch 19.

widget: arch-service // custom-element form
widget.icon: server // widget prop
widget.accent: accent
widget: "<div class='card'>{{name}}</div>" // inline template form
widget: """<archui-card>{{name}}</archui-card>""" // triple-quoted, raw

See Ch 20.

Terminal window
archlang validate <path> # validate; exit non-zero on errors
archlang validate --watch <path>
archlang validate --complete <path> # fail (exit 3) if any TODO remains
archlang info <path> # summarize a package
archlang check <path> # validate + policy-check + format --check + evidence
archlang check <path> --against=main # + change-gate dry run vs a git ref
archlang format <file.arch> # canonical formatting (whitespace, indent, ID minting)
archlang format --check # exit non-zero if format would change anything
archlang format --diff # print what would change
archlang set <path> <target> <field> <value> [--aspect] # headless field/aspect write
archlang set <path> <target> <text> --description # headless description write
archlang policy-check <path> # evaluate policies; error/warning/advisory findings
archlang evidence <path> [--repo=<path>] # check `sources:` bindings; exit 1 only on BROKEN
archlang export json <path> [-o <file>] # dump the resolved model as JSON
archlang export html <path> -o <file> # one self-contained HTML file, opens offline
archlang render <path> --out=<f.svg|f.png> [--view=board|bpmn|flow|sequence] [--process=<name>]
# headless diagram export (PNG via bundled resvg)
archlang serve <path> [--port=<n>] [--web-root=<path>] # HTTP API + optional web UI
archlang lsp # language server on stdio
archlang conform <path> --source=jaeger|tempo --endpoint=<url> # check telemetry vs the model

See Ch 21.

<archlang-viewer
src="./diagram.arch"
style="width: 100%; height: 480px"></archlang-viewer>

Sizing uses CSS (style, class); the element doesn’t accept width/height attributes. See Ch 23.

my-project/
├── package.archspace # manifest (required for non-anonymous package)
├── widgets.js # custom-element registrations (optional)
├── types.arch # type declarations
├── orders.arch # instance declarations
└── packages/shared/ # nested package (its own boundary)
├── package.archspace
└── ...