Skip to content

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 kinds module, facet, interface plus the top-level constructs process and view — with no standard library. Later chapters introduce richer kinds (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

Every project starts with a manifest. Create package.archspace:

name: shop

One line. The name identifies the package; we don’t import the stdlib yet because we’re using bare kinds only.

Chapter 12 covers the manifest in depth. For now this is enough.

Three modules

Add payments.arch in the same directory:

module Payments {
team: Platform
"Authorizes and captures card payments."
interface Authorize
interface Capture
interface Refund
}
module Ledger {
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 kind. Each has:

  • A kind (module) — the base kind of the language.
  • A name (Payments, Ledger, Customer) — how the rest of your model refers to it.
  • A team field — who owns it (optional; not required by the bare kind).
  • A description — the bare string literal. Plain markdown, plus two extensions you’ll meet in Chapter 10.
  • Zero or more interfacesinterface Authorize, etc. These are the things other modules can ask this one to do.

Customer has no interfaces. That’s fine — not every module exposes operations. (Stdlib kinds add semantic distinctions like actor for entities that only originate calls; for now everything is just module.)

Try it live — edit the source above, the diagram updates below. Hover identifiers, press F2 to rename, Ctrl/⌘ Space for completion:

Loading editor…

Save the file and run:

Terminal window
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 kind has no specialized rendering. Boxes labeled with names; one default widget for all three. The stdlib introduces per-kind widgets (Chapter 11); for this chapter, plain boxes are the point — they make the underlying structure obvious.

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

Open payments.arch and add a fourth interface:

module Payments {
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

shop/
├── package.archspace
├── payments.arch
└── checkout.arch

Three 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

  • A workspace starts with a package.archspace manifest naming the package.
  • The bare kinds module and interface are enough to model structure and exposed operations.
  • Processes are sequences of Caller > Callee.Interface steps. 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

Chapter 3: Reading a Diff → — make a change to the architecture and see how Archlang shows you what changed.