AI-first
Magik is a framework for building SaaS with AI agents doing most of the typing. This page is the argument: what that changes about the design, and what the repo owes each of its two agent audiences.
Status: spec only — none of the mechanisms below exists. The agent-facing tooling (magik check --json, magik errors explain, the generators) is planned. Reviewed 2026-08-26.
The claim
The primary developer is an AI agent; the secondary is an engineer driving one. That is axiom 1 of 01-thesis.md, and it is a constraint, not a marketing line — it decides the grammar, the error format, the size of the surface area and where failures are caught.
The observation underneath it: agents fail on ambiguity, not on syntax. An agent will write syntactically perfect Ruby all day. What it cannot do is choose correctly between two equally defensible options with no local signal — it guesses, the guess is plausible, and the guess is discovered in production. Every "you could do A or B here" is a tax the agent pays, and Magik's job is not to levy it.
A framework optimised for an agent turns out to be the calmest one for a human, because both want the same thing: fewer decisions with consequences.
What "AI-first" means concretely
Six design consequences. Each is a thing an implementer can check, not a sentiment.
1. The DSL is designed to be generated, not just written
| Property | Why an agent needs it |
|---|---|
| The grammar is a lookup, not a memory | a DSL's cost to its author is recall, and recall is the one cost automation removes — but only where the surface is lookupable. magik describe is what makes it one (11-dsl-as-tool-surface.md). |
| One block shape for every construct | learning model teaches job, ledger and api. The grammar has one lesson, not twenty (02-dsl-surface.md). |
| Keyword arguments only | no positional booleans to get backwards, no argument order to remember. |
| Declarations are order-independent | a generated file can be appended to without reasoning about what came before. |
| Names are derivable | screen :Orders → /orders, action :refund_order → its POST endpoint. There is no route file to keep in sync, so there is nothing to keep in sync incorrectly. |
| No template language | no second syntax, no escaping rules, no HTML for an agent to malform. The UI is Ruby. |
2. One obvious answer per decision
Every place the framework could offer a choice, it ships a default instead. The escape hatches exist — but they are operator configuration in App.define, resolved at boot, not a decision at every call site (04-swap-points.md). An agent writing a feature never picks a cache backend, a job backend or a serialization format; it writes cache.fetch and moves on.
3. The guardrail list is the specification an agent is checked against
03-guardrails.md is not documentation of an implementation detail — it is the machine-checkable half of "did the agent build this correctly". An agent that produces an unbalanced ledger, an unscoped query, a stateful screen or a raw card-number column finds out at boot, with the rule named and the file and line pointed at.
This is the difference the whole design rests on: a human reviewer catches those mistakes sometimes, and a boot check catches them every time, in a loop the agent can run itself.
4. magik check is the feedback loop
An agent needs a fast, unattended, machine-readable answer to "is this right yet".
| Command | Answers | Status |
|---|---|---|
magik describe <construct>[.<declaration>] --json |
what the grammar allows: every option, its type, its default, its allowed set and the codes it can raise (11-dsl-as-tool-surface.md) |
planned |
magik check |
do the guardrails pass, with no server and no ceremony | planned |
magik check --json |
the same, as structured findings with code, location, cause and fix | planned |
magik check --scale |
which query sites will hurt when this app shards | planned |
magik errors explain <CODE> --json |
what a code means and what to do about it, without reading source | planned |
magik test --changed |
only the tests the current diff can affect (../architecture/04-testing-strategy.md) |
planned |
The rule that makes them usable: every error carries a runnable fix: line. Advice is something an agent has to interpret; a command is something it can run (../architecture/03-error-codes.md). The diagnostic surface around this — structured logs, the request trace, the dev inspection commands — is ../architecture/06-observability.md.
5. The surface is small enough to fit in a context window
An agent's working memory is finite, and a framework whose API does not fit inside it is a framework the agent reasons about from half-remembered training data.
| Budget decision | Effect |
|---|---|
| ~30 constructs, one grammar | the whole DSL is a page (02-dsl-surface.md) |
| No SPA, no template language, no build config | three toolchains that are not in the context window because they are not in the framework (05-limits.md) |
One gem, subsystems under lib/magik/<subsystem>/ |
one dependency, one namespace, one place a symbol can live |
| Declarations over configuration | an app's behaviour is readable from its declarations; there is no config/ archaeology to reconstruct |
The intended test of this: a whole small app — models, screens, actions, jobs — read in one pass, with room left to think.
6. The docs are the context
The repo is structured so that a machine-readable map plus the spec is enough to start work, with no tribal knowledge in between.
| Artifact | Role |
|---|---|
llms.txt (repo root) |
the machine-readable repo map — the first thing an agent reads |
00-build-spec.md |
the source of truth for what to build |
02-dsl-surface.md |
the shape of every construct, for an agent implementing one or calling one |
03-guardrails.md |
the rules the result is checked against |
../architecture/05-adding-a-feature.md |
the loop, with the exact commands |
.claude/agents/*, .claude/commands/* |
the loop, pre-packaged as agent definitions and slash commands |
wiki/ |
the reference manual for app authors |
7. The agent decides, not only types
The six points above are about an agent writing Magik. This one is about an agent deciding it, and it is the version this project actually runs on: design questions that arrive mid-task are answered and recorded rather than queued for a human to arbitrate.
It is the same argument this page already makes about boilerplate, applied one level up. A framework generates hundreds of decisions and most have one defensible answer reachable from the constraints already written down; routing each through a person converts them into a bottleneck for work they would rubber-stamp. Direction is the scarce input. Adjudication is not.
The claim is narrow, and every clause is load-bearing: on a decision space that is already framed,
with a gate that runs in a minute and nothing shipped to break, an agent deciding and recording beats
a person adjudicating a queue. Remove the frame and it is invention; remove the gate and it is
guesswork; remove "nothing shipped" and it is someone else's outage. That is why the model is stated
with its boundary rather than as a principle — what stays with the owner, what a decision owes, and
the log of decisions taken this way are in 13-decisions.md.
Note that this does not contradict the honest limits below, and must
not be read as trust in the agent's judgement: the entire guardrail design assumes the agent errs
(03-guardrails.md). What makes delegation work is not that the decisions are
right, it is that a wrong one is cheap to find and cheap to reverse.
Two audiences
Both are agents. They need different things from this repo, and conflating them is how a doc ends up useful to neither.
| Agent A — implementing Magik | Agent B — building an app with Magik | |
|---|---|---|
| Works in | this repo, lib/magik/<subsystem>/ |
a generated app |
| Source of truth | 00-build-spec.md |
wiki/ + 02-dsl-surface.md |
| Needs | the tier rules, the conventions, the failing test first, YARD on every public method | the DSL grammar, the guardrail catalogue, the generators |
| Its loop | ../architecture/05-adding-a-feature.md → bin/check |
magik generate … → magik check → magik test |
| Its gate | bin/check green |
magik check + magik test green |
| Its failure mode | inventing framework behaviour the spec does not describe | inventing DSL that does not exist |
| Guarded by | "no framework code that is not spec-backed" (../architecture/00-conventions.md) |
boot guardrails and a boot that refuses unknown constructs |
Both failure modes are the same defect — a plausible invention — and both are answered the same way: a narrow, written surface, and a check that runs without a human.
Agent B does not assemble its own harness: the framework generates it. magik new emits that app's CLAUDE.md, AGENTS.md, llms.txt, .claude/ and docs/ as stage 1 of a three-stage scaffold — 09-app-scaffold.md is this page's argument applied one level out, to the app rather than the framework. Planned: the templates exist, magik new does not.
Honest limits of the claim
| Limit | Detail |
|---|---|
| None of this is proven | there is no framework, no magik check, and no agent has built anything with it. This page is a design intent, As of 2026-08-26. |
| An agent can still write bad Ruby | guardrails cover the framework's invariants — money, tenancy, boundaries, statelessness. They do not cover whether a feature is the right feature. |
| Small surface is a budget, not a law | every construct added spends it. That is the cost side of any proposal to extend the grammar. |
| Ruby has no compile step to lean on | which is exactly why the boot check has to do this much work (01-thesis.md — the Magik/Ultimate trade). |