2. Your First Architecture
This chapter walks through building a complete (small) architecture from an empty directory. By the end you’ll have three modules, one process tying them together, a diagram, and a feel for the shape of the language.
We’re going to use only the bare language — the base types module, surface, interface plus the top-level constructs process and view — with no standard library. Later chapters introduce richer types (service, command, event); Chapter 11 covers them in detail. Starting bare keeps the focus on what the language itself does, separate from convention.
We’ll model a payments domain: a customer pays, a payments service authorizes, a ledger records. Nothing else.
A package
Section titled “A package”Every project starts with a manifest. Create package.archspace:
package: shopOne line. The package: field names the package root; we don’t import the stdlib yet because we’re using bare types only. (Package names are lowercase, dot-separated — a bare shop is fine for a single project.)
Chapter 12 covers the manifest in depth. For now this is enough.
Three modules
Section titled “Three modules”Add payments.arch in the same directory:
module Payments { aspect team: "Platform" "Authorizes and captures card payments."
interface authorize interface capture interface refund}
module Ledger { aspect team: "Finance" "Immutable financial record of every transaction."
interface record}
module Customer { "The person initiating the payment."}You’ve declared three modules using the bare module type. Each has:
- A type (
module) — the base type of the language. - A name (
Payments,Ledger,Customer) — how the rest of your model refers to it. Module names areUpperCamelCase. - A team aspect — who owns it (optional; aspects cascade to everything nested, with override).
- A description — the bare string literal. Plain markdown, plus two extensions you’ll meet in Chapter 10.
- Zero or more interfaces —
interface authorize, etc. These are the things other modules can ask this one to do. Interface names arelowerCamelCaseand read like the real operation — a verb for an RPC call (authorize), an action-plus-resource for REST (Chapter 5 goes deeper).
Customer has no interfaces. That’s fine — not every module exposes operations. (Stdlib types add semantic distinctions like user for entities that only originate calls; for now everything is just module.)
We didn’t sit down and ask “what connects to what.” We described each module on its own — what it is, what it can do — and stopped. Connections come later, and they fall out of a process rather than being drawn. That two-pass habit (describe the cast, then tell the story) is the backbone of authoring in ArchLang.
Try it live — edit the source above, the diagram updates below. Hover identifiers, press F2 to rename, Ctrl/⌘ Space for completion:
Save the file and run:
archlang validate .You should see no errors. Open the directory in your editor (with the ArchLang extension installed) and trigger the inline preview pane — three boxes appear, connected to nothing yet. That’s expected — we haven’t said how they interact.
The diagram looks plain because the bare module type has no specialized rendering. Boxes labeled with names; one default widget for all three. The stdlib introduces per-type widgets (Chapter 11); for this chapter, plain boxes are the point — they make the underlying structure obvious.
A process
Section titled “A process”Add checkout.arch:
process Checkout { Customer > Payments.authorize Payments > Ledger.record Customer > Payments.capture Payments > Ledger.record}A process is a sequence of steps. Each step has the form Caller > Callee.Interface:
- The caller (left of
>) is a module — who is making the call. - The callee (right of
>) is an interface — the specific operation being invoked.
Save and the preview updates. The diagram now has arrows. They weren’t drawn — they were derived from the process. This is the first commitment from the foreword in action: behavior is the source of structure.
Mindset shift. In most diagramming tools you draw an arrow because two services talk. In ArchLang you declare a process step; the arrow appears because something declared that it talks. Delete the step and the arrow disappears. Add another step and a new arrow appears. The dependency graph is always a function of behavior.
A change
Section titled “A change”Open payments.arch and add a fourth interface:
module Payments { aspect team: "Platform" "Authorizes and captures card payments."
interface authorize interface capture interface refund interface void // new}Save. The preview updates. void shows up in the Payments node; no arrow connects it to anything because no process invokes it yet.
Now open checkout.arch and add a step:
process Checkout { Customer > Payments.authorize Payments > Ledger.record Customer > Payments.capture Payments > Ledger.record Customer > Payments.void // new — customer cancels mid-checkout}Save. The preview updates again. void now has an arrow into it.
You’ve added an interface and a process step in two edits and the diagram followed along. No layout to redo, no boxes to drag.
What you built
Section titled “What you built”shop/├── package.archspace├── payments.arch└── checkout.archThree files, three modules, one process. A complete (if minimal) architecture written in pure bare language. Every diagram, every dependency arrow, every impact analysis that ArchLang can do for you is derived from these files.
Summary
Section titled “Summary”- A workspace starts with a
package.archspacemanifest naming the package. - The bare types
moduleandinterfaceare enough to model structure and exposed operations. - Processes are sequences of
Caller > Callee.Interfacesteps. Arrows in diagrams are derived from processes — they are not drawn directly. - The editor preview re-renders on save. The dev loop is edit file → see diagram.
What’s next
Section titled “What’s next”Chapter 3: Reading a Diff → — make a change to the architecture and see how ArchLang shows you what changed.