Skip to content
Phero Lang
Menu

Get started

A model, its artifact, and generated code.

You write one .mox file. The compiler checks it, compiles it to Core IR, and every backend reads that artifact.

Confirm the binary is on your PATH:

bashexecuted by CI
pherolang --version

You should see pherolang 0.3.0 and the target triple it was built for.

1 / Design

Design a domain

A .mox file declares a package and the classes inside it. Every other surface reads this one.

This is lines 1–32 ofexamples/support/support.mox, unchanged:

examples/support/support.mox · lines 1–32
package nz.example.support

enum TicketState {
    Open as "open" = 0
    InProgress as "in_progress" = 1
    Resolved as "resolved" = 2
}

class User {
    id readonly String userId
    String name
    boolean active
    refers Ticket[] assignedTickets opposite assignee
}

class Ticket {
    id readonly String ticketNo
    String title
    boolean internal
    int refundCents
    TicketState state
    refers User[0..1] assignee opposite assignedTickets
    derived boolean needsRefund {
        expr { refundCents > 0 }
    }
    op boolean raiseRefund(int cents) {
        expr { refundCents + cents <= 5000 }
    }
    op boolean approveRefund(int cents) {
        expr { refundCents + cents <= 100000 }
    }
}

Three lines in that excerpt do most of the work:

  • refers User[0..1] assignee opposite assignedTickets declares both ends of one relation. The compiler checks that the two ends agree.
  • derived boolean needsRefund is computed, not stored — it has a body and no stored value.
  • op boolean raiseRefund(int cents) declares an operation whose body is written in the expression language and type-checked against int arithmetic.

Declarations are checked, not annotated: a misspelt feature inside that body is a compile error. The grammar is inLANGUAGE.md; the expression rules are inEXPRESSIONS.md.

2 / Compile

Check, compile, generate

Four commands. Each one exits 0 on the example above.

Check

check parses, resolves, validates and type-checks the file. It reports each problem with the file and the exact span that caused it.

bashexecuted by CI
pherolang check examples/support/support.mox

It prints OK examples/support/support.mox and nothing else.

Compile to Core IR

ir writes the artifact and prints nothing when it succeeds. The second command reads the file back: artifact check validates the serialized JSON on its own — it opens no model, resolves no import, and runs no compiler.

bashexecuted by CI
pherolang ir examples/support/support.mox -o support.phero.json
pherolang artifact check support.phero.json

The first command produces no output; the second printsOK support.phero.json.

Generate

A backend reads the compiled model and writes code. Here is the Rust one, over the same source:

bashexecuted by CI
pherolang gen rust examples/support/support.mox -o support-gen

It prints generated Rust model code into support-gen. You now havesupport-gen/models.rs: arena-based Rust model code, generated from the model rather than from the compiler's syntax tree.

3 / Understand

What you just built

The artifact is the product. The compiler's job ends at Core IR.

Parsing, name resolution, validation and lowering all happen before an artifact exists. Backends consume the artifact and nothing else — never the syntax tree. That is why an in-tree generator and an out-of-tree backend cannot disagree about a model's shape: they read the same Core IR, either in process or as the serialized artifact. The contract for writing one isBACKENDS.md.

support.phero.json · excerpt
{
  "formatVersion": 2,
  "pheroVersion": "0.3.0",
  "packages": [
    {
      "name": "nz.example.support",
      "annotations": [],
      "enums": [
        {
          "name": "TicketState",
          "literals": [ … ]
        }
      ],
      "classes": [ … ]
    }
  ]
}

Two fields do the work. formatVersion is the compatibility gate: a reader accepts that number or refuses the file. pheroVersion is provenance — which compiler wrote it, and nothing more.VERSIONING.mdstates the rule: readers gate on formatVersion only.

A second backend, over the same model:

bashexecuted by CI
pherolang gen json-schema examples/support/support.mox --profile wire -o support-schema

It prints generated JSON Schema into support-schema. One model, two targets, one shape.

4 / Continue

Where to go next

The .mox domain is one of nine surfaces. They compile together into one semantic graph.

The example tree exercises every surface — designs, policies, decisions, event contracts, use cases, cases, interaction flows, deployments. check prints oneOK line per file:

bashexecuted by CI
pherolang check examples/

graph build compiles that tree into one artifact instead of one per file: applications, every surface's nodes, and the edges between them. It is derived after compilation, never parsed.

bashexecuted by CI
pherolang graph build examples -o examples.graph.json