No description
  • Rust 96.9%
  • Nix 2.9%
  • Shell 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
JMARyA 256c6cc748
Some checks failed
moira/flake/env.flake.eeb9c92140c77a3b@x86_64-linux env.flake.eeb9c92140c77a3b — queued
moira/flake/packages.default@x86_64-linux packages.default — queued
moira/flake/packages.moira@x86_64-linux packages.moira — queued
moira/flake/packages.moira-agent@x86_64-linux packages.moira-agent — queued
moira/flake/packages.moira-agent-image@x86_64-linux packages.moira-agent-image — queued
moira/flake/packages.moira-server@x86_64-linux packages.moira-server — queued
moira/flake/packages.moira-server-image@x86_64-linux packages.moira-server-image — queued
moira/flake/checks.moira-agent@x86_64-linux checks.moira-agent — queued
moira/flake/checks.moira-agent-labels@x86_64-linux checks.moira-agent-labels — queued
moira/flake/checks.moira-agent-labels-container@x86_64-linux checks.moira-agent-labels-container — queued
moira/flake/checks.moira-binary-cache@x86_64-linux checks.moira-binary-cache — queued
moira/flake/checks.moira-cancellation@x86_64-linux checks.moira-cancellation — queued
moira/flake/checks.moira-cancellation-container@x86_64-linux checks.moira-cancellation-container — queued
moira/flake/checks.moira-cli@x86_64-linux checks.moira-cli — queued
moira/flake/checks.moira-clippy@x86_64-linux checks.moira-clippy — queued
moira/flake/checks.moira-fmt@x86_64-linux checks.moira-fmt — queued
moira/flake/checks.moira-gate-approval@x86_64-linux checks.moira-gate-approval — queued
moira/flake/checks.moira-gate-approval-container@x86_64-linux checks.moira-gate-approval-container — queued
moira/flake/checks.moira-git-integration@x86_64-linux checks.moira-git-integration — queued
moira/flake/checks.moira-git-integration-container@x86_64-linux checks.moira-git-integration-container — queued
moira/flake/checks.moira-server@x86_64-linux checks.moira-server — queued
moira/flake/checks.moira-smoke@x86_64-linux checks.moira-smoke — queued
moira/flake/checks.moira-smoke-container@x86_64-linux checks.moira-smoke-container — queued
moira/flake/checks.moira-test@x86_64-linux checks.moira-test — queued
moira/ci moira/ci — failed
moira/publish moira/publish — succeeded
fix(template): the context variables the docs promised
`docs/topics/configuration.md` publishes a "Context variables" table of sixteen
references and AGENTS.md three more. The runtime produced six: `git.{sha,branch,
ref,tag}`, `matrix.*`, `flake.*` and `steps.<n>.outputs.<k>`. The other ten
expanded to the **empty string**, because `apply_template` drops a key it does
not know — so `${{ inputs.version }}` in a manually triggered deploy was not a
typo anybody could see, it was a deploy of `""`, and an image tagged
`app:${{ git.short_sha }}` came out as `app:`.

Now resolved: `inputs.*`, `vars.*` (thread and step, a step's shadowing the
thread's, matching `build_env`'s precedence so a reference and an env var of the
same name cannot disagree), `env.*` (from the run's injected environment, never
the agent's), `run.{id,number,url}`, `trigger.event`, `git.{short_sha,repo,
author,message}`, and `steps.<n>.{status,exit_code}`. `run.url` is absent rather
than broken in local and solo mode, the rule `MOIRA_SERVER_URL` already follows.
A skipped step reports `skipped`, not `succeeded`: it satisfies a dependency, but
it is not the same claim, and `steps.<n>.status` exists to be compared against.

**Two references stay unresolvable, and `moira check` now rejects both by name
rather than letting them expand to nothing.**

`secrets.*` never resolves, and this is the design rather than a gap. A secret
reaches a step as an *environment variable* — declared in `secrets:`, read as
`$NAME`. Interpolating one would substitute the plaintext into the command line,
where `ps` and `/proc` expose it to every other process on the machine, and into
any log that echoes the resolved script. AGENTS.md claimed it "resolves at
dispatch time"; `dispatch.rs` has never performed a substitution of any kind, so
`run: deploy --token=${{ secrets.TOKEN }}` ran `deploy --token=` — a credential
failing open and silent. Rejected rather than warned about, for that reason.

`trigger.pr.*` never resolves either: moira carries no pull-request metadata on a
run at all. `docs/topics/incidents.md` taught `trigger.pr.number` and
`trigger.pr.title` as *the mitigation* for shell injection, with a worked
example, so anybody following that advice had a step keyed on `""`. The section
is rewritten around `git.message`, which is real and carries the same untrusted
free text.

**`moira check` could not see a template.** `lint_template_vars` walked
`thread.vars` and `step.vars` and nothing else — not `run:`, not `script:`, not
`with:`, not `for_each:`, not `when.eval` — which is where essentially all
interpolation lives. And its root list accepted `env` and `secrets` (which did
not resolve) while rejecting `vars` and `git` (`git` did). `TEMPLATE_ROOTS` is
now one constant checked against what the engine actually builds, the same
single-source-of-truth argument `BUILTIN_MODULES` settles for `use:`.

Not fixed here, and deliberately: an unresolved placeholder still becomes the
empty string. Making that a named failure is the other half and is staged behind
a warning pass, because it is the change most likely to break threads already
running in the fleet — see `TODO-run-foundation.md` §1.2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 17:57:00 +02:00
.moira/envs test: server test fixture with a self-starting Postgres (T.1) 2026-07-30 16:23:30 +02:00
crates fix(template): the context variables the docs promised 2026-08-12 17:57:00 +02:00
docs fix(template): the context variables the docs promised 2026-08-12 17:57:00 +02:00
grafana feat(metrics): measure the flake build queue, per org 2026-08-07 22:52:01 +02:00
k8s feat(metrics): measure the flake build queue, per org 2026-08-07 22:52:01 +02:00
nix fix(agent): the drain has never survived a deploy 2026-08-11 09:02:41 +02:00
scripts feat: coordinated job resolution and deployment docs (5.9, 5.10, 5.12) 2026-08-02 05:47:30 +02:00
.gitignore chore: gitignore agent workdir, remove accidentally staged nested repo 2026-04-24 20:37:10 +02:00
AGENTS.md fix(template): the context variables the docs promised 2026-08-12 17:57:00 +02:00
Cargo.lock feat(proto)!: the agent speaks vox, and the old protocol is gone 2026-08-10 10:53:53 +02:00
Cargo.toml feat(proto)!: the agent speaks vox, and the old protocol is gone 2026-08-10 10:53:53 +02:00
CLAUDE.md docs: add AGENTS.md with full model/architecture reference, symlink CLAUDE.md 2026-05-31 06:01:00 +02:00
devenv.lock update devenv lock 2026-04-19 14:12:08 +02:00
devenv.nix add devenv postgres 2026-04-19 13:14:08 +02:00
flake.lock feat(proto): one typed contract for what the server and an agent say 2026-08-09 15:12:52 +02:00
flake.nix fix(checks): make the test check able to pass at all 2026-08-12 11:18:12 +02:00
README.md docs: link to moira-modules standard library 2026-05-23 01:24:41 +02:00
TODO-run-foundation.md fix(template): the context variables the docs promised 2026-08-12 17:57:00 +02:00
zensical.toml docs(runs): describe the system that shipped 2026-08-11 20:23:06 +02:00

Moira

Alpha software. Moira is under active development — interfaces, config schemas, and APIs may change without notice between commits. Run it, break it, report what you find, but don't depend on stability yet.

moira is a unified automation fabric for infrastructure engineers who believe the git repository is the only legitimate source of truth. It merges the concerns of CI pipelines, scheduled automation, workflow orchestration, and IaC execution into a single declarative system — hermetically sealed by Nix, driven by Rust, and accountable to nothing but your repo.


The mythology

Hydra builds moira.

In Hesiod's Theogony, the three Moirai — the Fates — are daughters of Nyx, the primordial goddess of night. They weave the thread of every mortal life: Clotho spins it into being, Lachesis measures its length, Atropos cuts it with inexorable finality.

Your infrastructure has the same shape. Intent is declared. Work is measured and scheduled. Execution is final, hermetic, irreversible. And it all runs on Nix — named, knowingly or not, for the same primordial darkness the Fates were born from.

Hydra — the many-headed — spawns Moira. Moira, daughters of Nyx, runs on Nix.

The lore wrote itself.

Internal architecture: the three sisters

The moira runtime is divided internally along the mythological grain:

Sister Role
Clotho (CLI) Git watcher and intent compiler — she reads your declared threads and spins them into executable task graphs
Lachesis (Server) Scheduler and reconciler — she measures, allots work to agents, manages approval gate state, and ensures reality converges to declaration
Atropos (Agent) Step executor — she cannot be turned aside; hermetic, deterministic, she runs the step and cuts the thread when done

These are internal names. Users interact only with moira.

Documentation

Full docs live in docs/. To serve locally:

zensical serve

Standard library

moira-modules — curated environments, typed modules (HTTP, git, S3, SSH, …), and reference threads. Import as a flake input and use directly in your pipelines.