Astralang
A gilded and silver celestial globe from 1579, driven by clockwork and carried on a winged horse.

Mifa

Mifa is Astra's package manager, Cargo-shaped, agent-friendly, and built around one non-negotiable: the same inputs must always produce the same build.

From zero to running project

Five commands take an empty folder to a running native program.

$ mkdir myapp && cd myapp
$ mifa init myapp          # scaffold astra.toml + src/main.astra here
$ mifa verify              # validate astra.toml and the src/ layout
$ mifa lock                # write astra.lock (sha256-stable)
$ mifa run                 # compile + execute natively
$ mifa verify --json       # same result as a machine-readable envelope
$ mifa login <token>       # store a registry token (~/.mifa/credentials.toml)
$ mifa publish --dry-run   # validate + archive + checksum, no upload
$ mifa clean --cache       # drop target/ and ~/.mifa/cache

The manifest is Cargo-style TOML. This is exactly what mifa init writes; only name and version are required:

astra.toml
[package]
name = "myapp"
version = "0.1.0"
description = "A new Astra package"

[dependencies]
lib = { path = "../lib" }   # a local dependency (mifa add lib --path ../lib)

Manifests in Mifa's older flat form still load.

Dependencies you can import

A local package is a real dependency. mifa build compiles src/main.astra to target/<name> and searches each path dependency's src/ folder for modules; mifa run passes arguments through and exits with your program's exit code.

$ mifa init app              # creates app/
$ mifa init textutil
$ cd app
$ mifa add textutil --path ../textutil   # checks ../textutil/astra.toml
$ mifa run
HI!
textutil/src/textutil.astra ยท app/src/main.astra
pub fn shout(s: str) -> str:
    return s.to_upper() + "!"

import textutil
fn main() -> int:
    print(textutil::shout("hi"))
    return 0

mifa add needs --path, --git or a package in the registry; anything else is an error instead of recording a package nothing can fetch. This flow is covered by an end-to-end test that drives the real mifa binary.

Version requirements v0.13.1

A requirement means what it means in Cargo, and the newest matching version wins.

WrittenMeans
"1.2" or "^1.2"compatible: 1.2.0 up to, not including, 2.0.0 (^0.3 stops before 0.4.0)
"~1.2.3"1.2.3 up to, not including, 1.3.0
"=1.2.3"exactly 1.2.3
">=1.0, <3.0"a range
"*"any version

Versions are ordered by semver, so 10.0.0 is newer than 9.0.0 (before v0.13.1 they were compared as text). A requirement Mifa cannot read is named in the error (invalid version requirement 'banana'), and one nothing satisfies lists the versions that exist. Behaviour change in v0.13.1: a bare "1.2.3" used to mean exactly 1.2.3 and now means ^1.2.3; write "=1.2.3" to pin.

Git dependencies and workspaces v0.13.2

Dependencies from git, the whole graph resolved, and several packages in one tree.

# astra.toml
[dependencies]
textutil = { git = "https://github.com/acme/textutil.git", tag = "v1.2.0" }
helper   = { git = "https://github.com/acme/helper.git", version = "^1.2" }
util     = { version = "0.3", path = "../libs/util" }
  • Git dependencies by tag, branch or rev, or a version chosen among the repository's version tags. mifa add textutil --git <url> --tag v1.2.0 checks the repository before writing the manifest; repositories are cached and each commit is checked out once.
  • Version solving across the whole graph. Your dependencies' dependencies are resolved too. Mifa picks one version of each package that satisfies every requirement, backs off to an older version when the newest makes another requirement impossible, and names each requirement and who made it when nothing works. Cycles are refused.
  • Pinned and reproducible. astra.lock records each package's version, source and git commit; a branch stays on its pinned commit until mifa update. --locked fails instead of changing the lockfile and --offline builds from the cache, for CI. mifa tree shows the graph.
  • Workspaces. [workspace] members = ["app", "libs/*"] in the root astra.toml: one lockfile and one target/, commands that work from any member, and -p <name> to pick one.

A static package registry v0.13.3

A registry is only files: a folder, or any static web host serving one. There is no central public registry yet.

$ mifa publish --registry ~/astra-registry   # add this version; a version never changes
$ mifa add textkit --version "^1.1"          # depend on a registry package by name
$ mifa yank 1.2.0                            # hide a broken version (--undo brings it back)
$ mifa search text                           # registry folders only
  • Where it lives. An index per package and checksummed archives, in the spirit of Cargo's sparse index, so a shared drive, a git repository or a static web host (GitHub Pages, S3, nginx) can hold it. Name it with --registry, MIFA_REGISTRY or [registry] url = "..." in astra.toml.
  • Solved with everything else. A dependency with only a version (textkit = "^1.1") comes from the registry, with its own registry dependencies, in the same solver as path and git packages. Yanked versions are skipped unless astra.lock pins them.
  • Checked. Each archive's SHA-256 is checked on download and pinned in astra.lock; a replaced archive stops the build. Downloads are cached, so --offline works.
  • Its limits. Mifa publishes only into a folder, which you then upload; web registries are read with curl and are read-only, and mifa search works on folders only.

The lockfile

mifa lock resolves the full dependency graph and writes astra.lock: versioned, sorted, and content-hashed. Two machines with the same manifest resolve identical graphs, byte for byte. This was validated as differentiator D5: repeated locks of the same workspace produce sha256-identical files.

Reproducibility matters twice over for Astra's mission. Humans get reliable CI; agents get a guarantee that a build that verified once will verify the same way again, no drifting dependencies invalidating an earlier repair loop.

Mifa, as a globe

Every Mifa feature is a star: the brightest work today, faint dotted ones are planned. Drag to turn it, or pick a magnitude.

  • Works today: Projects (init, verify, clean), Build, run and test, Path dependencies, Git dependencies, Version solving (semver), Workspaces, Lockfile (--locked, --offline), JSON output for agents, Package registry (publish, add, yank, search), Registry dependencies by version, Checksums pinned in astra.lock
  • New in v0.13.3: Package registry (publish, add, yank, search), Registry dependencies by version, Checksums pinned in astra.lock
  • Next: Project-wide verify
  • Planned: Project-wide verify, Hosted registry, Package signing

Mifa milestones

Every local milestone has shipped, and a static, self-hosted registry works; a central hosted registry is what remains.

MilestoneScopeStatus
M1: Honest local workflow init / add / build / run / verify; 43-test integration suite shipped
M2: Lockfile + cache astra.lock, ~/.mifa/cache, path dependencies, lock / clean shipped
M5-basics: JSON output --json on init/add/verify/test/lock/login/publish; stable envelope for agent consumption shipped
M3: Registry protocol /v1/packages v1 API, SHA-256 checksums, yanked-version handling, stable REG4xx error codes shipped
M4: Publish + auth mifa login (per-registry tokens), publish --dry-run (validation, deterministic archive, checksum) shipped
M6: Graph, git, workspaces Transitive resolution with backtracking, git dependencies pinned to commits, update / tree, --locked / --offline, [workspace] v0.13.2
Static registry A folder or static web host: mifa publish into a folder, mifa add <name>, yank, search; SHA-256 pinned in astra.lock v0.13.3
mifa.dev: Public registry Hosted central registry with accounts and uploads v1.0

Honest note: there is no central public registry yet. A static registry you host yourself works: publish into a folder, upload it anywhere static, and depend on its packages by name, with checksums pinned. Uploading to a hosted registry (mifa.dev) waits on its deployment, and mifa login tokens are stored but a static registry does not use them. Local workflows (init, verify, lock, run, path dependencies, JSON output, login, dry-run publish) are real and covered by 90+ tests.

Honest about the registry v0.12

Since v0.12.0-alpha:

  • mifa --version prints the Mifa version.
  • mifa search says the registry is not deployed instead of listing packages. Up to v0.11.2-alpha, mifa search listed packages that do not exist. Since v0.13.3-alpha it searches a registry folder.
  • The Mifa flow is part of the black-box release suite that runs on every platform before a release publishes.

Why not reuse an existing manager?

Mifa is built around two things agents need most: fast verification and builds that never drift.

  • Verification-first. astra verify type-checks a program without generating code, so an agent can validate a change in milliseconds. mifa verify today checks only the manifest and layout; type-checking the whole project graph from Mifa is planned.
  • Lockfile as a contract. The lock isn't advisory; registry downloads refuse checksum mismatches outright.
  • One tool, one mental model. Mifa wraps the same compiler library the astra CLI uses. Diagnostics, exit codes, and JSON shapes stay identical between both tools, init, add, verify, test, lock, login and publish support --json and emit the same diagnostics[] envelope.