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

No generated code in the build path

This is the position I am least willing to give up. A build tool should not put code in your repository that you then have to keep in sync with the tool's version. Dagger works hard to hide it and it is still there: authoring a module writes dagger.gen.go and a tree of typed bindings next to your code, and the docs recommend committing them. Autotools has worked this way for decades: configure.ac becomes configure becomes a Makefile, generated code producing generated code producing the thing that runs. It is impressive, and when it breaks you need every layer in your head at once.

Marking generated files is right, and magus does it for its own output. The objection is about who did the generating. In magus I declared that output, in a target I wrote, and the tool does what I declared. A tool that writes a file into my tree as a condition of working, and tells me to commit it, has put itself between me and the build.

So the line: no generated code sits between you and running a build. A magusfile is Buzz, and magus interprets it. Nothing compiles it, nothing binds it, and no file lands in your tree that you keep synchronized with a tool version. magus init scaffolds a magusfile once and never touches it again. Scaffolding hands you a file and leaves. A generator that runs as a condition of the tool working never leaves.

Enforced by

  • A magusfile is interpreted; there is no compile or bind step for it.
  • magus init writes its files once; nothing else in magus writes into a workspace except a target the workspace declared.
  • Every generated file in this repository is a declared output of a target, and the drift gate fails a hand edit of one.

Good

A generated file this repository owns, declared by the target that writes it:

export fun index_generate(ctx: magus\Context, args: [str]) > void !> any {
    ctx.writesFiles("MAGUS.md");
    ctx.readsFiles("magusfile.buzz", "../magus.yaml", "../internal/render/target_graph.go",
                   "../internal/render/md/md.go", "../internal/hint/cli_command.go");
    index\render("docs");
}

Bad

$ dagger init --sdk=go
$ git status
  new file: dagger.gen.go
  new file: internal/dagger/dagger.gen.go

The tool wrote code you must commit and regenerate on every tool upgrade, and a version mismatch between that code and the engine is now your build failure.

See also

designprinciplecodegen
Last updated (2df714e8)
Glossary

Workspace

The magus root directory that owns a set of projects and shared config; the unit magus operates over. Workspace in full.

Magusfile

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

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. Target in full.

Module

A magus stdlib namespace a magusfile imports for host capabilities: filesystem, exec, vcs, and more. Module in full.

Buzz

The language magusfiles are written in (the .buzz engine). Buzz in full.

Engine

The interpreter a magusfile runs on; magus embeds the Buzz engine. Engine in full.

CI

An ordinary target you compose yourself with ctx.needs; magus does not hardcode its stages. It is the anchor magus affected ci keys off, and ci strips the rw charm. CI in full.

MAGUS.md

The committed routing index at a workspace root, regenerated from the knowledge graph: it lists every node and points at the exact query for a given question, so it is the entry point an agent reads first. MAGUS.md in full.

Tool

An action a model can call through its host: a name, a description, a typed input and a result. magus serves its tools over MCP, each a read of the workspace model or a run of the CLI it already has. Tool in full.

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. Run in full.

Conventions

This page uses none of the site's convention markers. The full set is on the conventions page.