Stop babysitting
your agent.

AI agents write your code now. Learn how to make them prove it is right, before it reaches you.

An agent can build a whole feature in one session.

That speed is real. The open question is what happens to everyone who still has to trust the result.

It is a loop. The question is who closes it.

Autocomplete

It suggests the next line. You write the rest. One small use case.

An agent, and you are the loop

It generates whole changes. You check each one, send it back, check again. This is where your day goes.

An agent that closes its own loop

It runs a real check, reads the failure, and fixes itself. It reaches you already green.

Most people are stuck in the middle: the agent got faster, and you turned into its feedback loop. The point is to give it a loop of its own.

A rules file is just a suggestion.

$ the agent finished
rule: every payment mutation emits an audit event
✓ tests pass ✓ lint clean ✓ it compiles
the audit event is missing, and nothing flagged it

It read the rule and dropped it anyway. Nothing mechanical caught it, so you find out in review. Or you do not.

The core idea

Suggestions get dropped. Checks get fixed.

Weakest“Do it well.” A wish. Nothing runs.
SuggestionA prompt, a skill, a rules file. The model can drop it, with no consequence.
PartialLint and types. Real checks, but only for syntax and shape.
The gateA hard check that runs. It gives a specific failure, and the agent must fix it before it moves on.

An agent corrects itself only against feedback that is hard, specific, and impossible to skip. That is a gate.

Review while the agent works, not after.

Context
Only the rules that touch this file.
Write
Code aimed at those rules.
Check
The gate runs. Free scripts, plus a reviewer where needed.
Fix
A precise failure, fixed in the same run.

The check lives inside the agent’s loop. It reaches you already green, instead of you reviewing raw output after the fact.

One gate. It does not care who wrote the code.

Hand-written code
AI-assisted code

The same gate

Passed means it ships.

The gate runs against the code, not against who wrote it or what prompt produced it. AI-built code clears the same bar as hand-written code, with no special path and no way to talk past it.

A script where it can. A reviewer where it must.

deterministic check, runs free
// every route must start with api/
for (const route of routes) {
if (!route.path.startsWith('api/'))
report(route, 'must start with api/')
}
plain-language rule, read by a model
# Audit every payment mutation
Any function that creates, updates, or
refunds a charge must call audit()
before it returns. No event is a refusal.

Some rules run as plain scripts, for free, and the agent cannot talk its way past them. Others you write in plain words, and a separate model checks them.

Rules you would actually write.

No database calls from the web layer.

Data access stays in one place you can change later.

Every endpoint checks who is allowed.

The check an agent forgets most, and the one that hurts most.

Every money change records an audit event.

So you can always answer what happened, and when.

This module stays pure: no clocks, no randomness.

Same input, same output, every run. Easy to test.

If you can say it in a sentence, and a script or a reviewer can check it, Yggdrasil can enforce it. Team conventions, security, layering, error handling, anything you keep repeating in review.

You attach a rule once. It rides everywhere it fits.

Your rules live in a small map beside your code, under .yggdrasil/. Point a rule at a layer or a feature, and the gate checks it everywhere that part reaches, not file by file. Change the rule, and everything it touches gets checked again.

See it catch a real mistake.

Rule

Every charge must record an audit event.

What the agent wrote

async function refund(req) {
await payments.refund(req.body.chargeId)
return { ok: true }
}

✗ refused: refund() changes a charge with no audit event

After it reads the failure

async function refund(req) {
await payments.refund(req.body.chargeId)
await audit('refund', req.body.chargeId)
return { ok: true }
}

✓ pass: recorded

The agent quietly skipped the audit call. The gate refused it, said exactly what was missing, and the agent fixed itself before you opened the pull request. No prompt makes it skip, on every change.

Not a linter. Not a rules file. Not a PR bot.

A linter checks syntax

It cannot check that a layer must not call the database, or that every charge records an audit event.

A rules file suggests

The agent can drop it. This one runs, and it blocks until the code is fixed.

A PR bot reviews after

By then the agent moved on. This reviews while it works, so the problem never reaches the pull request.

The rules in your head, now enforced.

implicitexplicitenforced

You already carry these rules and enforce them by hand in review. Write one down and the gate carries it, on every change, for human and agent code alike.

It holds in CI, with no keys.

ci.yml
- run: npx @chrisdudek/yg check

In CI it makes no model calls and needs no keys. It recomputes a hash of every rule and its code, then compares it to the verdict saved in your repo. If something changed without being checked, the build fails.

The rails do the heavy lifting.

Ship faster

The gate already did the work, so review is a quick green light, not a queue.

Less review drudgery

Rules written once ride every change. The mechanical checks run themselves.

The agent self-corrects

You read work that already passes the checks, not raw output.

You stay in control

Read AI output like a junior pull request. You decide what is worth enforcing.

What it does, and what it does not.

Structure, not runtime

It can require that you call the audit function. It cannot prove the audit fires in production. This is not monitoring.

Only as good as the rule

A shallow rule passes shallow code. The enforcement is real. Deciding what is worth enforcing stays yours.

It is a gate on how your code is arranged. It is not magic.

Try it on one rule you keep repeating.

get started
npm i -g @chrisdudek/yg
cd your-project
yg init

Open source, MIT. Delete the .yggdrasil folder and there is no trace.