Mentu

Architecture

Architecture

mentu-recipes is a single Swift package with two targets. MentuRecipesCore is a library that holds everything that decides or does something. mentu-recipes is a command-line target of a few hundred lines that parses arguments, calls the core, and prints. Everything below is in the public source at mentu-ai/mentu-recipes. There is no daemon, no background service, and no network call unless a step uses a network backend or you turn on the cloud hooks.

The core modules

Loading. RecipePaths decides where files may come from: recipes under <workspace>/.mentu/recipes then ~/.mentu/recipes, prompts under the matching prompts directories. A path that resolves outside those roots after symlinks are followed is refused. RecipeStore decodes the JSON, validates names, labels, prompts, and dependencies, and produces a topological order. PromptRenderer reads an inline prompt or a prompt file and substitutes $KEY and ${KEY} from the run's variables.

Backends. AdapterRegistry holds seven built-in adapters: shell, openai, openai-chat, deepseek, ollama, claude, and codex. Each adapter reports a capability record (execution kind, stream format, completion policy, whether it needs a credential or the network, which step options it supports) that doctor and the runner consult. A recipe can add custom OpenAI-compatible providers with a base_url and its own credential name. CredentialResolver turns credential names into values from the environment or the macOS Keychain, and the vault command is a thin wrapper over it. ProviderLogSanitizer strips terminal escape sequences from output lines before the progress view shows them.

Running. RecipeRunner is the scheduler. For a sequence it computes dependency layers and runs each layer's steps concurrently, capped by --max-parallel or the recipe's max_parallel. For pipeline, parallel, and compound recipes it runs child recipes as nodes with the same layer logic. ProcessRunner and OutputBuffer execute the step and capture its output with a timeout. HookRunner runs the recipe's before_run, before_step, after_step, on_error, and after_run shell hooks and records their exit codes.

Checking a step. After a step exits, three things happen in order. Verification runs the step's verify block: grep_present, grep_absent, file_absent, git_clean_outside, and arbitrary commands. GitWorkspace compares the working tree against the baseline captured at run start, commits the paths the step declared in expected_changes, and writes any undeclared change out as a patch under the run's quarantine/ directory rather than committing it. WorkspaceBaseline is what makes that comparison possible: it records which paths were already dirty before the run so that pre-existing changes are not blamed on a step.

Recording. RunStateStore keeps state.json, the per-step state machine (pending, running, success, warn_bookkeeping, failed, skipped, cancelled) that resume and retry-step read. RunEventWriter appends sequence-numbered events to events.jsonl. The run record itself, run.json, is rewritten after every step. RunReporter renders it as markdown, JSON, or CSV for report; RunAnalyzer aggregates many records for analyze-runs.

Quality and hygiene. RecipeDoctor scores a recipe without running it. ReleaseScanner is the scan command: it looks for secret-shaped tokens, local user paths, and internal names before a release is published, and the project runs it on itself.

Cloud hooks. MentuCloudClient is the only module that talks to a Mentu server. It is constructed only when --cloud is passed or the recipe sets cloud.enabled, and only if a MENTU_API_KEY is present in the environment or the Keychain. Without one, every run is local-only, which is what the run record says.

What a run leaves on disk

Each run writes one directory, .mentu/runs/<run-id>/, holding run.json, events.jsonl, baseline.json, state.json, one <step>.stdout and <step>.stderr per executed step, and a quarantine/ directory when a step touched undeclared paths. Steps with expected_changes also create a git commit in your repository, so the audit trail is your git log plus those files. The CLI reference describes each file.

These records are plain JSON. Nothing in the runner chains them, signs them, or verifies them after the fact.

Relationship to mentu-execution-graph-core

mentu-ai/mentu-execution-graph-core is a separate public Swift library, MIT-licensed, that defines a canonical form for contract-bearing execution graphs: RFC 8785 canonical JSON, lowering of a candidate graph into a hashed executable artifact, qualification and admission checks, and frontier scheduling with hash-linked outcomes. It performs no I/O and calls no model. It is the reference implementation behind the Agent Graph Runtime preprint at mentu-ai/agent-graph-runtime.

mentu-recipes does not depend on that package and does not import it. The runner's scheduler, records, and verification are implemented in MentuRecipesCore on their own. The two projects describe adjacent layers, recipes as files on one side and hashed graph artifacts on the other, but today they share no code.

What is not here

The runner does not ship a hash-chained ledger, trust scoring, hash-gated recipe commitment, per-step worktree isolation, or VM isolation. The public repositories are mentu-recipes, mentu-execution-graph-core, and the Homebrew tap; nothing else is documented on this site.

See also

© 2026 Mentu.