← Browse

@krzysztofdudek/yggdrasil

A

Agent Instructions — Yggdrasil Repository

instructionscodexclaude

Install

agr install @krzysztofdudek/yggdrasil --target claude

Writes 1 file into .claude/skills/, pinned to git-a9efb8b8.

  • .claude/skills/yggdrasil/AGENTS.md

Document

Agent Instructions — Yggdrasil Repository

You work on the Yggdrasil repository: an open-source CLI that makes a rule written once hold in every later session. A rule is attached to the code it governs, the agent editing a file gets only the rules that touch it, and a change has to satisfy them before it moves on. Some rules are local scripts that run for free; some are prose a separate model judges. Every verdict is tied by hash to the code it checked, so CI re-proves the set without a key.

This repo both implements that tool and runs it on itself, so the graph under .yggdrasil/ is a live example as well as the thing being enforced on your work here.

Context — Where Things Live

PathRole
source/cli/Implementation — CLI code.
.yggdrasil/model/cli/Graph — describes intended CLI architecture. Aspects enforce rules on source code.
docs/User docs — for adopters.
scripts/The quality gate (repo-check.sh) plus dogfood measurement instruments — deliberately NOT yg commands. See CONTRIBUTING before assuming one belongs in the CLI.
tools/Repo tooling outside the shipped CLI (the demo GIF renderer). Has its own README.
.plans/Agent working dir — design docs and implementation plans. Ignore skill paths (e.g. docs/plans/) — always use <root>/.plans/YYYY-MM-DD-<topic>-design.md and .plans/YYYY-MM-DD-<topic>-plan.md. Gitignored; not committed.

Product Scope

rules.ts (printed by yg prime) and the committed AGENTS.md digest are consumed by agents in ANY repository that adopts Yggdrasil — not just this one. When editing rules content, examples, or guidance: use domain-neutral examples (no Yggdrasil-specific types or commands). Think "what would help an agent working on an e-commerce app or a mobile game?" not "what would help an agent working on this CLI."

Constraints

  • Never hand-edit the marker-delimited Yggdrasil digest block in AGENTS.md (or .clinerules/yggdrasil.md) — it is generated. To change rules content: edit source/cli/src/templates/rules.ts (full manual) or source/cli/src/templates/digest.ts (committed digest), then rebuild and regenerate: node source/cli/dist/bin.js init --upgrade from repo root (repo-check's digest assertion fails the commit otherwise — it tells you the exact command).
  • Ignore the generated digest block for understanding; the source of truth is templates/rules.ts + templates/digest.ts.
  • Always reflect changes in corresponding documentation. When modifying code behavior, algorithms, or data structures, identify and update all documentation that describes the changed behavior — docs/ (user docs) and .yggdrasil/ (graph metadata). Changes to behavior are not complete until every document describing that behavior is consistent.
  • NEVER run yg init from a subdirectory. Always run from the repository root. Running from source/cli/ or any subdirectory creates a new .yggdrasil/ there or corrupts the project config. Use node source/cli/dist/bin.js for local builds, not npx yg (which may use a cached global version).

Yggdrasil-derived local state lives under .yggdrasil/

All Yggdrasil-derived local/rebuildable state (caches, indexes, scratch state) MUST live under the .yggdrasil/ directory — never at the repo root or elsewhere. Gitignore it within .yggdrasil/ (it is rebuildable and must not be committed). Examples: the relation pass's content-addressed AST fact cache lives under .yggdrasil/.ast-cache/, and the deterministic-verdict cache at .yggdrasil/.yg-lock.deterministic.json (rebuilt for free by yg check --approve --only-deterministic) — both dot-prefixed and gitignored. (.symbols-cache/ is a retired predecessor: nothing writes it any more, and it stays in the installed gitignore list only so an old checkout's leftovers keep being ignored. Do not treat it as the live cache.) Do not scatter Yggdrasil state outside .yggdrasil/ (no root-level .yg-cache/ etc.). The committed graph (model/aspects/flows/lock) also lives here; keep derived state in dot-prefixed, gitignored subdirectories so it never mixes with the committed graph.

Adding Support for a New Agent

Universal install covers every agent that reads AGENTS.md natively; Claude Code via the CLAUDE.md import; Cline via .clinerules/. A new agent needing a bespoke file is a design decision — open it with the maintainer before adding an installer.

Version Bump & Changelog

  • Changelog is always updated. Every code or behavior change gets an entry under ## [Unreleased] in CHANGELOG.md. This happens as part of normal work — do not wait for a release.
  • A changelog entry records what changed between versions — it is not a work log. Write for someone reading release notes: what was wrong, what is now true, why it matters to them. Leave out how you found it, what you ran to verify it, and the order you did things in. "Verified by reproducing each case and comparing output" is your method, not a change. One entry per change, not one per step; group related fixes rather than listing each file you touched.
  • Version bumps only on explicit user request. Never bump the version in source/cli/package.json unless the user explicitly asks for a release. When they do:
    1. Bump version (patch/minor/major per semver).
    2. Run npm install in source/cli/ to update package-lock.json.
    3. Move current version entries to a release section in CHANGELOG.md.
  • Two distinct version notions — do not conflate them. The package.json version is the release/marketing version and moves on every release. The graph schema version is separate: it lives in CLI_SUPPORTED_SCHEMA (core/graph-loader.ts) and the version: field of templates/default-config.ts, and it advances ONLY when the graph format/migrations change — never for a code-only patch. yg init compares a project's graph version against CLI_SUPPORTED_SCHEMA (not the package version) to decide whether an upgrade is needed. Bumping package.json does NOT require bumping the schema version; bump the schema version (in both places, plus a migration) only when the graph format actually changes.

CLI Message Design Principle

Every diagnostic message the CLI outputs to an agent must follow the what / why / next structure:

  • WHAT happened — facts, one line or short block
  • WHY it's a problem — context the agent needs to understand the situation
  • NEXT — concrete command or instruction to resolve

Use buildIssueMessage({ what, why, next }) from source/cli/src/formatters/message-builder.ts for all error/warning messages in validator, check, approve, and build-context. The builder enforces the structure; the caller handles presentation (indentation, error code prefix).

This applies to CLI output only. Rules.ts (system prompt) provides the map — workflow, vocabulary, categories. CLI provides the GPS — specific errors, next commands. They share vocabulary but never duplicate information.

Quality Gate

ALWAYS run scripts/repo-check.sh from repo root before ANY commit and ensure it passes cleanly. Do not commit with failing checks. This is non-negotiable — every commit must leave the repo in a green state. Do not run these individually before committing — repo-check.sh covers everything. The pre-commit hook also runs repo-check.sh, so there is no need to run it manually before committing either.

The gate is 16 fail-fast steps, in order: CLI typecheck; portal-e2e typecheck; lint; build; a built-binary guard (so the E2E suites cannot silently skip); a pack smoke; the deterministic cache as a test prerequisite; tests with coverage; a coverage >= 90% threshold; the AST-cache false-green audit; a Chromium-present guard; the portal E2E driving real Chromium through Playwright; docs build; markdown lint; digest freshness; and finally the graph check, which runs yg check --approve --only-deterministic (free and keyless — it rebuilds the cache and reports in one step).

Two of those bite in ways the category list would not warn you about:

  • The portal E2E needs Chromium installed for Playwright. Without it the guard fails the gate by design rather than letting the suite skip. Install it once: (cd source/cli && npx playwright install --with-deps chromium).
  • The digest gate is not repo-root-only. It checks both installed artifacts — AGENTS.md and .clinerules/yggdrasil.md — at the repo root and in every examples/*/ directory that carries its own .yggdrasil/. So after editing templates/digest.ts, one init --upgrade at the root is not enough: each such example needs its own, run from that directory against this repo's built binary. A newly added example with a graph but no agent-rules install fails this step too.

Only seven of the sixteen steps are themselves protected against being quietly dropped, by the advisory repo-check-gate-steps rule (typecheck, lint, build, test/coverage, docs build, markdownlint, graph check). The other nine rest on this list alone — if you add or remove a step, update it here.

Dogfood Issue Tracking

While working in this repo, if you encounter a problem with the CLI itself or with the rules/knowledge content (contradictions, missing warnings, misleading examples), append an entry to .temp/dogfood-report.md. Format:

## <date> — <short title>
**WHAT:** <what happened>
**WHERE:** <file:line or command>
**WHY:** <why it matters>
**REPRO:** <steps to reproduce>

Mark entries RESOLVED (with commit SHA) once fixed, or DEFERRED (with reason) when punted.

Memory

Do NOT use the auto memory system. All persistent knowledge goes into CLAUDE.md or AGENTS.md — nowhere else.

Working Preferences (maintainer-set; apply by default in this repo)

  • Quality over cost. Iterate as much as needed; do not skimp on rigor to save effort or tokens.
  • High bar, out-of-the-box. Aim for genuinely excellent — not "good enough" — and think past the obvious framing.
  • Never hardcode assumptions; derive and verify. Establish facts from the real config/code and check them, rather than asserting "probably X" when X depends on configuration. (E.g. whether a reviewer costs money or needs an API key depends on the configured provider — a hosted API does; a local/CLI provider like claude-code does not — read the config, don't guess.)
  • Don't expose internals in user-facing surfaces. A person sees what is happening in plain terms — not the names of commands, flags, or internal mechanisms.
  • Use multi-agent processes for substantive work — opinion panels, adversarial review, research workflows — rather than a single pass. When external research is wanted, offer a ready-to-run research prompt in a code block so the maintainer can run it with their own agent.
  • Subagents run on Sonnet or Opus only — set the model explicitly on every spawn. Never launch a subagent that silently inherits the session model. Default to Sonnet for research/mechanical work, Opus for hard synthesis or judging. Instruct subagents not to spawn their own agents (nested spawns would bypass the model choice).
  • Ground yourself before designing. Read all of yg knowledge and yg schemas so you understand the engine completely before proposing a design.
  • Graph before code, hierarchically; lock the design in. Design the target architecture + aspects up front, then calibrate as work proceeds. Concrete ("betonuj") the intended rules, relations, and architecture in Yggdrasil — a hierarchical model + aspects — so a future session cannot build anything inconsistent with the design (yg check refuses the drift). Where a preference here is mechanically checkable, prefer encoding it as an aspect, not just prose.
  • No artificial mocking. Tests run against real on-disk fixture projects (a real .yggdrasil/ graph + real source), never fabricated data. E2E tests use only the public CLI surface (spawn the built bin.js), drive the real output in Playwright + Chromium — every path, properly, not a token smoke test — and assert consistency with yg check. This matches the repo's existing source/cli/tests/fixtures/** + source/cli/tests/e2e/ convention.

Task-dependent — ask, don't assume. A few preferences vary by task; at the start of a relevant task, ask the maintainer rather than defaulting:

  • Working mode — run fully autonomously with minimal reporting, or collaborate with check-ins along the way.
  • Visual deliverables — whether to route the visual layer through Claude Design (rendered previews on claude.ai) for review.

When Evaluating yg check or scripts/repo-check.sh

Consider both:

  1. Product — Is the command correct and useful for adopters?
  2. Dogfood — Is this repo's graph coverage correct and complete?

Yggdrasil

This repository is managed by Yggdrasil — continuous architecture enforcement. An architecture graph in .yggdrasil/ defines the rules; a reviewer verifies source code against them, and yg check blocks CI whenever an enforced rule is violated or unverified.

Required first step: run yg prime and follow the protocol it prints before making any change. The full, current operating manual comes from the installed CLI — this block is only the standing summary. If yg prime is not a recognized command, the installed Yggdrasil CLI predates this integration: update the @chrisdudek/yg package before proceeding.

Non-negotiable invariants (they hold even before reading the manual):

  • Never write a yg-suppress marker without the user's explicit confirmation. The reviewer honors suppressions unconditionally — an unauthorized suppress silently disables a rule.
  • Never change a rule's review_by: date; renewing or retiring a rule is the user's decision.
  • Treat yg advise items and incidents as proposals: dismissing, deferring, or recording one requires the user's approval. Never fabricate an incident.
  • Changes to .yggdrasil/yg-architecture.yaml require the user's confirmation.
  • Log entries (yg log add) carry WHY in self-contained prose — no references to plans, file paths, steps, or conversation state.
  • Never hand-edit .yggdrasil/ lock files.
  • If the user explicitly requests a code-only change without graph updates, comply but warn: the affected rules stay unverified and CI stays red. Do not run yg check --approve — leave the rules unverified.

Start every session with yg check; re-print the manual any time with yg prime.

Repository README

Describes krzysztofdudek/Yggdrasil as a whole, which may contain artifacts other than this one. Where this artifact had no useful description of its own, its summary was taken from here.

Yggdrasil

Say it once.

Write a rule and it holds in every session after that, without you repeating yourself. Before the agent edits a file it gets only the rules that touch that file, not all two hundred. After the edit they are checked, and a violation comes back as an error the agent has to fix before it moves on. The same checks re-run in CI for free, with no API key.

CI npm version License: MIT codecov GitHub Discussions


You probably don't feel this problem, and that is the interesting part

If you have ever been the only thing standing between an agent and production, solo, after hours, shipping something fast to find out whether it was worth building, then you know the wall. Code arrives faster than you can keep quality up with it. From there it goes one of two ways. You slow to a crawl because you now have to watch everything yourself, or you lose the thread and end up with bugs you can no longer trace back to a decision.

If you work somewhere that pays for quality, you have probably never hit that wall. Review, QA and the rhythm of a sprint sit between you and it. Those same things mean you have never seen your own unconstrained speed either.

Nobody measures this in either direction. The best study available put experienced developers 19% slower on real tasks with AI assistance, while they believed they had been 20% faster (METR, 2025). Neither the people who feel fast nor the people who feel careful have an instrument.

Scaffolding is not there to stop you falling. It is there so that the brake does not have to be a person.

Five minutes to your first enforced rule

Requires Node.js 22+. You can start without an API key: yg init offers "None for now" as a real answer, and script rules, dependency control and the CI gate all work from there with no key and no model calls.

npm install -g @chrisdudek/yg
cd your-project
yg init
yg check

That first check is green, and honest about why:

yg check: PASS (1 warning)  0 nodes · 0/50 files (0%) · 0 aspects · 0 flows

  uncovered (50)  Not under a coverage.required root. Visible, non-blocking.

Nothing is enforced yet, because you have not said what matters yet. Nothing is pretending otherwise. That list is your to-do, not a finding.

So say one thing to your agent:

"Every service that handles payments must emit audit events. Create a rule for it and apply it to the payments module."

It writes the rule and maps the module. yg check now fails, because that rule has never been verified against your code. yg check --approve verifies it. From that point the rule holds, and any change that breaks it comes back to the agent as an error before it reaches you.

That is the whole loop, and it is the shortest honest path to seeing it.

Prefer to be taught instead? Tell your agent "onboard me into Yggdrasil". In an adopted repo the agent knows the tutor playbook and will teach you on your own code, in your own language.

What it does

The rule: every charge records an audit event. The agent writes a refund that skips it.

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

yg check refuses it: refund changes a charge with no audit event. The agent adds the call, re-runs, passes.

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

You reviewed nothing. That is the loop: the agent writes, the check runs, the agent fixes its own work before you look at it.

You attach a rule once and the tool works out everywhere it lands. You never paste it onto each file, and you never hand the agent the whole rulebook.

Two kinds of rule

Script rules ship a check.mjs that runs locally, every time, at zero cost. Deterministic, and there is no talking past it. This is the layer to lean on, and it is exactly the kind of rule an agent quietly drops when it is only a line in a rules file.

Judgment rules are plain Markdown, read by a separate model, for the calls a script genuinely cannot make.

# Audit every payment mutation

Any function that creates, updates, or refunds a charge must
call `auditLog.emit()` before it returns. A mutation with no
audit event is a refusal.

Judgment rules are the higher variance layer, so keep those components small and run new rules as advisory before you enforce them. A rule is one kind or the other, never both.

The rest of the vocabulary, components, flows, ports, statuses and the predicate language, is in the docs. You do not need any of it to get the first finding.

The part that is genuinely not available elsewhere

Every verdict, from a script or from a model, is recorded against a content hash of everything that produced it. CI does not re-run your model review. It recomputes the hashes and re-proves the existing verdicts, for free, with no API key.

In practice you pay a reviewer once per piece of code instead of once per pull request. Every metered AI review product bills you again for code that did not change, and none of them can stop without breaking their own pricing.

If the code changes, the hash changes, the verdict is void and the check goes red. A green build cannot quietly mean "we skipped that one".

Why it is built the way it is

Everything in this tool is here because at some point I needed it and did not have it. Nothing was added because it sounded good on a feature list. If a mechanism looks oddly specific, that is usually why, and the commit history says when.

I built it while shipping things alone, fast, which is where the wall above comes from. That is one person's experience, not a study. Take it as such.

Two limits, before you install

It enforces structure, not runtime behaviour. It can require that you call the audit utility. It cannot prove the audit fired in production.

A green check is only as good as the rule behind it. A shallow rule passes shallow code. The enforcement is real. Deciding what is worth enforcing stays yours.

See the whole graph

yg portal renders everything as a read only map in the browser: every component, every rule, and whether each one is verified against the code as it stands right now. Nothing is rounded up to green. yg portal --static writes a single self contained file you can hand to someone who has no checkout.

In CI

- run: npx @chrisdudek/yg check --approve --only-deterministic
- run: npx @chrisdudek/yg check

The first line rebuilds the free local cache that a fresh checkout never has. The second is the gate: it recomputes the input hash of every rule against its recorded verdict, and fails if anything changed without being verified. No keys, no model calls.

Works with

Any agent that reads AGENTS.md: Claude Code, Cursor, Copilot, Codex, Cline, OpenCode, Amp, Zed and others. yg init writes one universal rule set, so there is no platform to pick.

Reviewer providers: Anthropic, OpenAI, Google, OpenAI compatible, Ollama locally, or delegation to an installed agent CLI with no API key at all.

FAQ

How is this different from a rules file? A rules file is flat text dumped into every prompt, with no scoping and no verification. Here the agent gets only the rules that touch the file it is editing, and the output is checked against them.

How is this different from a pre-commit or agent hook? A hook is a real gate and you should use one. Point it at yg check and you have wired this in. What a bare hook has no notion of is which rule applies to which file, rules that need judgment rather than a script, and a lock that lets CI re-prove a model verdict for free.

How is this different from an AI review bot? Review bots hunt for bugs against their own idea of good code, and they re-run and re-bill on every pull request. This checks your specific rules, the ones only your team knows, and records a durable proof of each verdict.

What if I want to stop? Delete .yggdrasil/ and the rules file. No runtime dependencies, no build hooks, nothing left behind.

Examples and docs

examples/ has six runnable projects, four of them keyless. This repository uses Yggdrasil on itself, so .yggdrasil/ is a live graph you can read. Full docs at krzysztofdudek.github.io/Yggdrasil.

License

MIT


Trustgrade A

  • passBody integrity

    Whether the stored document is plausibly the kind of file the artifact declares, rather than something fetched by mistake.

  • passType matchnot applicable to this artifact type

    Whether the artifact is really the kind of thing its metadata claims it is.

  • passFreshness

    How long since the source repository was last pushed to.

  • passPrompt injection

    Scans the artifact's own text for instructions aimed at your agent rather than at you.

  • passLicense

    Whether the source repository declares an SPDX license permissive enough to redistribute.

How the grade is calculated

Each check contributes 0 points when it passes, 1 when it warns, and 2 when it fails. The total maps to a letter:

  • Aevery check passed
  • Bone warning
  • Ctwo warnings
  • Dprompt injection or body integrity failed, or three warnings
  • Fone of those failed, and something else is wrong

These are automated hygiene checks, not a security audit, and not a dependency or vulnerability scan. A grade of A means nothing was flagged — not that the artifact is safe.

Versions

  • git-a9efb8b8dc5e2026-08-04