Decision — Mix components
Status: accepted 2026-10-10. Amends the source layout (AGENTS.md §2 and §10).
The decision
-
A component may be written entirely in Mix. It lives where its kind says (
services/<role>d/,apps/<name>/,cli/<name>/,libs/<name>/) and follows every naming rule. It has no Cargo package. -
Its identity is
component.mxat the top of the component, a strict-data document (schema 1) with the fields a Cargo package carries in[package.metadata.mixos], plus the name, version and principal program:{ schema: 1, name: "releasesd", -- = directory = component component: "releasesd", kind: "service", -- matches the kind directory layer: "desktop", -- bus | mix | core | desktop contract: "public", -- none | public version: "0.1.0", -- the component's own MAJOR.MINOR.PATCH program: "scripts/releasesd.mix" } -
A component is one or the other. A directory with both
Cargo.tomlandcomponent.mxis refused. -
Layout inside the component:
- programs in
scripts/, modules theyrequireinscripts/lib/; - units in
units/, calling/opt/mixos/bin/mixby absolute path; - tests in
tests/*_test.mix.
- programs in
-
Install location: a Mix component's
scripts/tree installs to/opt/mixos/lib/<component>/, read-only like the binaries in/opt/mixos/bin./opt/mixos/sharestays for data. -
Shared Mix test helpers live in
tests/lib/. The first isprivate_bus.mix, which starts a throwaway, owned noded broker for Bus tests of serve citizens. -
Gates.
tools/component_index.mixreads both identity sources, applies the same identity, layer and contract rules to each, and checks thatprogramnames a.mixfile inside the component. Names are unique across both kinds. A Mix component has no Cargo dependency closure, so its declared layer is checked at review: it may use only themixbinary, the Bus and the verbs of components at or below its layer. -
Versions and contracts. A Mix component carries its own version, since there is no workspace package to inherit one from. With
contract: "public", its Bus verbs and document schemas are registered like any other (docs/docs/spec/bus/verbs.conf.mix,docs/docs/spec/<topic>/).
Why
Mix is the system's own language. A service that is mostly glue (talking
HTTP, checking hashes, moving files, answering the Bus) is shorter, clearer
and easier for an agent to change in Mix than in Rust, and Mix already has
the primitives. Until now every component had to be a Cargo package, so such
a service had a choice of being rewritten in Rust to fit the layout, or
hidden in another component's scripts/, where it has no owner, no index
entry and no gate. Neither is honest.
component.mx keeps the one rule that matters (directory = component =
name, with a declared kind, layer and contract), so the component index stays
the agent's single map of the tree.
Consequences
- The first Mix component is
services/releasesd(upstream application releases). - The generic line-JSON bridge for external applications (AGENTS.md §4.1) will land the same way.
tools/component_install.mixinstalls Mix components:scripts/to/opt/mixos/lib/<component>/andunits/to/etc/systemd/system. It writes an install record, keeps one previous tree for rollback and has a--checkfor drift.--roottargets an image or container tree. Units of Rust components still wait for the unit collector.- Rejected: a separate top-level directory for Mix programs. It would classify by language, not by kind of artefact.