magus v0.4.3 is out. See what's new
¶ View markdown source · ✎ Suggest an edit
4 min read

Providers

A provider is a spell a magusfile selects to do one job magus knows nothing about. magus calls a few reserved function names on it (a contract) and reads what comes back. Every provider is wired the same way, at the top level of the root magusfile:

import "magus";
import "spells/endoflife-date" as eol;
magus\lifecycle.provider(eol);
Provider Selected with How many Contract
Remote cache magus\cache.remote one get_artifact, put_artifact
CI magus\ci.provider one enabled, annotate, last_green_run, ...
Secrets magus\secret.provider one resolve_secret
Review magus\review.provider one find_review, review_threads, ...
Workspace magus\workspace.provider many list_projects
Agent harness magus\harness.provider many harness_config, harness_skills, ...
Lifecycle magus\lifecycle.provider one list_lifecycles

There is one provider where two would disagree, and many where each answers a separate part. How a failure reads follows what is at stake: a workspace provider that fails stops the load, because the project set would be wrong, while CI, review and lifecycle answers are extra information and degrade to "unknown".

The lifecycle provider

A spell's tool names the product that publishes its release cycles: Tool{probe = ..., lifecycle = "go"}. The go, typescript, python and rust spells declare go, nodejs, python and rust. That name carries no dates. The lifecycle provider supplies them.

With one wired, magus describe tools asks it for every product the workspace's spells name, in one call, and adds three columns:

lifecycle: endoflife-date, GET https://endoflife.date/api/v1/products/{go,nodejs} (as of 2026-09-24T00:07:56Z)

  PROJECT/TOOL   INSTALLED   WINDOW        DECLARED BY  VERDICT  CYCLE  EOL         SUPPORT
  ./go           v1.26.6     >= 1.26       spell+ws     inside   1.26   -           unannounced
  console/node   v24.19.0    >= 22, < 25   workspace    inside   24     2028-04-30  supported
  • cycle is the longest release line that prefixes the installed version.
  • eol is that line's end-of-life date.
  • support is supported, eol (on or after the date), unannounced (upstream has named no date) or unknown (nothing to place the version with).

The header line names every URL the provider read, so the network use is never silent. -o json carries the same facts as a lifecycle object: provider, state, sources, as_of and fetched_at. The console's Toolchain tile shows the same columns, and a script reads them with magus\describe.tool(), which returns a ToolReport.

Nothing here fails a build. The gate is the tools window a project declares; end of life is a column in a report and a doctor line.

When the provider is not asked

describe tools stores each answer under the cache directory. The stored answer is what the other readers use:

State Meaning
live asked on this call
offline MAGUS_OFFLINE is set, so the spell never ran; the stored answer, or none
unreached the spell threw or ran past 15 seconds; the stored answer, or none
unwired no provider is wired; the columns read -
cached read from the store without asking (doctor)

With no stored answer, support reads unknown (offline) or unknown (unreached). A stored answer is used only while the question is the same: the same provider, the same products, the same built-in spells and the same workspace spell sources.

magus doctor runs the toolchain-lifecycle check against the stored answer and never fetches. It gives advice when an installed version, or a project's tools floor, sits in a cycle past its end of life. With nothing stored it says so and names magus describe tools as the fix.

A malformed answer is an error that names the spell, the product and the field: an answer for a product nobody asked for, a missing source, an asOf that is not RFC 3339, or a date that is not YYYY-MM-DD.

Using endoflife.date in another workspace

The provider this repository wires is spells/endoflife-date. It is not compiled into the magus binary: it imports http, and the binary carries no release feed (see Scope). Until remote spells publish, another workspace uses it by copying it:

  1. Copy spells/endoflife-date/spell.buzz to spells/endoflife-date/spell.buzz in your workspace.

  2. Wire it in the root magusfile:

    import "magus";
    import "spells/endoflife-date" as eol;
    magus\lifecycle.provider(eol);
    
  3. Run magus describe tools.

The copy is yours to read and change. It makes one GET per product to https://endoflife.date/api/v1/products/<product>, with no credential.

Writing your own

A lifecycle provider exports one function:

import "magus/spell";

export fun mgs_getName() > str { return "my-lifecycles"; }

export fun list_lifecycles(target: Target, cb: fun(any)) > [Lifecycle] !> any {
    final io = {<str: any>};
    cb(io); // io["keys"] is every product the workspace's spells name
    return [
        Lifecycle{
            key = "go",
            source = "https://example.internal/lifecycles/go.json",
            asOf = "2026-09-24T07:44:41Z", // upstream's last change, never the clock
            cycles = [ReleaseCycle{cycle = "1.26", released = "2026-02-10", eol = "", lts = false, latest = "1.26.6"}],
        },
    ];
}

Answer only the keys you were asked for, and leave out a product you do not know. Throw when the source cannot be reached: magus reads that as unreached, never as a failure. A workspace wires one lifecycle provider, because a product name has one meaning; wiring a second is an error.

providerproviderslifecycleend-of-lifeendoflife-datetoolchainspellsextension
Last updated (b5647a35)
Earlier changes on this page (2)

Full history ↗ · Blame source ↗

Glossary

Workspace

The magus root directory that owns a set of projects and shared config; the unit magus operates over. See workspace.

Project

A directory magus recognizes as a unit of work (it has a magusfile); the unit of caching, scheduling, and dependency tracking. See workspace.

Magusfile

The magusfile.buzz that declares a project's targets (as export funs) and binds its spells. See targets.

Target

A named operation (build, test, ...) you invoke with magus run <target>; it may compose a spell's tool-native operations and depend on other targets. See targets.

Op

A single tool-native command a target composes (long form: operation); the middle of the work hierarchy (Spell to Op to Target). See operations.

Spell

A language/runtime adapter (e.g. go, md) that maps generic targets onto a toolchain's real commands. See spells.

Buzz

The language magusfiles are written in (the .buzz engine). See engines.

Cache

The content-addressed store magus consults before running a target, so unchanged work is skipped. See cache.

CI

An ordinary magusfile-defined target you compose yourself with magus\needs: magus does not hardcode its stages. Magus.RunCI treats it specially only in that it strips the rw charm, it is the anchor magus affected ci keys off, and a selected scope with no project declaring it is a load error rather than a silent no-op. See targets.

Remote cache

A CI-only backend that shares content-addressed artifacts across runners: a cold machine replays a build another runner already did instead of rebuilding. Every remote artifact must be signed by a trusted key. See remote.

Window

The terminal a command runs in. It keys fire-once notices for a caller no host gave a session, and is never recorded as a session.

Job

The unit of delegated work, and one row of the job store: what an orchestrating agent handed out, with its goal, the checkpoint it was cut against, the paths it may write or must not touch, and the one check it runs. A job's holder is either a session, for work an orchestrator handed out, or the server, for its own maintenance. The store records; the agent guard is what reads those facts back when grading a write. See doctrine.

A job is not a run. magus run build web is a run, and no job exists for it. A job causes runs: its check executes as one, and a server job records the invocation of its last one. Jobs are listed with magus ls jobs and in the console's Jobs view; runs are listed in the Runs view.

Run

One target executing under one magus invocation, such as magus run test web or magus affected ci. A run keeps its captured output behind an output reference. Every magus run is a run whether or not any job asked for it; see Job for how the two relate.

Lease

The grant a holder takes on a job: the write and read paths that job declared, enforced in the checkout that took it with magus job exec. A job is the piece of work; a lease is permission over it.

Conventions

Placeholders

Angle brackets mark a value you replace with your own; never type the brackets:

magus run <target>
magus completion <shell>    # e.g. bash, zsh, fish

<target>, <path>, <shell>, <name> and the like are stand-ins, not literal text.