Tools › Commands

Tools

archec commands

archec <command> … — archec with no command lists the everyday ones; archec help --all lists every command by what it is for (the sections below), archec help <command> (or archec <command> --help) gives one command's usage and an example; archec --version gives the version. A command that checks something exits 1 when it finds a problem, so each one can be a CI step; archec ci is all of them at once.

Start#

Command What it does
archec help [--all | <command>] The everyday commands; --all every command by what it is for; a command's usage, options and an example (as archec <command> --help).
archec new [dir] [--template <id|owner/name>] [--board <id>] [--name <name>] [--parts "a -> b, b -> c"] [--target none|c|embassy|go] [--handlers typescript|python|arche] [--yes] [--dry-run] A new project that checks clean, instead of a blank page (new.md). From a template archec ships — blank (the default), rover-esp32, can-sensor-node (STM32G4 and CAN), drone-fc (a flight controller) — or one of the store (owner/name). --board puts a board of the board store in (or swaps the template's for it), --parts adds parts and links (lidar -> planner; a name alone is a part), --target writes a deployment for archec gen when there is none (go sets language go). The project says handlers typescript (its behaviour in TypeScript, handlers.md) unless --handlers says another, or the code it starts from is Python; the template's ```arche bodies translate to it. Each step is checked as archec check does, and one that would add an error is left out with a note. Writes main.arche, README.md and .gitignore. In a terminal it asks its questions (what you build, the board, the parts, the code), each one a flag did not answer; --yes takes the defaults; --dry-run prints the files and writes nothing.
archec new <dir> --kind firmware|service|containers|ros2|desktop|library [--target c|embassy|go] [--no-run] A project of a kind that already runs (new.md): the kind's template, its deployment, its code generated (the code you fill in into src/, committed, its USER CODE regions kept; the rest into generated/, ignored), a first test for each part no test plan names, CI files at the root (.github/workflows/archec.yml, .gitlab-ci.yml: archec ci, then the code generated, built and tested), .vscode/ (recommended extensions, tasks build, test and live), a README with the commands. Then the first run: archec check, archec test, archec gen, the kind's build and tests, each step said and one line at the end (first run: simulated 500 ms, built (make), 4/4 tests pass). A tool not on this computer, or a daemon not running, skips its step with a note; a step that fails exits 1. --no-run skips the first run; --dry-run writes nothing and runs nothing. Without --kind and in a terminal, the first question is the kind.
archec new --first-run [dir] The first run again, in a project archec new --kind made (its .archec/kind.json says the kind): check, simulate, generate, build, test. Exit 1 when a step fails.
archec new <dir> --from <owner/name[@range]> [--store <where>] Remix: any store package (an architecture, a template, a board…) copied into a new project as an editable copy, not a uses dependency, checked as archec add checks it (hash, signature, trust). The project gets derived-from "owner/name@version"; what the package uses from the store is taken with archec add. A package without a main file gets one that includes its files.
archec new <dir> --describe "a robot with 2 motors, a lidar and a Raspberry Pi" [--kind <id>] [--board <id>] [--rounds 4] [--model id] [--dry-run] Claude (claude-opus-5-5) writes the first model from a sentence: it gets a compact language reference, the board store's boards and a template as an example; what comes back is checked as archec check does, and the errors go back to it, up to --rounds times. A first draft to read, not a verdict. It sends text out: your description, and archec check's messages on what Claude wrote, go to the Anthropic API, only when this command runs; --dry-run prints the prompt and sends nothing. Credentials: ANTHROPIC_API_KEY. The kind is --kind, else the one the words of the sentence name (firmware, esp32, stm32…: each kind's words); --dry-run says which.

Write and check#

Command What it does
archec check <main.arche>… [--json] [--strict] [--quiet] [--beginner] [--sarif <report.sarif>] Lint: errors, warnings, hints, each with its code ([unresolved], [suspect], [rule]…). Exit 1 on an error; --strict also on a warning. --sarif: the same diagnostics as SARIF 2.1.0, for code scanning (below). The project's own rules and the links made suspect by a reworded requirement are part of it. --beginner (or ARCHE_LEVEL=beginner): the common messages in plain words, with what exists (“You used bar but b has no port called that. Its ports are: cmd, st.”), and how many archec fix can fix (fixes).
archec fix <main.arche> [--dry-run] [--only code,…] [--vet] [--json] Errors that fix themselves: the preferred fix of each diagnostic (the closest name, property, value or unit, the link's ends swapped, a port's direction, a ; before a glued property, a file an include names…), one per place, then checked again — until none applies (5 passes at most). Prints each fix and the diff; --dry-run writes nothing. The fixes that guess content or remove something (an unused declaration, a placeholder text) are the editor's to offer, not applied — unless --only names their code. Style findings only with --vet. A pass that adds errors is retried fix by fix, keeping only those that add none. See fixes.
archec explain [<code>| <area>] What a diagnostic code ([naming], [unresolved]…) means, and the style guide's section on it. With no code, the areas the codes fall into (parse, names, types, links, timing, safety, style…); archec explain timing lists an area's codes, one line each; a near miss gets a did-you-mean. Long messages are cut after their first sentence in the terminal; --long prints them whole.
archec review <main.arche> [--threshold 0.3] [--suggest] [--dry-run] [--json] [--model id] Advice from Claude (claude-opus-5-5) on the traces. The checker knows both ends of a trace exist, not whether the link makes sense: this asks, one judgment per trace from what the two elements say about themselves (and the trace's rationale), and lists those below the threshold. --suggest also lists parts that very likely satisfy a requirement with no trace saying so. It is advice, kept apart: nothing of it reaches check, ci or a build, and the answers are not reproducible. It sends model text out: the kind, id, name and texts of each traced element go to the Anthropic API, only when this command runs; --dry-run prints the requests and sends nothing. Credentials: ANTHROPIC_API_KEY, or ant auth login. A refused request falls back to another model on the server side.
archec live-fix <ID> [main.arche] [--state .arche/live.json | --replay <trace>… [--deployment D]] [--dry-run] [--json] [--model id] Explain & fix: why a requirement, chain, thread or container that archec live sees failing fails, and the edits to the .arche files that would fix it, from Claude (claude-opus-5-5). It reads the latest live state (.arche/live.json beside the main file, which archec live rewrites at each refresh; --state another; --replay runs archec live --replay on the traces to their end), and sends the item, its evidence, what was measured and what archec analyze predicts of the chains, threads and containers involved, and their declarations with file and line. Each proposed edit replaces text found at its line (or within 5 lines); the others are dropped with the reason. --json: {explanation, edits: [{file, line, col, endLine, endCol, old, new, why}], rejected, notes}, what the VS Code extension applies as a previewed edit. Advice, like review: it sends model text out, only when this command runs; --dry-run prints the request and sends nothing.
archec mcp The compiler as a Model Context Protocol server on stdio, for AI agents. Its tools are the commands, one to one: check (diagnostics as JSON), fix (the fixes of each diagnostic as edits by line and column; apply: true applies the preferred ones as archec fix), explain, describe (the language reference of a keyword), outline (the declarations, nested, with file and line), analyze, format, diff, generate, build, and for a running system live_status (what archec live sees: .arche/live.json, or a replay of the traces given) and live_explain (the request archec live-fix would send — or, with send: true, Claude's answer). Paths are relative to the directory it runs in. The agent edits the .arche files itself and calls check: the compiler stays the judge. In Claude Code: claude mcp add archec -- archec mcp.
archec vet <main.arche>… [--json] Style, as go vet: long forms, property order and groups, declarations out of their set, naming. archec check leaves these out (--vet shows them there too). Exit 1 on a finding; archec fmt --write fixes the layout ones.
archec fmt <file.arche>… [--write|--check] [--simplify] [--extract-code[=file.ts|file.py]] Format (to stdout, or in place with --write; --check fails when a file is not formatted). --simplify rewrites the long forms in the short ones, with the same meaning; --extract-code moves the ```ts (or ```python) blocks into .ts (.py) files: one per component, in its language, or all in the file named. --edition 0.12: the project then says the edition it is written in (edition "0.12"), in which the old spellings are errors.
archec edit <main.arche> <element-id> [--set <key> <value>]… [--unset <key>]… [--label "…"] [--dry-run] One element's properties or label changed in its .arche file, by its id as archec export gives it (REQ-BRK-3, Vehicle.ctrl, BRAKE_STATUS). The value is written as arche-lang (--set period 20ms, --set satisfies REQ-1). Written only when the model has no more errors than before. What the Python package's Element.set runs.
archec convert-handlers <main.arche> --to typescript|python|arche [--component X] [--dry-run] The model's handlers rewritten in another language, in place: the blocks (their fence and indentation kept), the `code` files (`code "x.py"` becomes `"x.ts"`, a new file beside the old one, which is kept; to `arche`, each function a ````arche block on its element), the transitions' guards, and the project's `handlers` (the component's, with `--component`). From ```arche ```` it is exact; from Python and TypeScript statement by statement, through what the action language says (handlers.md). A statement that does not translate stays as a // TODO(convert): <original> comment (# in Python), listed with why ([convert-todo]) and reported by archec check until it is written. A message's fields: bare names in Python, msg.field in TypeScript (message ↔ msg.name). Nothing is written when the result has more errors than the model; --dry-run says what would be.
archec stubs <main.arche> [-o arche.d.ts|arche.py] arche.d.ts beside the model's .ts files (and a tsconfig.json when there is none), arche.py beside its .py files, so editors know Arche's API and the model's names (handlers.md).
archec patterns [-o patterns.md] The reference of every declaration (patterns.md).
archec ast <file.arche> The syntax tree (debugging).

Code scanning (SARIF)#

--sarif report.sarif writes the diagnostics as SARIF 2.1.0, which GitHub code scanning, GitLab and the SARIF viewers read. Each diagnostic code is a rule: its id is the code (unresolved), its help is what archec explain <code> prints. Each diagnostic is a result at its file, line and column, the file relative to the current folder: run archec from the repository's root. The levels: error → error, warning → warning, info → note, hint → none.

A GitHub Actions job that shows them on the pull request:

name: model
on: [push, pull_request]
permissions:
  contents: read
  security-events: write   # to upload the report
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm install -g arche-lang
      - run: archec check main.arche --sarif archec.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()       # upload even when archec check fails
        with:
          sarif_file: archec.sarif
          category: archec

Build and test#

Command What it does
archec build <main.arche> [-o <dir>] [--force] The Arche project folder (default ./arche-out); open it with arche --project <dir>. Refuses to overwrite code edited in Arche and not pulled back.
archec pull <main.arche> [-o <dir>] [--write] Code edited in the Arche app, back into the .py defs and code blocks it came from (a dry run without --write).
archec test <main.arche> [-o <dir>] [--plan <id>]… [--case <PLAN/CASE>]… [--coverage] [--allow <file>] [--sim web|python] [--ui-golden [--tolerance 0.1]] Build, then run the test plans in the Arche simulator (arche-cli): each case, the requirements it verifies, and with --coverage the states, transitions, messages and functions the run went through. --allow: the known failures, one PLAN/CASE per line. A case with a ui step (do press hmi.engage, expect hmi.mode.text == "…": ui) runs on the browser simulator — Arche's has no ui — in the same report, and needs no arche-cli; --sim web runs every case there, --sim python none. --ui-golden: then each screen compared with its golden, as archec ui snapshot.
archec run <main.arche> [-o <dir>] Build and run the simulation; each Python error is shown at its line in your sources.
archec sim <main.arche> [--for 10s] [--system S] [--deployment D] [--seed 1] [--keyframe K] [--json] [--html out.html] [--plant plant_bridge.py [--test [TP|TC]]]
archec sim <main.arche> --batch N [--seed 1] [--vary part.var=lo..hi]… [--threads k] [--print a,b] [--csv file] [--json]
Run the model's behaviour with nothing installed — no Arche, no Python: state machines (on a message, on "after 500ms"), deadlines and watchdogs, ```arche bodies and the Python the action language can say, ports and links, a deployment's periodic threads, on a virtual clock. Prints the trace (each message with its from and to port and its payload, each state change); --json the same as JSON. --html: one self-contained page that runs it live in a browser — the block diagram, each message a dot along its link, each part's state in its box; Play/Pause, Step (the next event) and Step by (a fixed time), a speed from 0.1× to 10×, a time scrubber back over what has run, Reset; a form per input port that sends one of its messages now, a push (step or pulse) on a physical network's sources (the network integrated in the page), live plots of states, variables, message fields and physical quantities; keys (space, →, Shift+→, ←, + / −, Home, R) listed on the page. What it does not simulate is said, never guessed. --plant: against a plant run elsewhere, in lockstep — mujoco/plant_bridge.py of archec gen --target mujoco (run with MUJOCO_PYTHON, else python3), or any command that speaks its JSON lines: every period the plant says, its sensors' messages come in as if their parts sent them, the model runs a period, and what it sent to the plant's parts goes back. A sensor's noise, resolution and range, an actuator's ctrl range, gain, lag and force-range and a port's latency are simulated (the trace shows each command an actuator takes and its output then), the noise drawn from --seed (simulation { seed }, else 1); --keyframe K starts from that keyframe of the system (and the plant from it). See the browser simulator. --batch N: N runs over worker threads, a part's variable that is a number drawn within each --vary range (its first value); for each run the messages, state changes and errors counted and every part's variables that are numbers at the end (--print keeps some), then their mean, min, max and σ — the same runs for a seed on any number of threads.
archec physics <main.arche> <System|Def> [--for 1s] [--step 1ms] [--every 100ms] [--integrator rk4|euler|implicit|trapezoid] [--tol 1e-6] [--print a,b] [--csv file] [--json] [--set name=value] [--keyframe K] [--seed 1] [--equations]
archec physics <main.arche> <System> --linearize [--at start|2s|x=1,…] [--inputs a,b] [--outputs y,z] [--lqr Q,R] [--json]
archec physics <main.arche> <System> --batch N [--seed 1] [--vary name=lo..hi]… [--threads k] [--print a,b] [--csv file] [--json]
A physical network run with nothing installed: parts whose ports have a potential and a flow (include "std/physics"), linked with no direction. Flattened (potentials equal and flows adding up to zero at each node), checked (as many equations as unknowns, each unknown given once — else the parts concerned are named), sorted into blocks, each solved in order — a linear loop once, a nonlinear one torn and solved by Newton's method on its tear variables — and the states integrated at a fixed step (RK4, --euler). --integrator implicit (backward Euler) and --integrator trapezoid (second order) solve each step by Newton's method, the Jacobian by finite differences: on a stiff network (a fast time constant beside a slow one) they keep a step RK4 blows up at. --tol makes the step adapt, the error on each step within it (relative and absolute): Dormand–Prince 5(4) for RK4, step doubling for the others; the number of steps is printed on stderr. Prints --print's variables (default: the states) every --every (a tenth of the run); --csv writes every variable at every step; --set gives an input (an in signal linked to nothing) or a part's parameter (motor.ra.r=2) its value; --equations prints the sorted equations and does not run. Index-0 only: states tied by an equation are reported, not reduced. --linearize: the network around an operating point, dx/dt = A·x + B·u, y = C·x + D·u, by central finite differences of the states' rates (as MuJoCo's mjd_transitionFD), to 7 digits. The point is the start (--at start), where a run leaves it (--at 2s), or states given (--at c.v=5). The inputs are the network's, or parameters of the parts whose equations use them (--inputs supply.v: a composite's parameter is passed on, so name the part that uses it); the outputs any of its variables (default: the states). Then the eigenvalues of A — each a time constant, or a pair's frequency and damping — and whether it is stable, marginally (an integrator: a position, an angle) or not. --lqr Q,R: the gain K of u = -K·(x - x0) that minimizes ∫ xᵀQx + uᵀRu, Q and R diagonal (one weight for all, or one each: 10:1:1,0.1), by the continuous Riccati equation, and the modes of the closed loop. --batch N: N runs, each with the parameters (motor.r) or inputs --vary names drawn within their range, spread over worker threads (--threads, by default as many as there are cores, 8 at most); each run's --print variables (default: the states) at the end, then their mean, min, max and σ. Run i draws from the seed and i alone, so a seed gives the same runs on any number of threads. --csv: one row a run; --json: the runs and the summary. An actuator's in signal with a gain, lag or force-range (or a type with a range) takes its command at <port>.command and acts through them, the lag a state of the network; a sensor's out signal is printed as it reads (its noise from --seed, its type's range, its resolution, its latency). --keyframe K starts from a keyframe of the system (its states, its actuators' commands); --linearize --at K linearizes there.
archec fit <main.arche> <System|Def> <data.csv|log>… --params a,b[=lo..hi] [--signals x[=series],…] [--inputs u=series] [--step 1ms] [--method lm|nelder-mead] [--json] [--html report.html] [--write] A physical network's parameters from what was measured (system identification). The data: a CSV (a header row, the time first or in a column t, a signal in each other column, a unit in brackets converted to SI: t (ms), w (rpm); an empty cell is no sample), or a log archec replay reads (candump, ASC, BLF, MCAP, JSON lines), decoded by the model, each numeric field a series MSG.field. A series drives the input (an in signal linked to nothing) or is compared with the variable it is named as: load.w, its flat name load_w, or MSG.load_w; --signals load.w=MOTOR.speed and --inputs src.u=PROBE.u say it when the names differ. A parameter is a part's (motor.r: its argument, else its definition's default), the system's own, or a parameter declaration; its bounds are its tolerance (or min/max), else its sign, or name=lo..hi in its unit. The network is run (RK4, the measured inputs linear between samples) from the model's start values, and the parameters found by least squares — each signal scaled by its spread — by Levenberg–Marquardt on a finite-difference Jacobian, Nelder–Mead when that makes no progress (or --method nelder-mead). Prints each value in its unit with its uncertainty (1σ, from s²·(JᵀJ)⁻¹), the RMS error of each signal before and after. Warns fit-no-influence for a parameter the signals do not change (not fitted) and fit-correlated for two that change them the same way (correlation above 0.999). --html draws measured, before and after per signal; --write puts the fitted values in the source (a part's argument replaced or added, a default or a parameter's value), checked first as archec edit does.
archec difftest <main.arche> [System] [--seed 1] [--steps 50] [--for 2s] [--target c] [--deployment D] [-o dir] [--json] Differential testing: the simulator (archec sim's runtime) and the code archec gen --target c writes, driven with the same inputs, must do the same thing. The inputs are random but repeatable (--seed): --steps messages from outside, each to a port of a part that receives it, with random field values, 1 to 20 ms apart. The C of each component is built with a harness (CC, else gcc, else cc) that plays them on a virtual clock, sends along the system's links with their latency, and does what happens at one instant in the simulator's order. Then the two traces — inputs, state changes, messages sent with their payloads (the C one decoded from its bytes), messages sent on a port linked to nothing — are compared in order and in time, and the first divergence is printed with the events before it. What one side cannot translate (Python the action language cannot say, TypeScript outside the portable subset, a body that waits) is listed as not compared. -o: where the C and its harness go (a temporary folder by default); --json: the inputs, both traces and the divergence. Exit 1 on a divergence, 2 when it cannot run (no compiler, the C does not build). A sensor's noise is drawn from the same seed on both sides (the C built with -DARCHE_SIM), and each command an actuator takes, with its output then (gain, lag, force-range), is compared too.
archec where <main.arche> [-o <dir>] "<error text>" Where an error Arche reports is in the sources: (Controller › Control loop, line 4) → ctrl.py:32.
archec where <main.arche> [--gen generated] [--from <dir>] "<compiler output>" | - A C, Rust or Go compiler's error (gcc, clang, rustc, go) in code archec gen wrote → the model element it comes from and its .arche line, through generated/.archec/genmap.json; a line in a USER CODE region says so. --from: the folder the compiler ran in (make in c/<binary>). With -, the output read from stdin, the element under each line (regeneration).
archec ci <main.arche> [-o <dir>] [--strict] [--coverage-min <percent>] [--require-tests] [--require-approval] [--junit <report.xml>] [--sarif <report.sarif>] What a pipeline checks, in one command: lint, format, ui (a binding, a press or a ui test step that does not hold — a button sending a message renamed since), timing, TARA, build, tests and coverage. One line per gate, a JUnit report with --junit, every diagnostic (style findings too) as SARIF with --sarif, exit 1 when a gate fails. Without arche-cli the cases with a ui step still run (on the browser simulator), the others are skipped, unless --require-tests. --require-approval: an approval gate, every requirement approved at what it says now (archec approve).
archec validate <arche-project-dir> An Arche project's YAML against the schema.
archec diff <a> <b> Two projects (folders, or a .arche entry) compared as data.

Analyse#

Command What it does
archec merge <base> <ours> <theirs> [--path p] [-o out] A three-way merge of .arche files by declaration, as git's merge driver: what one side changed is taken, a declaration both changed is merged inside (its properties by key, its members by kind and name), and only an item both changed differently is a conflict, marked with its name (`
archec verify <main.arche> [-o dir] [--json] The model checker (NuSMV or nuXmv, on the PATH or named by NUSMV) on each requirement's formal property — never brakes in Fault, always …, eventually …, a in X leads to b in Y — and on each state's reachability. A property that fails comes with its counterexample as a sequence diagram (<REQ>.mmd). Exit 1 when one fails, 2 when no checker is found. archec ci runs it as its verify gate. NuSMV is untimed: a within is left to the monitors, archec replay and --conflicts.
archec verify <main.arche> --conflicts [--tick 10ms] [--horizon 8] [--json] Requirements no implementation can satisfy together (realizability, as NASA's FRET checks it), with nothing to install: the formal properties and the EARS sentences, read over each part's states. The environment chooses the message each part receives at each tick (one, or none); the implementation then chooses each part's state, any of them (the machine's transitions are one implementation, not a limit), from its initial one. A set no choice of states survives is a conflict: printed as a minimal set (leave out any one and the rest can hold), with a witness — the inputs tick by tick, the obligations awaited, and at the last tick every state left with the requirement it breaks (req-conflict). Bounded: time is counted in ticks (the deadlines' common divisor, made coarser — each deadline rounded up — past 16 ticks per deadline; --tick sets it); eventually and leads to with no within are read as within --horizon ticks (8), so a conflict that names one may go away with a longer horizon; an EARS response with no within comes at the tick of its trigger; a response that sends a message is not read; orthogonal regions are read as one; a group of requirements whose game has more than 2 million moves is not solved (a note says so). Requirements that share no part are checked apart. Exit 1 on a conflict.
archec verify <main.arche> --meaning [REQ…] [--json] What each formal property (or the one an EARS sentence gives) says: a sentence, and two small timelines, one where it holds and one where it fails, as NASA's FRET draws them. archec doc --html and --md show the same under each requirement.
archec verify <main.arche> --modelica [--system S] [--results S_res.csv] [--case TC] [--tol 0.01] [-o dir] [--json] Each system with test plans, as gen --target modelica writes it, simulated by OpenModelica (omc on the PATH, or OMC=…; the package and the results in <dir>/modelica/), its test plans' expectations read on the results (at, within, never:, always:, a step's expect at 1s: …; the network's names or Arche's physics.x_y), and archec physics run on the same network beside it: each state's largest gap against --tol of its span. --results: a run made elsewhere (OpenModelica's CSV, or any with the time first and a column per variable by its Modelica or network name). Exit 1 when a case fails or the two disagree, 2 with no OpenModelica and no --results. See physics.
archec replay <main.arche> <log>… [--format f] [--deployment D] [--bus can0=<bus>] [--period-tolerance 50%] [--json] [--junit report.xml] [--strict] [--events] [--scenario out.arche [--from part,…]] Runtime verification: the real system's logs checked against the model. It reads candump (default and -L), Vector ASC and BLF, ROS 2 MCAP (chunks stored, lz4 or zstd), JSON lines ({"t", "msg", "from", "value"}, or {"t", "part", "state"} for a part's state) and distributed traces (OpenTelemetry OTLP JSON, Jaeger, Zipkin: each call from one service to another is a message, by the name archec observe gives it or its label); several logs are one trace. A CAN frame is the message its deployment's route gives that id, decoded by the layout the DBC and the generated C and Rust share; a ROS 2 message is decoded by its type (CDR, as --target ros2 writes the .msg). Then each check, with the time of its first violation: EARS requirements as monitors (the trigger, the while, the response within its deadline), formal properties (never, always, implies, leads to, eventually, and their within), a metric that is a message field against its limit, contracts (assume, guarantee … within 30ms after M), chains' budgets (the latest input taken as the cause: a lower bound), each field's range, each message's period (± 50 %), each port's stale-after. What reads a state needs the states in the log, else it is not checkable; a response the log ends before is inconclusive (--strict fails on it). JUnit like archec ci. --scenario out.arche writes the log as a test case for the simulator: what the parts --from names sent (default: the parts with no state machine), sent to the model at the times it came, and each state the log gives after the first, expected; include it and archec test shows where the model does not do what the system did. Exit 1 on a failure, 2 when a log cannot be read.
archec observe <trace>… [--states] [-o observed.arche] [--model main.arche] [--json] [--format otlp|jaeger|zipkin] [--system Name] [-k 2] How the running system behaves, recovered from its traces: OpenTelemetry's OTLP JSON (the file exporter's lines, or one object), a Jaeger JSON export, Zipkin v2 JSON. A span whose parent ran in another service is a call from that service to its own (the server span's name, the time from the client span's start to its end); a client span with nothing under it goes to its peer.service, db.system or server.address; a span in the same service is one of its steps (an fn). Writes a .arche (-o, else to stdout): a message per operation (POST /orders → POST_ORDERS, a gRPC Svc/Charge → CHARGE), a component and a part per service (outside sends what starts a trace), a link per caller and callee with each operation's count, p50, p95 and errors, and its latency the time on the wire; a scenario per way a request went (the traces clustered by the shape of their calls: calls that overlap are a par, the same call in a row a loop), with how many traces went that way and each reply's p50 and p95 or its error. --states: a state machine per service that waits on another, from what it received request by request (the request, then each reply), its states named by the replies they await, merged when they await the same and the next -k events are the same (k-tails); a // observed: comment says in how many traces each transition was taken. The file checks and draws (archec diagram <file> <scenario>, <System.part>.states). --model main.arche: the traces against a model instead — services no part is, calls no link or message of the model is, links never seen, a link's deadline against the time on the wire, a timeout against the replies, and what archec replay checks (EARS, formal, periods) on the calls as messages. --json for CI. Exit 1 when the model misses something or a check fails, 2 when a file has no span.
archec analyze <main.arche> [--json] Each deployment's timing: core loads, response times against deadlines, bus loads, memory, end-to-end chains. Exit 1 when a core is overloaded or a deadline or a chain budget can be missed.
archec timing <main.arche> <trace…> [--deployment D] [--json] [--junit report.xml] [--html report.html] What a run did, beside what archec analyze predicted. The traces are those archec gen --trace makes — arche-trace <ns> <kind> <name> <arg> lines from a UART, defmt or a log (anything before arche-trace on a line is skipped), or Chrome trace JSON — or any Chrome trace whose slices are named after the model's threads, or are the outermost on a thread so named. Per thread: activations, period and jitter, response time from its release (min / avg / p99 / max) and the time it ran, preemption taken out; per core: the share of the trace its threads were active; per bus: the load of the frames sent on it; per chain: the latency from a start to its end. A measurement worse than the prediction is flagged OPTIMISTIC (the analysis is wrong: a wcet too small, a blocking it does not see), one over a deadline or a budget MISS; either exits 1 (2 when no event matches the model). --junit: a test case per thread, core, bus and chain, as archec ci writes them; --html: one self-contained page. An event thread's response counts from when it starts; a chain whose start and end are in two traces takes their clocks as one.
archec live [main.arche] [--deployment D] [--replay <trace|dir>…] [--json] [--once] [--duration 10s] [--html report.html] [-o dir] [--no-compose] The living model: what a running system does turns the model's requirements, chains, threads and containers pass, fail or pending as it runs. Without --replay, the deployment's containers (the one --deployment names, else the first with containers) are generated (--target c --trace built with make LIVE=1, --target containerd, into -o, else a temporary folder), built with podman build, started with podman compose (plain podman run with --no-compose or without compose), their logs followed and podman stats polled every 2 s; the state is evaluated every second and the containers removed at the end (Ctrl-C, or --duration). --replay <file|dir>…: traces already written (arche-trace lines, a log with them in it, Chrome trace JSON), evaluated once. A chain or a thread fails on a miss (a budget, a deadline; worse than predicted only says so), a container over its memory-limit or stopped fails; a requirement fails when a runtime monitor says so (arche-trace <ns> monitor <REQ-ID> 1; an invariant, traced only when it fails, passes by its silence while other monitors report) or what satisfies it fails — a chain … { satisfies R }, a thread or a container running a part that satisfies R — passes when they pass, and is pending until then. Each state is also kept in .arche/live.json beside the main file (replaced whole at each refresh). --json: one state per line at each refresh (ndjson, nothing else on stdout), each item with its file and line; --replay may be given once per file; --once: run --duration (10 s), print the final state, exit 1 when anything fails; --html: the final state as one page.
archec study <main.arche> <id> [--json] A study over the parameters' tolerances: worst case (each output's range, and the corner it is at) or Monte Carlo (mean, σ, percentiles). It runs Arche's own study evaluation (vendor/arche.js), not a simulator; to vary a parameter through a run of the network or of the behaviour, use archec physics --batch or archec sim --batch.
archec parts [main.arche] [--provider nexar|digikey|mouser] [--offline] [--dry-run] [--json] Each part number of the bill of materials (product { vendor "…"; part-number "…" }), once, looked up at a distributor: its stock, its price breaks, its lifecycle (active, NRND, end of life), kept with the date in .arche/parts-cache.json. Nexar (Octopart): NEXAR_TOKEN, or NEXAR_CLIENT_ID + NEXAR_CLIENT_SECRET; DigiKey (Product Information v4): DIGIKEY_CLIENT_ID + DIGIKEY_CLIENT_SECRET; Mouser (Search API v1): MOUSER_API_KEY — the first whose keys are set, unless --provider; --url or ARCHE_PARTS_URL for another server. --offline: the cache only; --dry-run: the requests, keys left out, nothing sent. Exit 1 on a part at its end of life, NRND, out of stock or unknown. archec check then warns about those from the cache ([part-lifecycle], [part-stock]), with the date — only when the cache exists, and never on the network.
archec safety <main.arche> [--json] The safety analysis: each hazard with its ASIL and its rate, written and derived; the fault tree of each hazard with error … on …, derived from the error model of the parts (produces, contains, turns, from), with its minimal cut sets; the FMEA derived from it — each error source, where its error goes, the hazards it leads to; the STPA — each control action by the four types of unsafe control action, the UCAs with their hazards, constraints and loss scenarios. Exit 1 when the derived and the written ones disagree (fta-mismatch, fmea-mismatch) or the STPA has a gap (stpa-incomplete, stpa-no-path, uca-untraced).
archec tara <main.arche> [--json] The cybersecurity risk assessment (ISO/SAE 21434): each threat's impact, feasibility, risk and CAL. Exit 1 when a risk of 4 or 5 has no treatment.

Present#

Command What it does
archec animation list [category] [--json] Arche's animation templates — the ones its editor offers — by category: flows, timing, state machines, signals, hardware, mission, comms… animation v-x "…" from <template> { … } starts from one (animations).
archec animation show <template> What a template draws, each piece of data it reads (its shape, what it means, its sample), what it can take from the model (machine, scenario), and a starter block.
archec animation new <template> <id> [--label "…"] [--into file.arche] A starter animation block, its data the template's sample written in the language; printed, or added to a file.
archec animation preview <main.arche> [id] [-o page.html] [--open] A page that plays the animation (each one, without an id) in a sandboxed frame, as a slide shows it — its ${…} worked out against the constants and parameters, light or dark. Default folder: arche-out/animations.
archec ui <main.arche> [--json] [--id <component>] The product's user interface as archec resolves it (ui): each ui's device and theme, its screens and, element by element, what it is bound to (with its type and unit), what a press does, where the screens lead, the names it reads. --json prints the model itself (UiModel, src/ui.ts) — what a preview, a simulator or a code generator reads; the build writes the same to ui/<component>.json.
archec ui preview <main.arche> [--screen S] [--id <component>] [-o screens.html] [--png screens.png] [--chrome path] The screens drawn (ui): one self-contained page with every screen and dialog of each ui (or --screen S), the overlays over them, each element showing a sample value — the model's own first values (each part's variables and state at the start of a run of the browser simulator), its constants, and for a message not received yet a value within its type's range. A click on an element says what it is, what it reads and does, and the file and line it is written on. -o names the page (screens.html by default); --png also takes a picture of them by headless Chrome (--chrome, $CHROME, else the usual places). archec doc --html shows the same screens as figures.
archec ui snapshot <main.arche> [--update] [--screen S] [--id <component>] [--tolerance 0.1] [-o <diff dir>] [--chrome path] Golden screenshots (ui): each screen and dialog drawn by headless Chrome, as archec ui preview --png draws it, and compared pixel by pixel with ui/screenshots/<ui>/<screen>.png beside the main file; --update writes them. A screen with more than --tolerance percent of its pixels changed (0.1 by default; a channel within 24 of the golden is the same) fails, its diff written to -o (arche-out/.archec/ui-diff/<ui>/<screen>.png: the golden faded, what changed in red, and <screen>.now.png). Without Chrome it says so and compares nothing (exit 0). Exit 1 when a screen differs or has no golden.
archec story list <main.arche> The stories, and how many steps each has.
archec story export <main.arche> [story] [-o story.html] [--lang en] [--open] A story as one HTML file, for someone with no Arche: its steps in order, their text in the language asked (a translation, else as written), the animations they play running in sandboxed frames with their data worked out, the pictures, and a step on a system (its canvas, or its file) that system's block diagram; what only the app shows is named (In Arche: the memory map · KRIA260.yaml). Arrows, Home/End, n notes, f full screen; p (or #play in the address) plays it by itself, each step for its dwell (8 s without). Nothing is fetched. Default: arche-out/<story>.html.
archec animation render <main.arche> [id] [-o out.gif|dir] [--theme dark] [--seconds s] [--fps n] [--width px] [--chrome path] A GIF of the animation, recorded the way Arche's .pptx export records one (its own frames, painted by the drawing), in headless Chrome or Chromium (--chrome, $CHROME, or the usual places); one cycle of its duration (3 s without) at its fps (10).

Requirements#

Command What it does
archec baseline <main.arche> [--name v1.0] [--sign [--key ~/.ssh/id_ed25519]] Freeze the requirements (baselines/<name>.json); the linter then marks the links to a reworded one as suspect. --sign: an SSH signature beside it (<name>.json.sig, ssh-keygen -Y sign, namespace arche-baseline) with --key, else ARCHE_SIGNING_KEY, else git's user.signingkey when gpg.format is ssh.
archec baseline <main.arche> --verify [name] Each baseline's signature (or one) against reviews/allowed_signers (git's allowed-signers format: qa@example.com ssh-ed25519 AAAA…). Exit 1 on a bad signature or a signer not listed.
archec approve [main.arche] <id…> --as <name> [--role <role>] Sign-off: records in reviews/approvals.yaml who approved each element (a requirement, a case, a test plan, Car.brakes…), in which role, when, and a fingerprint of what it said — a requirement's wording as a baseline keeps it (a status or an owner changing does not undo it), another element's declaration without its comments and layout (a part's with its definition). One line per approval, sorted, for git. Approving again replaces that person's approval. --as defaults to git's user.name; the model to main.arche here.
archec approvals [main.arche] [--stale] [--json] The approvals, each current, stale (the element changed since: approve it again) or gone. --stale: only those, exit 1 when there is one. archec cert shows who approved each requirement (a stale approval is a gap) and the baselines' signatures; archec ci --require-approval fails while a requirement has no current approval.
archec changes <main.arche> [--since v1.0] [--json] Requirements added, removed and changed since a baseline (the newest by default), and the suspect links.
archec issues sync [main.arche] [-o arche-out | --results test-results.json] [--only cases|requirements] [--dry-run] An issue in Jira (REST v3), GitHub or GitLab for each case the last run says failed (.archec/test-results.json, as archec test writes it) and each requirement that is not verified — nothing verifies it, its cases failed, or none of them ran. The issue's key is written on the element, in its place among the properties: issue "CAR-128" (acme/car#7 on GitHub and GitLab). An element that has one gets its issue updated; one whose problem is gone gets a comment, and on GitHub and GitLab its issue closed (a Jira workflow is the project's own). The tracker is in issues.yaml beside the model — tracker: jira|github|gitlab, url, project (the Jira key, owner/repo, the GitLab path), issue-type, labels — or --tracker, --url, --project; the token in the environment: JIRA_EMAIL + JIRA_API_TOKEN or JIRA_TOKEN, GITHUB_TOKEN, GITLAB_TOKEN. It sends model text out (the ids, names and texts of those elements), only when this command runs; --dry-run prints the requests (the token left out), sends nothing and writes nothing.
archec issues list [main.arche] [--json] Every requirement, plan and case with an issue.
archec polarion <workitems.json> [--project main.arche] [-o out.arche] [--config polarion.yaml] [--document "Name=ID"…] [--module text…] [--id puid] A Polarion project's work items, from a JSON export of its REST API, as requirements — any project: the standard fields known, a custom field recognised by its name or said in polarion.yaml, anything else kept as attr. A link between them in a derives role (parent, satisfies, refines…) is derives, the others attr polarion-links. Importing.
archec polarion pull [main.arche] [-o out.arche] [--save workitems.json] [--url u] [--polarion-project P] [--query q] [--dry-run] The same, read from the server named in polarion.yaml (every page of the query), the token POLARION_TOKEN from the environment; the requirements are written to out: — pulling again rewrites them. --dry-run: the request, not sent.
archec reqif <main.arche> [-o out.reqif] [--document D] The requirements as ReqIF 1.2 (DOORS, Polarion, Jama…).
archec reqif <in.reqif> [-o out.arche] A ReqIF file's requirements in arche-lang.
archec doc <main.arche> [-o spec.tex|spec.html|spec.md] [--html|--md] [--no-diagrams] The specification: LaTeX, one self-contained web page, or Markdown. The page draws each view (a viewpoint with include lines) and plays each scenario on its system's blocks (SVG, no script); the Markdown has them as Mermaid. --no-diagrams leaves them out. --provenance adds a chapter on who wrote the code (see provenance).
archec doc <main.arche> --template <file.docx|file.odt> [-o out.docx] Your own Word (.docx, .dotx) or LibreOffice (.odt, .ott) document, its placeholders filled with the model: {{ requirement REQ-1 .text }}, loops that repeat table rows ({{#each requirements where tag=safety}}…{{/each}}), {{#if}}, {{ count … }}, and {{ diagram Car }} for a system's block diagram (SVG, with a PNG for older Word). A placeholder Word cut into pieces is read whole. One that cannot be filled is marked in the document and printed; exit 1 then. See template documents; the output defaults to <template>-filled.docx.
archec diagram <main.arche> [view] [--format mermaid|d2|svg] [-o file] [--md] [--auto] [--list] [--all -o dir] [--max-links N] A diagram as text other tools draw, or as a picture: a system or a component (Car, Car.adcu) as a flowchart, a state machine (Car.adcu.states) as a state diagram, a scenario (emergency-stop, one sequence: emergency-stop.detect) as a sequence diagram, a view (braking, a viewpoint with include lines) as the blocks it picks. Mermaid by default (GitHub draws it in a README or a pull request; --md fences it), D2, or SVG laid out by ELK as the editor lays it out — a block keeps the place it was given (at, a canvas line, or main.layout.json beside the model, where the editor keeps the places dragged in a view), --auto lays everything out. The format also follows -o's extension (.mmd, .d2, .svg). --play (with SVG) plays a scenario on its system's block diagram: each step lights its two blocks and the link between them, the message moving along it, a step every 1.6 s, in SMIL — no script, so it plays where an image plays. --list lists the diagrams, --all -o dir writes each one. --overlay provenance colours each block by who wrote its code (see provenance). --max-links N: a block diagram draws its N heaviest links, among those whose label says a weight ("12 imports", "3 calls"; the others are all drawn) — each block's heaviest first, so none is left alone — and says "+K weaker links not drawn"; 30 by default for a model archec recover wrote (its system's prop recovered), none otherwise; --max-links 0 draws all. Exit 2 when the diagram does not exist.
archec qualify [--use check,gen-c|all] [--config qualify.yaml] [--asil A-D] [--dal A-E] [--standard iso26262|do330|both] [--results results.json | --no-run] [-o dir] [--html] [--repo dir] [--strict] [--list] The tool-qualification kit for the archec features a safety project relies on, from the self-model (examples/arche-lang: the use cases, the requirements on archec that refine them, the test cases that verify those), a run of those tests (each test's result, the version, the git commit, the hashes of dist/, the environment) and the docs' known limits: the ISO 26262-8 §11 tool classification (TI, TD, TCL per use case) and qualification report, the DO-330 Tool Operational Requirements and their verification cases and results, a configuration index, the known problems; Markdown, --html too. --list lists the use cases. TI2 and TD3 unless the config says otherwise, with your reasons. Exit 1 when a test failed (--strict: or a requirement is not shown). It supports a qualification; it does not certify archec. See qualification.
archec cert <main.arche> [--standard iso26262|do178c] [-o file.md] [--strict] The trace matrix a standard asks for — goals or requirements with their ASIL or DAL, derived requirements, the elements that satisfy them, the tests that verify them — and its gaps; --strict: exit 1 when there is one.

Generate#

Command What it does
archec gen <main.arche> --target <t> [-o generated] [--deployment D] [--check] [--trace] [--monitors] Source code from the model. embassy: a Rust crate per binary (channels, CAN codec, state machines, tasks; your app.rs kept). sbom: a CycloneDX 1.5 bill of materials (sbom/bom.cdx.json) — the hardware with its vendor and part number, the libraries at the version arche.lock names, a firmware per binary on its processor. proto, ros2, dds: the messages, structs, enums and unions (and an interface's operations as a service) for protobuf (proto3), ROS 2 (.msg, .srv, as the ament package <project>_msgs) and DDS (OMG IDL 4); ros2 with a deployment that says packaging ros2 (the one --deployment names, else the first) also writes ros2_nodes/: an ament_cmake package per binary on a Linux processor — an rclcpp executable per process, a node per part around its C module (publishers, subscriptions, services, a timer per periodic thread, parameters from its props, QoS from the links) — and <deployment>_bringup with its launch file; colcon build in the output folder builds them. gazebo: the plant of that deployment in Gazebo (gz sim Harmonic), as the package gazebo/ — an SDF world with a link per sensor, actuator or part with a mass (gpu_lidar, camera, imu, navsat sensors where the part is one), the ros_gz_bridge config, sim_adapter.py (Gazebo's standard messages into the model's, the nodes' commands into gz topics) and a launch file that starts it all with the nodes on simulated time; the world and the adapter are yours once written. mujoco: the plant in MuJoCo (mujoco/<system>.xml, MJCF) — a body per part with a mass or a shape, nested as the parts are and placed by their joint … at, its geom from its shape with its mass, its hinge, slide, ball or free joint, a sensor per kind sensor part (jointpos, jointvel, accelerometer, gyro, force, torque, touch, rangefinder, framepos, framequat, from its name or the unit of what it sends), an actuator per kind actuator part on the joint of the body it is in (motor, position or velocity from the unit of the field that commands it; on a free body, a thruster on a site), the timestep from the solver step, a keyframe from the joints' = value — and mujoco/plant_bridge.py, the commands into data.ctrl and data.sensordata into the sensors' messages at their period: --stdio for archec sim --plant, --csv out.csv [--control seq.csv] for a fixed control sequence, --viewer, --ros2 a ROS 2 node on the topics of gen --target ros2 (see MuJoCo). tests: a test case per transition a message triggers (the shortest way to its source, then its trigger and the state after) and per received message at its limits; the cases with a TODO are listed in tests/generated.allow for archec test --allow. ears-tests: a test case per EARS requirement (the trigger sent by the part wired to send it, the response expected in time). go: a Go program per binary that says language go, on a Linux board of the hardware store: the board's adaptor and a driver per device linked to it (bus and address, or pins, from the links), the parts it runs (variables, arche bodies translated, state machines, messages on channels), a goroutine per thread, a link to a part another go binary runs as JSON over HTTP (`net.go`, each binary on its port from 9001, `ARCHE_LISTEN`/`ARCHE_PEER_<BINARY>` to move them; tested in `net_test.go`), `user.go` yours; the store's Go code it uses is copied in, so it builds with nothing outside Go. On a host (a processor with `compute { os linux }` and no board), the same without the hardware. The parts' HTTP handlers (`handler GET "/items/{id}" -> item`) become a server (`http.go`: the routes `--target openapi` describes, each call run on its part's thread, on `ADDR` or the port of the part's `attr url`, else :8080) and `http_test.go`, a test of each route for `go test`. `ui-web`: the product's screens (each `ui`) as a web app that runs on its own — `ui-web/index.html`, `ui.js`, `ui.css`, `ui.json`: by default the model simulated in the page (a press sends its message into the run), with `?ws=ws://host:port` the values from a WebSocket instead (see [ui](ui.md#the-web-target-gen---target-ui-web)). `c`: C99 — the types and their codecs (the same bytes as the DBC and the Rust), a module per component (its variables and state, its functions with arche bodies translated, goto, fire for its transitions, its after timers, deadlines and watchdogs, in the order the specification gives), the send functions yours to wire, and with a deployment a FreeRTOS task per thread. --monitors: the requirements as run-time monitors in each binary (EARS responses within their deadline, formal invariants, eventually … within and … leads to … within, one flag and one deadline each), the checks archec replay makes on a log; a violation calls arche_monitor_violation, yours in monitor_hook.c; no heap. With --trace, each verdict is also a trace line, `arche-trace monitor <1 fail
archec gen <main.arche> --target c|embassy --build [--lint] [--sarif f] Builds what was just written (codegen quality): c with each binary's Makefile (or each module on its own without a deployment) and -std=c99 -Wall -Wextra -Werror -pedantic, embassy with cargo build. --lint adds cppcheck's MISRA C:2012 addon and clang-tidy for C, cargo clippy for Rust — each only when installed, a missing one said. Each finding is printed at the model element its generated line comes from (main.arche:57 error [cc-unused-variable] … — c/controller_ports.c:6 in controller_send_cmd (port cmd of Controller)); --sarif writes them as SARIF 2.1.0 at those elements. Exit 1 when the build fails.
archec gen <main.arche> --target c-tests [-o generated] [--run] [--coverage] The model's test plans as C unit tests of the generated C (codegen quality): under c-tests/, the component modules, arche_tests.c (difftest's harness — the parts on a virtual clock, the links' latency — and a function per case) and a Makefile (make test, make coverage). A case's send(...), a part's variable set, part.state == "S", sent("MSG") and expressions are translated; a case with anything else is a SKIP that says why. --run builds and runs them (PASS/FAIL/SKIP per case, exit 1 when one fails) and writes c-tests/results.json as archec test writes its results; --coverage with gcov reads the lines that ran back as the states, transitions and functions covered, reported as archec test --coverage does.
archec gen <main.arche> --target c --defensive [-o generated] Defensive C from the model (codegen quality): each message's ranges as <msg>_in_range(), and with a deployment each input of a binary checked as it is dispatched — a value out of its range rejected (not clamped), an input quiet for longer than its port's stale-after (else its message's period × 1.5) flagged stale (<binary>_input_stale()), a wire format's wrong checksum and its counter repeated (rejected) or jumping (lost messages, counted), as AUTOSAR E2E does; each counted in arche_errors and logged once until the input is good again. Opt-in: it changes what the parts see.
archec gen <main.arche> --target trace-matrix [-o generated] [--results r.json]… The traceability matrix (codegen quality), trace-matrix/matrix.md and matrix.csv: each requirement, the model elements that satisfy it, the C generated for each (file, line, function), the cases that verify it and their last result — from --results files, else arche-out/.archec/test-results.json (Arche's simulator) and <out>/c-tests/results.json (the C) — then the gaps (no element, no code, no case, a failing or unrun case).
archec gen <main.arche> --target modelica [-o generated] The systems whose parts have equations or physical ports as a Modelica package (modelica/<project>.mo) and an OpenModelica script per system (simulate_<System>.mos, results as CSV): a std/physics part as the Modelica Standard Library 4.0 component it is (Resistor → Modelica.Electrical.Analog.Basic.Resistor, HeatCapacitor → Modelica.Thermal.HeatTransfer.Components.HeatCapacitor…), the other components models with their equations, physical ports as MSL connectors, signals as RealInput/RealOutput, links as connects, a fn main that waits and sets as when clauses, an experiment per system from its test plans and its solver step. The table, and what is left out, in physics.
archec gen <main.arche> --target ui-lvgl|ui-slint [-o generated] [--deployment D] Each ui { } as code for a device (ui). ui-lvgl: ui-lvgl/ui_<id>.c/.h for LVGL 9 — its screens, widgets, theme, the bindings read from the part's struct of --target c (each message it reads kept by the part, the parts beside it copied by the wiring), the events calling the part's send functions — and ui_<id>_task.c (written once: lv_init, your display, the loop); a binary built with -DARCHE_UI starts it. ui-slint: a crate per ui under ui-slint/<id>/ — the .slint file, the Rust glue (Received, Sent, the events) and a std host main.rs (written once). An element a target makes only in part is a note; none is dropped.
archec gen <main.arche> --list The targets: the built-in ones, and the project's own generators (generator … { templates | script | command }) with their kind and where they are written.
archec gen <main.arche> --target <generator> [-o generated] [--deployment D] [--option k=v]… [--check] Runs a generator of your own (generators): the generator model in, its files into <out>/<output>/ (its id by default), never outside, never over a file it marks keep that exists. --option sets one of its options for the run (JSON when it reads as JSON). Its problems are printed at the elements' lines; exit 1 on an error.
archec generator new <id> --templates|--script|--command [--label "…"] [--into main.arche] A generator that works, to start from: its files in generators/<id>/, its declaration added to the file.
archec gen <main.arche> --target canopen|j1939|mavlink|someip|openapi|asyncapi [-o generated] [--deployment D] Protocol descriptions (integration targets). canopen: a CiA 306 EDS per binary on a CAN bus, a transmit PDO per frame it sends and a receive PDO per frame it takes (the route's id the COB-ID, the period the event timer), the messages as objects from 0x2000 mapped at their bits; node id and identity from attr canopen_node_id, vendor_id, product_code. j1939: per bus with 29-bit routes, the parameter groups — PGN, priority, PDU format, destination or group extension, source address read from the id — with an SPN per signal at its J1939 position, length, resolution and offset (attr spn on the field gives its number). mavlink: the catalog as a MAVLink 2 dialect for mavgen — a message per message, a field per signal (arrays of scalars as arrays, enums with their entries, units MAVLink knows), ids from attr mavlink_id, else numbered from 65536 and listed. someip: the SOME/IP services as JSON — an interface a port provides (its operations methods, the messages its provider sends events), an Ethernet port that publishes, each instance with its binary and its consumers, the data types; ids from attr someip_service_id, someip_method_id, someip_event_id, else numbered and listed. openapi: an OpenAPI 3.1 document per component with HTTP handlers — an operation per handler, path, query and body parameters from its function, the return type the answer. asyncapi: an AsyncAPI 3.0 document per system — a channel per sending port at its topic, send and receive operations, a server per bus. What the model does not say is in the notes.
archec gen <main.arche> --target cmake|west|platformio|ci [-o generated] [--deployment D] Build systems around the C of --target c, written into the same folder (integration targets). cmake: a project per C binary (its model a library, its runtime POSIX on a host, FreeRTOS cross-compiled), a toolchain file from each microcontroller's core, port.cmake yours for the kernel, startup and linker script, and cmake/CMakeLists.txt that builds every C binary on the host. west: a Zephyr application per binary on a Zephyr board — its CMake, prj.conf, the devicetree overlay and a west.yml pinning Zephyr and the board's HAL. platformio: platformio.ini per binary on a board PlatformIO knows, its platform, board and framework, the C as its sources. ci: a GitHub Actions workflow and a GitLab pipeline — archec check and archec ci, archec gen --check per target the deployment uses, the C built with CMake and run, each Rust binary built with cargo.
archec gen <main.arche> --target flash [-o generated] [--deployment D] Per binary on a microcontroller (the lab): flash/<binary>/flash.sh [image], which flashes it with the first of its chip's tools installed (STM32: probe-rs, OpenOCD; nRF52: probe-rs, nrfjprog, OpenOCD; RP2040: picotool, probe-rs, OpenOCD; ESP32: espflash, esptool; TOOL= chooses), the image from cargo's target folder or build-<binary>/; and flash/<binary>/monitor.sh, which reads its --trace output for ARCHE_DURATION seconds — a C binary's from the board's UART at the link's bitrate, a Rust one's defmt over RTT with probe-rs — then runs archec timing and archec live --replay on it.
archec gen <main.arche> --target bench [-o generated] [--deployment D] The hardware test rack of a deployment (the bench): bench/<deployment>.yaml — each bus with its type, bitrate, the rack's interface, the nodes on it and the frames it carries; the devices under test with their board, chip, flash and monitor scripts; the power supplies and what they feed; the IO links — and per CAN bus setup_<bus>.sh (SocketCAN at its bitrate, CAN FD, or a vcan) and bench_<bus>.py (python-can: the frames named after the model and checked against their periods, --as <binary> to stand in for a missing node, --interface virtual without hardware).
archec gen <main.arche> --target regmap [-o generated] The register map of each part with addressed memory blocks, in regmap/<part>/: a C header (offsets, field masks and shifts, access macros on a base, static asserts on the layout), an AXI4-Lite register bank in VHDL and in SystemVerilog (rw/w registers out, r values in, a write strobe per element, large blocks as RAM ports, reset values, SLVERR elsewhere), IP-XACT (IEEE 1685-2014), SystemRDL 2.0 and a Markdown memory map (register maps).
archec gen <main.arche> --target cpp [-o generated] [--deployment D] C++17 in cpp/: constants as inline constexpr, enums as enum class, unions as std::variant, optional fields as std::optional, messages as structs with encode/decode on the C's wire layout (the same bytes); a class per component — its variables, its functions (```arche bodies and the Python the action language can say translated), its state machine as an enum class State and a switch (go_to, fire, on-exit and on-enter, after timers, watchdogs, deadlines), what it sends as std::function members; with a deployment, a main.cpp per binary that says language cpp (each binary when none does) with a std::thread per thread of the model, the links inside the binary wired and the others through hooks.cpp (yours); a CMakeLists.txt (C++).
archec gen <main.arche> --list The targets: the built-in ones, and the project's own generators (generator … { templates | script | command }) with their kind, the targets they run after or read (builtins), where they are written, and their declared options (type, default, values, what each is for, the value set when it is not the default).
archec gen <main.arche> --target <t> [--no-hooks] A target's files go through the project's hooks on it — the generators that say after <t> (a built-in target or one of the project's), in the order they are written — before they are written or --checked: each gets the files and returns what it changes (generators). --no-hooks: the target's files as they are.
archec gen <main.arche> --target <generator> [-o generated] [--deployment D] [--option k=v]… [--check] Runs a generator of your own (generators): the generator model in, its files into <out>/<output>/ (its id by default), never outside, never over a file it marks keep that exists. --option sets one of its options for the run (JSON when it reads as JSON; as the option's type when it declares one, and held to it). Its problems are printed at the elements' lines; exit 1 on an error.
archec generator new <id> --templates|--script [--ts]|--command [--label "…"] [--into main.arche] A generator that works, to start from: its files in generators/<id>/, its declaration added to the file. --ts: the script in TypeScript (generate.ts), typed by generator-model.v1.d.ts written beside it.
archec generator types [-o generator-model.v1.d.ts] The generator model and a script's ctx as TypeScript declarations (schemas/generator-model.v1.d.ts), for a script "gen.ts".
archec gen <main.arche> --target <t> [--move <old>=<new>]… [--orphans ok] Your code in a region the new code no longer has stops the write: nothing is written, exit 1, each stranded region shown with the new regions it may belong to. --move puts a region's code into another; --orphans ok lets it go to <file>.orphans. A rename made with the editor's Rename or archec refactor rename carries the code by itself (arche.renames.json), and a clear rename by hand is recognised (regeneration).
archec refactor rename <main.arche> <element> <new-name> [--dry-run] The element renamed everywhere (its declaration, every reference, its uses in its component's code), as the editor's Rename does, and recorded in arche.renames.json so archec gen carries your code to the new name.
archec gen <main.arche> --target <t> --diff What a write would change, as a unified diff (your USER CODE regions carried, as a write carries them); nothing written, exit 1 when something would change. --check lists the files instead. Generated C, Rust and Go keep the code between USER CODE BEGIN <id> / END <id> markers each time they are written again; a region the model no longer gives goes to <file>.orphans (regeneration).
archec generator model <main.arche> [--deployment D] [-o model.json] The generator model, version 1 — what a generator reads (schemas/generator-model.v1.json).
archec generator test <main.arche> <id> [--update] [--expected dir] The generator's output against the files you approved (expected/<id>/ beside its declaration): each file missing, changed (at its first different line) or new; exit 1 on a difference. --update approves the output as it is.
archec plugin list [main.arche] [--json] The plugins found — the project's plugins/<name>/plugin.arche, the libraries of kind plugin it uses (the Store's among them), ARCHE_PLUGINS, the ones built into archec (lib/plugins) — each with where it comes from and the generators, importers and exporters it brings, their options, and what needs approval; the errors in a plugin's own declarations (exit 1). Without a project: the built-in plugins and ./plugins (plugins).
archec plugin approve <main.arche> <plugin> [--revoke] Every script and command a library's plugin brings, listed with its code, then each recorded in arche.lock at the library's fingerprint (acme/importer:kv, acme/exporter:x, acme/gen); a change to the library asks again.
archec fmi <main.arche> <System|Def> [-o dir] [--build] An FMI 2.0 co-simulation FMU of the equations (sources; --build compiles and zips it). A physical network goes in sorted and solved, a nonlinear loop by Newton's method in C; its states, the parts' variables and out signals are outputs, an in signal linked to nothing an input.
archec kicad <main.arche> [System] [-o file.net] A system's wiring as a KiCad netlist (.net, the s-expression format pcbnew reads): each part with signals a symbol with no footprint (a board A1, the others U1), its pins those of its ports (uart2.TX/PA2, a port type's wires, CAN_H/CAN_L, SDA/SCL, V+/GND); a net per signal — TX to RX crossed, the same signal otherwise, everything on a kind bus by signal (chassis_can_CAN_H), every GND one net. The system is the one named, else the deployment's platform. See boards.
archec sysml <main.arche> [-o model.sysml] The architecture in SysML v2 textual notation.
archec export <main.arche> [--json] [-o model.json] [--compact] The resolved model as one JSON document, for scripts: every declaration an element with its id (its path, Vehicle.ctrl; a requirement its own id; one with no name its parent's id and kind, Vehicle/link1), kind, file and line, parent and children, type, definition, direction, unit and properties — a quantity as {"value": 10, "unit": "ms"}, a name as {"ref": "REQ-1", "id": "REQ-1"} with what it resolves to; each link's and transition's ends resolved; the traces once each, from whatever wrote them (satisfies, verifies, derives, satisfied-by, a trace, a requirement inside a component); and the diagnostics. Written even with errors (exit 1). The Python package lib/python/archelang reads it: archelang.load("main.arche").requirements.untraced() (Python).
archec export <main.arche> --format <exporter> [-o out.x] [--option k=v]… [--deployment D] The model as a file of another tool, by a plugin's exporter (the generator model in, its files out): one file to -o (or stdout), several into -o as a folder. Without --format, -o's ending picks the exporter whose extension it is; -o model.json stays the JSON. Its problems are printed at the elements' lines; a library's script runs once approved (plugins).
archec api serve <main.arche> [--port 9000] [--host 127.0.0.1] The model over the OMG Systems Modeling API (SysML v2 REST/HTTP), read-only, for a SysML v2 tool or a script: /projects, its branch, /commits (git's history of the project's folder, newest first, and the files as they are when they differ; a model outside git is one commit), /tags (each baseline, at the commit that added it), /commits/{c}/elements[/{e}], /roots, /elements/{e}/relationships?direction=in|out|both, and POST /query-results with a Query (PrimitiveConstraint: property, operator = < <= > >= instanceOf, value, inverse; CompositeConstraint and/or; select, scope). Lists are paged by page[size], page[after], page[before], with a Link header. An element's @id is the same in every commit; elements are typed as archec sysml writes them (a definition a PartDefinition, a part a PartUsage, a port a PortUsage, a link a ConnectionUsage, a requirement a RequirementUsage, a trace a Dependency), with what archec knows of each under arche (its id, kind, file, line, properties); ?kind= and ?type= filter /elements (archec's own). The memberships between elements are not elements: owner and ownedElement say the ownership directly.
archec capella <main.arche> [-o dir|project.zip] A Capella 6.1 project (one Arcadia level per layer), checked against Capella's metamodel; what Capella cannot hold is listed.
archec capella <model.capella|folder|project.zip> [-o dir] [--prefix p] [--layers oa,sa,la,pa,epbs] [--no-diagrams] [--project dir] A Capella model in arche-lang, through the Arche project the app's Capella import makes.

Import#

Command What it does
archec import <arche-project> [-o <dir>] An Arche project rewritten in arche-lang, built back and compared until it gives the project back exactly.
archec import <plant.fmu> [-o plant.arche] An FMU as a component whose behaviour it is, run in the simulation.
archec import <model.sysml> [-o out.arche] A SysML v2 textual model in arche-lang; what has no equivalent is kept as a // sysml line N: comment and a note.
archec import <bus.dbc> [-o bus.arche] A CAN DBC in arche-lang, as gen --target dbc writes it back: each frame a message with its wire format (start bit, length, byte order, sign, factor, offset, range, unit, value tables as enums, cycle time as period, comments as labels), each node a component with a port per frame and a processor on the bus, each frame a route at its CAN id. See importing.
archec import <types.asn> [more.asn…] [-o types.arche] ASN.1 type definitions (a subset) in arche-lang: each module a package, its IMPORTS found among the files given; SEQUENCE a struct (a message when no other type uses it), CHOICE a union, ENUMERATED an enum, INTEGER ranges, SIZE. See importing.
archec import <robot.urdf|scene.xml> [-o robot.arche] A robot from URDF or MuJoCo's MJCF (.xml by its <robot> or <mujoco> root): its bodies nested as parts with mass, shape and joint (what gen --target mujoco writes back), its actuators and sensors as kind actuator / kind sensor parts, a commands part sending to the actuators; what they do not say as prop records. MJCF's includes and default classes resolved, the first keyframe as each joint's start. What has no place is a // urdf: or // mjcf: comment and a note. The result is built at once. From MJCF, a sensor's noise and cutoff and an actuator's forcerange and filter are said as the ports' noise, range, force-range and lag, and each <key> is a keyframe of the system.
archec import <file> [--importer id] [-o out.arche|dir] [--option k=v]… [--allow-read dir]… [--project main.arche] A file of another tool through a plugin's importer: the one whose extensions end the name (a built-in importer keeps its own endings), or --importer. A script reads only the file's folder, its plugin's, the folders it declares with reads and --allow-read. What it returns is written — one file to -o x.arche or stdout, several into -o as a folder — and checked as archec build would; its warnings at the lines of the file. The plugins are those of --project, else of main.arche here, else the built-in ones and ./plugins (plugins).

Refactor#

Rewrites that keep the project the same: each one writes nothing unless the project builds the same. The old names (archec move-traces, archec name-components, archec translations, archec extract-component) still run, with a note.

Command What it does
archec refactor translations <main.arche> --extract <lang> [-o file] [--dry-run] The inline translations of a language ("Démarrer" en "Start") moved into one translations en { … } file, included by the main file, so the model's files read in one language. A text is named by its place (REQ-1.text) or, when no path names it (a sequence step, a branch, a procedure), by what it says ("texte" "text"); entries are grouped under the file they come from. A text stays where it is when it has several languages, or when the same words are also written without a translation (an entry by its words would translate them too). Written only if the project builds the same.
archec refactor name-components <main.arche> [--dry-run] A component an import named by its Arche id (c-1793752253957) gets a name from its label — component flash_memory "FLASH_MEMORY" as c-1793752253957 — and every path that names it says the name; the id stays Arche's. Written only if the project builds the same.
archec refactor move-traces <main.arche> [--dry-run] [--list] Each trace written apart, moved to where it starts — verifies on the case, the plan or the scenario, satisfies on the part, refines on the requirement — with its id (verifies REQ-1 as t-7); an address written as a string becomes a path when it names something of the project. Written only if the project builds the same traces; --list says why each other one stays.
archec refactor extract-component <main.arche> <A.b> [--name Def] [--also A.c,A.d] [--folder dir] [--dry-run] A component moved into the component library: a folder of its own, copyable into other projects; nothing changes unless the project builds the same.

Code and model#

Command What it does
archec recover <src-dir> [-o recovered.arche] [--lang ts,js,go,py,c,rust] [--depth N] [--min-imports N] [--std] [--json] [--graph gitnexus] The architecture of code as arche-lang, for code nobody drew (or an AI wrote). Each file's imports are read by a small scanner per language: TS/JS import, export … from, require, import(); Go import with the module path of go.mod; Python import and from … import, relative or by package; C/C++ #include "…" (folder, include/, then name); Rust mod, use crate::/super::/self::. Folders of dependencies and builds (node_modules, vendor, dist, build, target…) and files that say they are generated are left out. A part is a folder; folders nest down to --depth levels (2); a folder's own files, when there are more than 12, are cut into groups: the files most of them import kept apart (common), then families of names that import one another (websim*, parser*: a stem of 4 letters or more), then the rest placed by coupling (modularity, a family never joining another), a group of more than 20 cut again; files that import only the common ones are each alone at the top, together (others) in a folder; a group is named after its stem, else the file others import most; a folder of one or two files that only one sibling imports, where siblings are many, is merged into it. Each outside package is a part of kind external (prop package); the standard libraries (Node's own modules, Python's, Go's, libc, Rust's std) are left out and counted in a note, --std keeps them, one part each (node, python, go, libc, std). Each part says its files with source (a folder src/gen/**, or files); its api port's functions are the names others import from it; one link per pair of parts, with the number of imports; in a block of more than 12 links, those of fewer than 3 imports are weak: listed in the block's prop weak_links and not drawn (--min-imports N: the bar, in every block; 1 draws all). A cycle is said by the light links whose imports, removed, break it (a feedback arc set weighted by imports), each with an import's file and line, or for a big one by what to cut first; unresolved imports and imports of a computed name are // recovered: comments too, and past a part's ten fns eight more names. The system says prop recovered (the command): archec diagram then draws its 30 heaviest links. The result checks clean and archec diagram draws it. --json: the parts, their files, the links with each import's file and line, the cycles and their cuts. --graph gitnexus: the calls between files from a GitNexus index, counted on the links (without the program or an index, a note says why and the imports alone are used).
archec conform <main.arche> [--src dir] [--lang …] [--system S] [--directed] [--json] [--junit file] The model against the code: the reflexion model (Murphy and Notkin). Each part's files are those its source names (the most specific source wins: a file before a glob, a longer folder before a shorter); the code's imports, lifted to the two parts under their nearest common part, are a convergence (a link of the model between them), a divergence (no link: an error at the import's file and line) or, for a link with no import under it, an absence (a warning at the link). A link allows imports both ways (data and imports often go opposite ways); --directed asks them to go its way. Files no part names, and files two parts name, are warnings. An outside package is compared when a part says it is that package (prop package = "yaml"). A pair of parts a block lists in prop weak_links ("a -> b: 1 import", as archec recover writes them) is allowed, its imports counted apart (--directed: its way only). The code is read from the main file's folder, or --src. Exit 1 on a divergence. archec ci runs it as its conform gate when a source names a file of the code.
archec arch-diff <src-dir> <rev-a>[..<rev-b>] [<rev-b>] [--model main.arche] [--lang …] [--depth N] [--std] [--json] [--md] The architecture of two git revisions compared: each recovered from git's blobs (nothing checked out), the second grouped as the first was so a file stays in its group, and a folder cut into groups or kept whole as in the first (one that crossed 12 files is said under Folders, not as files moved); without a second revision, the working tree. Parts added, removed and renamed, files moved from one part to another, file counts, links added, removed or with more or fewer imports, cycles new and gone. --model: the divergences at each revision against that model, and the new ones (then exit 1). --md: Markdown for a pull request comment.

Libraries#

Command What it does
archec lib <main.arche> The libraries the project uses: the version of each, where it is, and the other versions there are. Exit 1 when one is missing or in no version the project accepts.
archec lib <main.arche> fetch The libraries written uses name "^1.2" from "<git URL>": their repository's version tags (v1.2.0 or 1.2.0) are read, the version arche.lock names (else the newest in range) is checked out into .arche/libs/<name>@<version>/, which the build then reads; what they use from git is fetched too. archec lib … lock then records each one's repository and commit; a tag that moved since is reported and the locked commit checked out.
archec lib <main.arche> lock arche.lock beside the main file: each library's version and a fingerprint of its files. The version locked is kept, and a library whose files changed under the same version is pointed out.

Boards#

Known boards — the store archec ships (arche-hw-store: ESP32, STM32 Nucleo, Raspberry Pi Pico and Pi, nRF52840 DK, Jetson Orin Nano, Kria KR260) and your own collections, found in the project's libraries, in ARCHE_BOARDS (a path list; VS Code's arche.boardCollections sets it) and beside archec. A board is a component of kind board: its product { vendor; part-number; url }, its processors (compute { hal …; chip "…" }) and its connectors with their pins (pins { tx PA12; rx PA11 }). A binary on a board runs on its processor, and archec gen --target embassy drives the CAN controller on the board's pins. See the board store.

Command What it does
archec device list [--family i2c] [--displays] [--json] · archec device show <device> · archec device add <main.arche> <device> [--to <board>.<port>] [--as <part>] [--into <System>] [--dry-run] The hardware store's devices (sensors, displays, motors…: devices/ of lib/arche-hw-store), their bus, address, readings and Go driver (--displays: the screens — ILI9341, ST7789, SSD1306, HDMI — with the size, density and input a ui takes from them, ui.md); add writes the uses, the include, the part in the platform and, with --to, its link to the board's port — kept only if the project builds as before.
archec board list [<main.arche>] [--json] Every board of every collection the project (or this machine) sees: its processors, HAL and connectors.
archec board show <board> [<main.arche>] One board — by its id (nucleo-g474re), its definition (NucleoG474RE) or collection/id: what it is, its processors, its connectors and their pins.
archec board add <main.arche> <board> [--copy] [--as <part>] [--into <System>] [--dry-run] The board in the project: uses its collection (and libraries for one of yours), include its file, and a part in the platform — the system a deployment names, else the one board add made, else a new system <Project>Hw. --copy copies its folder into components/ instead. Nothing is written unless the project builds as well as before.
archec board new <id> --in <folder> [--from <board>] [--name "…"] [--vendor "…"] A board of your own in a collection (its library.arche made if the folder is not one yet): from a template, or a copy of another board to adapt.
archec board check [<folder>] A collection (default: the store): each board builds on its own, its processors say hal and chip (or os), its pins are pins of its chip, its picture is there. Exit 1 on an error.
archec pins <main.arche> [System] [--json] Each board's pin map: every pin its connectors use, the port and role on it, where the port is linked, its level, whether the part wrote it; then the pin plan's warnings (pin-conflict, pin-function, pin-pair, pin-level, board-pin). Exit 1 on one. See boards.
archec board extract <main.arche> <Def|System.part> --in <folder> [--id <id>] A board the model defines, copied into your collection with its picture; what it uses from the project is reported.

Store#

The Arche Store: architectures, drivers, specifications and boards people share, as signed packages. Which store: --store <where> (a folder, a git URL, or a hosted store's https URL), else ARCHE_STORE, else what archec store use set. See the Arche Store.

Command What it does
archec add <main.arche> <owner/name[@range]> [--dry-run] Takes a package and what it uses: the newest version in the range this archec reads (or the one arche.lock names), checked against the store (archive hash, the publisher's signature, the files' fingerprint) and the project's trust, unpacked into .arche/store/<name>@<version>/. Writes uses <name> "^x.y", updates arche.lock, and lists the code it brought. Nothing is written when one check fails.
archec audit <main.arche> [--json] Every piece of code the project holds (code files and code blocks), grouped by where it came from: the project, a library of its own, or a store package with its version, fingerprint and trust. --authors: who wrote it instead (see provenance).
archec publish <folder> The same as archec store publish.
archec search <words> The same as archec store search.
archec store fetch <main.arche> The store packages arche.lock names that are not in .arche/store (a fresh checkout), in the locked version, checked against the lock's fingerprint.
archec store outdated <main.arche> [--json] Each installed package against its store: a newer version this archec reads, or a yank (recorded, so archec check warns about it). Exit 1 on a yank.
archec store search <words> [--kind <kind>] [--json] / archec store info <owner/name> Find packages by name, keywords and description; one package's versions, license, export classification, badges and family.
archec store diff <owner/name> <version> <version> [--json] What the model gained, lost or changed between two versions: systems, components, their parts, ports and links, interfaces, messages and requirements, compared as declarations, not as text.
archec store check <folder> What publishing would refuse (no owner, license or export-control; a script, a binary, an executable file; a syntax error), warn about, or hold for a reviewer (words that read like defence technology).
archec store card <folder> [-o card.html] The package's page as the store shows it: its README and what archec reads from the model (systems, components, boards, interfaces, requirements, the code it brings).
archec store pack <folder> [-o <dir>] The .archepkg file: the same folder always packs to the same bytes.
archec store publish <folder> [--dry-run] [--private] Checked, packed, signed with the owner's key (made the first time, in ~/.arche/keys) and written into the store: a folder or a git clone (then commit and open a pull request), or uploaded to a hosted store. A published version never changes. --private: only the owner's organisation sees it (hosted store).
archec store yank <owner/name@version> --reason "…" The version is not taken any more, except by a lock that names it; projects that have it are told by archec store outdated.
archec store init <folder> [--name "…"] A new index, laid out as a git repository with its GitHub workflow (checks pull requests, writes badges, publishes the pages).
archec store seed <index> [--license <SPDX>] The packages archec ships: the board store and each board, the standard library, and the examples as architectures, published by arche (verified).
archec store verify-index <index> [owner/name…] Every archive is the one its entry names, with the fingerprint and signature it records.
archec store test <index> [owner/name…] [--all] [--write] [--breaks] Every package (its newest version, or --all) built with this archec as a project using it would build it, plus cppcheck and a Python parse of its code. --write records the badges; --breaks fails only on a package that passed with an earlier archec: run it before a release.
archec store site <index> -o <dir> The store's pages: a searchable list, a page per package (card, versions, badges, family tree), publishers, collections, requests. Static: GitHub Pages serves them.
archec store serve <index> [--port 8080] [--host 127.0.0.1] The hosted store: the pages and an API (search, packages, archives, publish, yank, review, stars, discussions, requests). Accounts are tokens; with GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET set, /auth/github signs people in with GitHub.
archec store token <index> <user> [--org a,b] [--reviewer] [--admin] An account's token (shown once; only its hash is kept in <index>/.tokens.json).
archec store login <url> --token <token> / archec store use <where> Sign in to a hosted store; set the store used by default.
archec store review <owner/name@version> [--refuse --reason "…"] Releases a package held for review (a reviewer's account on a hosted store), or refuses it.
archec store verify-publisher <index> <owner> [--name "…"] Marks a publisher verified (a board vendor, a known project): their packages are verified, the only ones trust verified accepts.
archec store collection <index> <id> "Title" <owner/name>… A hand-picked list of packages, shown on the Collections page.
archec store request "…" [--kind board] / archec store star / archec store discuss Ask for a board or driver that is missing; star a package; post on its page (stars and discussions: hosted store).
archec store import-zephyr <zephyr>/boards -o <folder> A board collection from Zephyr's board files: each board's processor (hal/chip for STM32, nRF, RP2040, ESP32), RAM, and its UART, CAN, SPI and I2C ports with their pins, as the DTS sets them.

Provenance#

Who wrote the code: the model, an AI assistant, or a person. Each line of a code file gets one of four origins:

  • generated: archec gen wrote it, and it is still what gen wrote. Gen leaves .archegen.json in its output folder: the files it wrote, with a fingerprint per line. A file with no manifest but a Generated by archec line at the top counts as generated whole.
  • AI: an AI assistant wrote it. The commit that last changed the line says so: a Co-Authored-By: trailer naming an assistant (Claude, Copilot, Codex, Cursor, Gemini, Aider, Devin…), Generated-by: (not archec), Assisted-by:, AI-assisted: yes, or an assistant's address as author. Or a marker in .arche/provenance.jsonl says so.
  • edited after gen: gen wrote the file, and a person changed this line since.
  • human: the rest.

The lines come from git blame, so each line counts for the commit that last changed it. Outside a git repository, the markers and the gen manifests are all there is.

Command What it does
archec provenance <main.arche|folder|file…> [--json] [--since <rev>] [--model] [--html -o page.html] The share of lines of each origin, by part of the model and by file. With a model: the files its parts name (source, code, implements "glob"), with those of their parts, and the code files beside it; a generated file that names an element (@arche Ctrl, or a genmap) goes with that part. The files an AI assistant wrote that no person committed to since are marked ! not reviewed and listed at the end (a Reviewed-by: trailer on the assistant's commit counts as a review). --since <rev>: only the lines changed after that commit. --model: the .arche files too. --html: a page of its own. Exit 0 all the same.
archec audit <main.arche> --authors [--json] [--since <rev>] The same as archec provenance <main.arche>.
archec provenance mark <file> [--lines a-b] --tool <name> [--model <m>] [--session <s>] Say an assistant wrote these lines (the whole file without --lines). The marker keeps a fingerprint of each line, so it still finds them after others moved them; a line a person changed since is theirs. For assistants with no hook.
archec provenance mark --commit <sha> --tool <name> Say an assistant made this commit, when its message does not.
archec provenance hook Reads a Claude Code PostToolUse event on stdin (Edit, MultiEdit, Write) and marks the lines the assistant added. Never fails.
archec diagram <main.arche> [view] --overlay provenance [--since <rev>] Each block coloured by who wrote most of its code (generated blue, AI amber, edited purple, human green), the shares written on it, and a bar of them in SVG.
archec doc <main.arche> --html|--md --provenance The specification with a chapter "Who wrote the code": the same tables.

The Claude Code hook#

Add this to .claude/settings.json in the project. After each edit, it notes the lines Claude wrote in .arche/provenance.jsonl:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [{ "type": "command", "command": "archec provenance hook" }]
      }
    ]
  }
}

Without archec on the PATH, copy tools/provenance/claude-hook.mjs into .claude/hooks/ and use "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/claude-hook.mjs". It needs only node. ARCHE_AI_TOOL and ARCHE_AI_MODEL set the tool and model it records.

Commit .arche/provenance.jsonl with the code, so others see the same. A line of it:

{"file":"src/plan.c","lines":[4,6],"hashes":["a1b2c3d4","…"],"tool":"claude-code","session":"…","time":"2026-11-10T12:00:00Z"}

hashes are the first 8 hex digits of the SHA-1 of each line written, trimmed. A marker counts for a line only when the line has the same text and was not committed before the marker's time.

Examples#

npm install && npm run build
node dist/cli.js build examples/autonomous-car/main.arche -o out   # → an Arche project
../arche/dist/arche-darwin-arm64 --project out                     # open it
node dist/cli.js check examples/autonomous-car/main.arche          # lint (exit 1 on errors, --strict on warnings, --json)
node dist/cli.js fmt --write examples/**/*.arche                   # format
node dist/cli.js fmt --simplify --write old.arche                  # rewrite in the short forms (same meaning)
node dist/cli.js fmt --extract-code --write main.arche             # move ```python blocks into .py files (same meaning)
node dist/cli.js stubs main.arche                                  # arche.py: Arche's helpers + the model's names, for Python tooling
node dist/cli.js pull main.arche --write                           # code edited in the Arche app → back into the .py / .arche sources
node dist/cli.js test main.arche                                   # build + arche-cli test, errors shown at their source line
node dist/cli.js analyze examples/autonomous-car/main.arche        # core load, response times, bus load, latency chains
node dist/cli.js difftest examples/live/main.arche                # the simulator and the generated C on the same random inputs
node dist/cli.js physics examples/dc-motor/main.arche Drive --integrator implicit --tol 1e-6  # a physical network, a stiff one too
node dist/cli.js physics examples/dc-motor/main.arche Drive --linearize --inputs supply.v --lqr 1,0.1  # A, B, C, D, its modes, an LQR gain
node dist/cli.js physics examples/dc-motor/main.arche Drive --batch 100 --vary motor.r=0.8..1.2 --csv runs.csv  # 100 runs over worker threads
node dist/cli.js sim examples/live/main.arche --html sim.html     # one page that runs the model live: pause, step, speed, send, plots
node dist/cli.js doc examples/autonomous-car/main.arche -o spec.tex # LaTeX specification (lualatex spec.tex)
node dist/cli.js doc examples/autonomous-car/main.arche --template examples/templates/autonomous-car-spec.docx -o spec.docx # your Word template, filled ({{ … }}: docs/templates.md)
node dist/cli.js diagram main.arche Car --md >> README.md          # a diagram as Mermaid, which GitHub draws (or --format d2|svg)
node dist/cli.js validate ../arche/sample-aesa                     # schema-check any Arche project
node dist/cli.js patterns                                          # the pattern reference
node dist/cli.js import model.sysml -o model.arche                 # a SysML v2 model in arche-lang
node dist/cli.js import bus.dbc -o bus.arche                       # a CAN DBC: frames, signals, nodes, routes
node dist/cli.js capella main.arche -o project.zip                 # a Capella 6.1 project (and back: capella model.capella -o dir)
node dist/cli.js ci main.arche --junit report.xml                   # every check a pipeline runs, one exit code
node dist/cli.js check main.arche --sarif archec.sarif             # the diagnostics as SARIF, for code scanning
node dist/cli.js lib main.arche lock                               # the versioned libraries used, locked in arche.lock
node dist/cli.js recover src -o recovered.arche                    # the architecture of code, as arche-lang
node dist/cli.js conform recovered.arche                           # the code's imports against the model's links
node dist/cli.js arch-diff src main..HEAD --md                     # what a branch changed in the architecture

More on some commands#

archec review main.arche asks Claude whether each trace is plausible from what its two ends say, and lists the doubtful ones (--suggest: the missing ones too). It is advice, never part of check or ci, and it sends the traced elements' texts to the Anthropic API; --dry-run shows what and sends nothing.

While a system runs, archec live shows which requirements, chains, threads and containers pass or fail; archec live-fix REQ-1 asks Claude why one fails — from the evidence, the measured and predicted timings and the declarations involved — and proposes edits to the .arche files, each checked against the text at its line. In VS Code, "Arche: Start Live" colours those lines, and "Explain & fix with Claude" previews the edits. --dry-run shows what would be sent.

Sign-off is kept in the repository: archec approve REQ-1 Car.brakes --as "A. Martin" --role safety writes one line per approval to reviews/approvals.yaml — the element, a fingerprint of what it says, who, when. When the element changes, its approval is stale (archec approvals --stale); archec cert shows who approved each requirement, and archec ci --require-approval fails while one is missing. archec baseline --sign signs a baseline with an SSH key (ssh-keygen -Y sign, as git does), checked by archec baseline --verify against reviews/allowed_signers.

archec issues sync opens an issue in Jira, GitHub or GitLab for each failing case and each unverified requirement, and writes its key on the element (issue "CAR-128"); the next run updates it, or comments and closes it once the problem is gone. The tracker is named in issues.yaml, the token comes from the environment, and --dry-run prints the requests without sending them.

archec parts looks the bill of materials' part numbers up at Nexar (Octopart), DigiKey or Mouser — stock, price breaks, lifecycle — and keeps the answers with their date in .arche/parts-cache.json; archec check then warns about a part at its end of life, not recommended for new designs or out of stock, from that cache alone.

archec diagram main.arche <view> writes any diagram the editor shows — a system, a component, a state machine, a scenario, a view — as Mermaid (--md fences it, for a README or a pull request, where GitHub draws it), D2, or SVG laid out by ELK. A viewpoint with include/exclude lines is a view of its own, a query over the model (include * -> adcu, exclude kind sensor): the diagram stays right as the model changes, and a term that matches nothing is a warning. --all -o docs/diagrams writes them all. archec diagram main.arche emergency-stop --format svg --play plays a scenario on its system's blocks, step by step, as an SVG with no script; archec doc --html puts every view and played scenario in the page.

archec sim main.arche --html sim.html writes one page that runs the model in any browser, live, as MuJoCo's viewer runs a scene: play and pause, a step to the next event or by a fixed time, a speed from 0.1× to 10×, a scrubber back over what has run (the run replayed, with what you sent), a form per input port that sends one of its messages now (its fields with their type, range and enum values), a push — a step or a pulse — on a physical network's sources, and live plots of the states, variables, message fields and physical quantities chosen. The keys are listed on the page (docs/sim.md).

For AI agents, archec mcp is the compiler as a Model Context Protocol server on stdio. Its tools are the commands: check, explain, describe (the syntax of a keyword), outline, analyze, format, diff, generate, build. The agent edits the .arche files and calls check. In Claude Code: claude mcp add archec -- archec mcp.

Python#

lib/python/archelang reads a model in a script or a notebook, through archec export --json (standard library only; pandas for the tables, when installed):

import archelang                                   # pip install -e lib/python, or PYTHONPATH=lib/python
m = archelang.load("examples/autonomous-car/main.arche")
m.requirements.unverified()                        # [<requirement REQ-SAF-001 …>, …]
m["REQ-BRK-001"].satisfied_by                      # [<component Adcu …>]
m["Car.brakes"].ports                              # a part's ports, its definition's
m.find(kind="port", direction="in")
m["REACTION_TIME"].value                           # Quantity(value=150, unit='ms')
m.requirements.to_dataframe()                      # with pandas
m["REQ-BRK-001"].set("priority", "high")           # archec edit: written only if it adds no error

Each element has its id, kind, label, file and line, parent and children, properties (el.period, el.prop("stale-after")), and its traces (satisfies, verified_by, derives…). Links and transitions have their source, target, and the parts they are on. archelang finds archec on the PATH, or ARCHEC names it. examples/brake-by-wire/model.ipynb is a short notebook.

SysML v2 API#

archec api serve main.arche serves the model over the OMG Systems Modeling API (the SysML v2 REST API), read-only: the project, its commits — git's history of the model's folder, and the files as they are — its baselines as tags, the elements at each commit, their relationships, and queries.

archec api serve examples/autonomous-car/main.arche --port 9000
curl -s localhost:9000/projects
curl -s -X POST localhost:9000/projects/<id>/query-results \
  -d '{"@type":"Query","where":{"@type":"PrimitiveConstraint","property":"@type","operator":"=","value":"RequirementUsage"}}'