# Monkey D Loopy — complete agent context Generated from the canonical repository Markdown. Do not edit this file directly. Documentation index: https://matrixy.github.io/Monkey.D.Loopy/llms.txt # Repository overview Canonical page: https://matrixy.github.io/Monkey.D.Loopy/ Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/README.md

Monkey D Loopy logo

**A factory for runnable, crash-resumable agent loops.** [Documentation](https://matrixy.github.io/Monkey.D.Loopy/) · [First loop](https://matrixy.github.io/Monkey.D.Loopy/quickstart) · [Agent guide](https://matrixy.github.io/Monkey.D.Loopy/agent-guide) · [`llms.txt`](https://matrixy.github.io/Monkey.D.Loopy/llms.txt) · [GitHub](https://github.com/MaTriXy/Monkey.D.Loopy) Describe a loop once in a declarative **LoopSpec**; compile it to something that actually runs — journaling every step, resuming after a crash, and stopping when it should. You bring the agent and the model; Loopy handles the hard parts. https://github.com/user-attachments/assets/ad1b2379-f545-4257-9abc-b2f727b11526 > **The load-bearing rule:** the compiler will not emit an unbounded loop. Every loop must > declare a termination signal and carries mandatory caps — iterations, a no-progress > fingerprint, and a token/$/wallclock budget. The validator rejects anything that could run > forever. ## Why Hand-rolled agent loops fail in predictable ways: no termination criteria, context blow-up, unbounded cost, no resumability, no observability, goal drift, weak self-judging. A *factory* prevents most of these **structurally** — and the one it can't design out (a model grading its own work) it **measures and prices**: the validator traces who actually feeds every exit predicate, and the scorecard caps any loop whose "done" signal is only the agent's own report. You describe the loop; Loopy emits something that runs standalone *or* plugs into your harness, journals every step, resumes after a crash, and stops when it should — so the failure modes are designed out or made visible instead of debugged later. ## What's inside - **A declarative LoopSpec.** Express the loop — state, steps, termination, caps — as data. Never hand-write loop control flow again; produce a spec and let the factory emit the artifact. - **A bounded-loop guarantee.** Termination is *required* and caps are *mandatory*; the two-tier validator refuses unbounded or unreachable loops before anything runs. - **Verify before you run.** A codegen-free interpreter dry-runs the loop with mocked effects (no side effects) and proves it's **bounded · deterministic · resume-stable**, then a 0–100 scorecard grades termination strength, caps, observability, and resumability — including **termination grounding**: whether real evidence (a shell exit code, an http status) decides when the loop stops, or just the agent's own claim. (See [Prove it before you run it](#prove-it-before-you-run-it).) - **A durable runtime.** Event-sourced journal with a chained checksum, deterministic replay, write-ahead **idempotent effects**, **durable sleep** (park the run and resume past the wake time), human **breakpoints**, and **real USD cost metering** against the budget cap. Crash → resume from the journal, at-most-once for completed effects. - **Provider- *and* tool-agnostic.** Run `agent` steps on **any** LLM provider and **any** coding agent — no vendor lock, no default. (See [No vendor lock](#no-vendor-lock).) - **Multiple compile targets.** One spec → a standalone Node project, a durable supervised process, a coding-agent execution guide, a Claude Code-native slash skill, or a workflow. (See [Compile targets](#compile-targets).) - **Start from what you have.** Point the inferencer at an existing bash/JS/TS script or a `.loopy` run journal to get a draft spec to refine. - **Start from an outcome.** Verified recipes cover repository health, dependency policy, documentation drift, production errors, release follow-up, and market signals. Each ships with external-grounding guidance, safety boundaries, and adversarial runtime fixtures. - **Authoring help built in.** The [`/loopy`](.claude/skills/loopy/SKILL.md) skill turns a natural-language goal into a validated, verified, graded spec; the `loopc-mcp` server exposes the whole factory to agents as MCP tools. - **Zero-install artifacts.** `compile --vendor` bundles the runtime so a compiled loop runs with plain `node` — nothing to install. - **Optional local operations.** `@loopyc/operator` adds a secured loopback control center, explicit single-authority scheduling, guarded runtime controls, bounded artifact indexing, and idempotent generic webhooks. Guarded evolution evaluates isolated LoopSpec candidates against deterministic regression gates, then requires a reasoned human activation with byte-exact rollback. Journals and standalone/vendored artifacts remain independent. ## Quickstart ```bash npx --yes @loopyc/cli@latest quickstart # Node ≥ 22 ``` That one safe command validates and scores an honest **100/100** starter LoopSpec, runs it to completion, records its completion observer, inspects its durable journal, and emits a zero-install standalone artifact under `./loopy-quickstart/`. Deterministic verification fixtures model the same structured shell evidence without executing side effects during proof. It needs no model, API key, or external service and refuses to overwrite a non-empty directory. When you are ready to author real work: ```bash npm i -g @loopyc/cli loopc blueprints # list starting points (one per pattern) loopc new my-watch --blueprint poll-until # scaffold a LoopSpec loopc validate my-watch.loop.yaml # rejects unbounded / unreachable loops loopc verify my-watch.loop.yaml # dry-run: bounded + deterministic, no side effects loopc score my-watch.loop.yaml # graded 0–100 scorecard loopc compile my-watch.loop.yaml --target all --out ./out/my-watch ``` The poller requires a `status_url` input before execution; inspect the generated `inputs:` block and pass an `inputs.json` file to `loopc run`. See the [first-loop guide](https://matrixy.github.io/Monkey.D.Loopy/quickstart) for the complete clean-room journey. Claude Code users also get a native project skill from `--target all`: copy `out/my-watch/claude-native/.claude/` into the project where the loop should be available, then invoke it as `/my-watch run` from Claude Code. The local operator is deliberately optional and installs separately: ```bash npm i -g @loopyc/operator loopyd --help ``` It imports compiled artifacts for local scheduling and inspection; installing it does not start a service or make standalone/vendored artifacts depend on the operator. (Working from a clone instead? See [Develop](#develop) — everything runs from source via `tsx`.) Prefer an opinionated product workflow over a structural blueprint? This path is ready in under five minutes and preserves recipe provenance in every generated `loop.lock`: ```bash loopc recipes loopc new repo-check --recipe repo-health-doctor loopc verify repo-check.loop.yaml loopc compile repo-check.loop.yaml --target standalone --out ./out/repo-check ``` Set the generated `check_command` input to a repository-owned command that emits structured, redacted status/evidence JSON. See the [verified recipe guide](docs/recipes.md) and each recipe's README for its exact evidence and safety contract. ## Prove it before you run it The differentiator in one command. `loopc verify` executes your loop through the real runtime with **mocked effects** — no network, no shell, no model calls — restarting the process between every iteration to prove resume actually works. Then `loopc score` grades what the dry-run proved: ``` ✓ verify PASSED bounded: ✓ deterministic: ✓ resume-stable: ✓ Scorecard: 100/100 (A) ██████████ termination safety 30/30 — signal: oracle · grounding: external ██████████ caps 25/25 — explicit, no_progress, budget ██████████ observability 15/15 — trace: journal · observer: completed hook ██████████ resumability 15/15 — stable ██████████ determinism 15/15 — deterministic ``` **Grounding is checked, not trusted.** The factory traces which steps write the state your exit predicate reads. `grounding: external` means an http/shell fact decides when the loop stops; `grounding: agent` means the model grades its own work — and the score is capped accordingly, no matter what the signal label claims. Relabeling a judge as a `state-predicate` makes the score go *down*, not up. When a dry-run needs representative effect data, pass a data-only JSON fixture file with `--fixtures`. Verification returns those values from mocked shell/http/agent effects; it never executes the real effect. The quickstart emits its fixture alongside the spec so its 100-point claim is reproducible and inspectable. ## Examples One runnable spec per pattern in [`examples/`](examples/README.md) — fix-tests-until-green, API migration, doc-link sweep, deploy watch, issue triage, nightly digest, judged release notes. Each passes validate + verify, with its score and grounding in the [gallery table](examples/README.md). For complete product workflows, browse the [verified recipe catalog](recipes/README.md). For sequential artifact builders with fresh critics, see the [Gauntlet workflow](docs/gauntlet.md). ## A LoopSpec at a glance ```yaml loopspec: "0.1" id: deploy-watch pattern: poll-until inputs: { status_url: { type: string, required: true } } state: vars: { status: { type: "enum[pending,green,red]", init: pending }, attempt: { type: int, init: 0 } } body: - { id: check, kind: http, request: { method: GET, url: "${inputs.status_url}" }, save: { status: "$.state" } } - { id: triage, when: "${state.status == 'red'}", kind: agent, harness: cli, # any coding agent via LOOPY_AGENT_CMD prompt: "Deploy failed (attempt ${state.attempt}). Diagnose and push a minimal fix.", on_done: { incr: attempt } } - { id: wait, when: "${state.status == 'pending'}", kind: sleep, for: 5m } terminate: { signal: state-predicate, until: "${state.status == 'green'}" } # required caps: { max_iterations: 288, no_progress: { fingerprint: "${state.status}", max_repeats: 12 }, budget: { tokens: 200000, usd: 5.0, wallclock: "24h" }, on_cap_exceeded: breakpoint } # mandatory schedule: { mode: forever } ``` ## Compile targets One spec, `compile --target all`, five runnable forms: | Target | What it emits | |---|---| | **`standalone`** | A self-contained Node project running on `@loopyc/runtime` — the durable engine (journal, replay, caps, sleep, breakpoints). Add `--vendor` for a zero-install bundle. | | **`babysitter`** | A durable long-running process for the Babysitter process-supervisor runtime. | | **`claude-code`** | A prose execution guide a coding agent follows step by step. | | **`claude-native`** | A Claude Code project skill under `.claude/skills//SKILL.md`, invokable as `/`, with a hybrid handoff to standalone when available. | | **`n8n`** | An importable n8n workflow JSON for visual automation. | ## Claude Code-native skills The `claude-native` target emits a Claude Code project skill: ```text .claude/skills//SKILL.md .claude/skills//reference/loopspec.json .claude/skills//scripts/run-standalone.mjs ``` Install it by copying the generated `.claude/` directory into the target repository. Claude Code discovers project skills from `.claude/skills//SKILL.md`, and the skill directory becomes the slash command name, so a `deploy-watch` loop runs as: ```text /deploy-watch run '{"status_url":"https://example.com/status"}' /deploy-watch step /deploy-watch inspect ``` This target is intentionally hybrid. When a sibling `standalone` artifact exists, the skill hands off to `node loop.mjs` so the Loopy runtime enforces journals, replay, caps, durable sleep, breakpoints, and budget behavior. Without standalone, Claude can still execute from the embedded LoopSpec contract, but those guarantees are Claude-honored rather than runtime-enforced; the compiler prints that boundary as capability warnings. ## Why not a workflow engine? Temporal, Inngest, and Restate give you durable execution; LangGraph gives you agent graphs. Loopy overlaps with neither's core bet: - **Bounded by construction, not by discipline.** Engines will happily run a workflow forever; that's a feature. Loopy's compiler *refuses to emit* a loop without a termination signal and caps, and `verify` proves boundedness before the first real side effect. No framework we know of makes unboundedness unrepresentable. - **A compiled artifact, not hosted infra.** The output is a self-contained Node project (or a prose guide, or a workflow JSON) that journals to a local `.loopy/` directory and runs with plain `node`. No cluster, no service, no account — you can `scp` a compiled loop to a box. - **Agent-native semantics.** Termination-signal trust tiers (oracle > state-predicate > llm-judge > self-assess), grounding analysis, token/USD budget caps metered against real usage, and no-progress fingerprints are loop-safety concepts for *agents*, not generic retry policies. - **Declarative data, not framework code.** A LoopSpec is one YAML document — diffable, lintable, generatable by an LLM, and portable across five compile targets. There is no SDK your loop logic has to marry. If you need fan-out across a fleet, multi-service orchestration, or exactly-once across distributed workers, use a workflow engine — that's their home turf. If you need one agent loop that provably stops, survives crashes, and can't blow your budget, that's this. ## No vendor lock Agent steps are **provider- and tool-agnostic** — choose at runtime, nothing is hardcoded. - **Any LLM provider.** The built-in `llm` harness is an OpenAI-compatible client that talks to any compatible provider — cloud or fully local. It auto-detects whatever provider key you have, or point it with `LOOPY_LLM_*`. Cost is metered per call against the `usd` budget cap. - **Any coding agent.** For a full file-editing, tool-running harness, drive **any** coding-agent CLI with your exact flags via `LOOPY_AGENT_CMD`. No harness is the default — pick the tool you run; nothing is hardcoded. Named harnesses include Claude Code, Codex, OpenCode, Antigravity, Cursor Agent, and `pi`; pi's JSON event stream contributes trusted token and cost usage. - **Explicit agent limits.** Configure built-in harnesses with `LOOPY_AGENT_TIMEOUT_MS` and `LOOPY_AGENT_MAX_BUFFER`. `doctor` reports the effective values, and a tripped limit names the exact control instead of looking like a generic tool failure. ## Packages | Package | Role | |---|---| | [`@loopyc/core`](packages/core) | Pure, zero-I/O brain: the LoopSpec IR, expression engine, two-tier validator, planner + target adapters, blueprint catalog. | | [`@loopyc/runtime`](packages/runtime) | Durable execution engine the standalone artifact runs on (journal, replay, caps, sleep, breakpoints, cost metering). | | [`@loopyc/verify`](packages/verify) | Dry-run verification (bounded + deterministic + resume-stable) + scorecard, via a codegen-free interpreter. | | [`@loopyc/cli`](packages/cli) | `loopc` — `new · validate · verify · score · compile · run · inspect · schedule · reprint · targets · infer-scaffold · blueprints`. | | [`@loopyc/mcp`](packages/mcp) | `loopc-mcp` — the factory as MCP tools for agents. | | [`@loopyc/evals`](packages/evals) | Eval harness graded by the real code: property-based pipeline, capability honesty, validator corpus. `pnpm eval`. | | [`@loopyc/infer`](packages/infer) | Deterministic FactPack extraction from scripts (JS/TS AST, bash) + `.loopy` journals → a draft LoopSpec for the skill to complete. | ## Zero-install artifacts (`compile --vendor`) A normal `standalone` artifact `import`s `@loopyc/runtime`, so it needs `npm install`. For a **truly self-contained** loop, compile the standalone target with `--vendor`: ```bash loopc compile examples/deploy-watch.yaml --target standalone --vendor --out ./out/deploy-watch cd out/deploy-watch/standalone node loop.mjs run # no npm install, empty node_modules — just runs ``` `--vendor` bundles `@loopyc/runtime` (with esbuild) into a single local `runtime.bundle.mjs`, points `loop.mjs` at it, and drops the dependency from the emitted `package.json`. The artifact runs with **plain `node` on any machine with Node ≥ 22** — no install, nothing from this monorepo. ## Docs - [Documentation website](https://matrixy.github.io/Monkey.D.Loopy/) — guides, references, and operator-platform material in a searchable reading experience. - [Using Loopy with agents](docs/agent-guide.md) — the recommended agent workflow, MCP setup, context endpoints, and the guarantees an agent must preserve. - [`llms.txt`](https://matrixy.github.io/Monkey.D.Loopy/llms.txt) and [`llms-full.txt`](https://matrixy.github.io/Monkey.D.Loopy/llms-full.txt) — compact and complete agent-readable documentation indexes. - [LoopSpec reference](docs/loopspec.md) — the IR, step kinds, expression language, validation rules. - [`loopc` CLI](docs/cli.md) — every command and flag. - [`@loopyc/runtime`](docs/runtime.md) — runtime API, journal format, resume semantics, guarantees. - [`loopc-mcp`](docs/mcp.md) — MCP tools and how to register the server. - [Local operator](docs/operator.md) — secured dashboard, scheduler handoff, run controls, and audit. - [Artifacts and notifications](docs/artifacts-and-notifications.md) — safe output contracts and generic webhook delivery semantics. - [Guarded evolution](docs/guarded-evolution.md) — isolated candidates, deterministic regression gates, explicit waivers, human activation, and byte-exact rollback. - [Operator platform roadmap](docs/operator-platform-roadmap.md) — verified recipes, local control center, artifacts, notifications, and guarded evolution. - [Verified recipe contract](docs/recipes.md) — product-use-case packages over canonical LoopSpec. - [SPEC.md](SPEC.md) — full design and tracked decisions. - The [`/loopy`](.claude/skills/loopy/SKILL.md) skill — the authoring judgment layer over `loopc`. ## Develop Dev runs from source via `tsx` (no build needed): ```bash pnpm -r typecheck # tsc across packages pnpm -r test # vitest (unit · golden codegen · security · runtime · verify · mcp · evals) pnpm eval # property-based + capability + negative evals (graded by the real code) pnpm eval:skill # NL→spec authoring quality (live with any provider key, else golden) pnpm build # tsup → dist/ for every package (ESM + .d.ts; bins get a node shebang) pnpm docs:build # verify agent docs and build the GitHub Pages site pnpm release:check # synchronized versions + CLI/help/targets/docs parity pnpm release:pack-smoke # clean consumer installs tarballs and exercises every target ``` Each package publishes its compiled `dist` (via `publishConfig`), so installed consumers run the `loopc` / `loopc-mcp` bins and the generated artifacts with **plain `node`** — no `tsx` required. CI runs typecheck + tests + `pnpm eval` + build on every PR; the live skill-eval runs nightly. Release `0.8.0` adds first-class Gauntlet workflows while retaining repository-to-tarball parity, a clean-room onboarding smoke, and a zero-vulnerability audit. --- # Using Loopy with agents Canonical page: https://matrixy.github.io/Monkey.D.Loopy/agent-guide Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/agent-guide.md # Using Monkey D Loopy with agents Monkey D Loopy is designed to be authored *with* agents without asking those agents to enforce the important guarantees in prose. An agent can propose the goal, inputs, state, steps, and evidence; the validator and runtime remain responsible for boundedness, durability, and budget enforcement. ## Give an agent the right context Use the smallest context that fits the task: - [`llms.txt`](./llms.txt) is a compact map of every guide and its purpose. - [`llms-full.txt`](./llms-full.txt) concatenates the canonical documentation for a context window or retrieval index. - [LoopSpec](./loopspec.md) is the exact authoring contract. - [Gauntlet](./gauntlet.md) explains when independent builder/critic workstreams are worth the additional cost and how to choose Creative versus Verified grounding. - [MCP](./mcp.md) is the tool surface for agents that can call MCP servers. - [Recipes](./recipes.md) are the strongest starting point for supported product workflows. The raw endpoints are stable under the project site: ```text https://matrixy.github.io/Monkey.D.Loopy/llms.txt https://matrixy.github.io/Monkey.D.Loopy/llms-full.txt ``` ## Zero-context handoff An unfamiliar agent can prove the installation without cloning this repository: ```text Read https://matrixy.github.io/Monkey.D.Loopy/llms.txt. Run `npx --yes @loopyc/cli@latest quickstart ./loopy-first-loop` in a new directory. Inspect the generated LoopSpec and journal, then report the termination evidence, caps, score, and artifact path. Do not run any workflow with real external effects until its inputs and commands are explicitly approved. ``` The quickstart is intentionally deterministic and local. It gives the agent a real successful run to reason about before it authors a production workflow. See the [first-loop guide](./quickstart.md). ## Recommended agent workflow Ask the agent to follow this sequence. Each boundary corresponds to a real command or tool result, not a promise in the prompt. 1. Choose a verified recipe when one matches the outcome; otherwise choose the closest structural blueprint. 2. Make external completion evidence explicit. Prefer shell exit codes, HTTP status, tests, or repository-owned structured output over the agent's self-assessment. 3. Draft the LoopSpec with realistic iteration, no-progress, token, dollar, and wall-clock caps. 4. Run `validate`; repair all hard errors before continuing. 5. Run `verify`; do not compile until boundedness, determinism, and resume stability pass. 6. Run `score`; explain every deduction and any agent-grounded termination cap. 7. Compile the narrowest target needed by the user. Use `--vendor` only when a zero-install standalone artifact is useful. 8. Keep generated journals and operator state out of source control unless the user intentionally wants a fixture. ## Make an opinionated Gauntlet decision Do not wait for the user to know the name of every loop pattern. Recommend Gauntlet when one substantial artifact spans multiple reviewable quality dimensions, separate fresh critics would reduce builder self-grading, and the parts need a holistic integration review. State the likely workstreams, quality bar, completion authority, and cost tradeoff. Prefer a simpler pattern when the work is a single small fix, one draft with one repeated rubric, an independent batch, an ordered plan, or an external status poll. Prefer Verified Gauntlet when tests or another trusted command can decide completion; use Creative Gauntlet only when the bar is inherently qualitative. If the artifact, workstreams, or completion authority cannot yet be named, ask for that information before scaffolding. See [Gauntlet workflows](./gauntlet.md) for the complete decision guide and a user-facing explanation agents can reuse. Do not describe Creative Gauntlet's 87/B as a defect or as an estimate of artifact quality. It is the native workflow-safety score for honest agent-grounded completion. Never raise it by merely renaming the termination signal: Loopy traces the evidence feeding the predicate. Recommend Verified Gauntlet for 100/A when a trusted external oracle exists, or explicitly propose a separate mixed-grounding variant when both qualitative critique and a mandatory external gate are needed. ## Prompt contract This compact instruction works well after providing the relevant documentation: ```text Turn this outcome into a Monkey D Loopy LoopSpec. Start from a verified recipe when one matches. Choose Gauntlet only when one substantial artifact has multiple reviewable workstreams that justify independent fresh critics and a holistic integration review; otherwise prefer the simpler matching pattern. If recommending Gauntlet, explain why, name the workstreams, and choose Creative versus Verified grounding. Use external evidence for completion, make every cap explicit, and preserve provider/tool choice. Validate, verify, and score the spec before compiling it. Do not weaken a hard gate to make the score pass. Report the selected termination evidence, cap behavior, compile target, and remaining capability warnings. ``` ## Use the MCP server Install and register `@loopyc/mcp` as `loopc-mcp` in an MCP-capable agent host. The server exposes the same factory operations as structured tools, including authoring context, validation, verification, scoring, compilation, recipes, and inference. The productive pattern is: ```text discover recipes or blueprints → request authoring context → draft LoopSpec → validate → verify → score → compile ``` See the [MCP server reference](./mcp.md) for registration examples and exact tool names. ## Boundaries the agent must not blur - A prompt is not a hard guarantee. Only validator and runtime controls count as enforcement. - `llm-judge` and `self-assess` termination are weaker than external evidence and are scored as such. - Verification uses mocked effects. It proves control-flow properties; it does not prove that a production API, shell command, or model will return good content. - A Claude-native artifact can fall back to instructions when no standalone sibling exists. In that mode, durability and caps are agent-honored rather than runtime-enforced; capability warnings must remain visible. - The local operator coordinates canonical runtimes. It does not become a second execution engine or rewrite journal history. ## Existing loops and scripts For an existing shell, JavaScript, TypeScript, or `.loopy` journal, use inference to extract a FactPack and draft spec. Treat inference as scaffolding: the agent still needs to name the real completion evidence, state mutations, effect boundaries, and appropriate caps before validation. Continue with the [`loopc` CLI reference](./cli.md) or the exact [LoopSpec v0.1 reference](./loopspec.md). --- # First bounded loop Canonical page: https://matrixy.github.io/Monkey.D.Loopy/quickstart Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/quickstart.md # Your first bounded loop This path starts from an empty directory and ends with an executed, inspected, portable loop. The generated loop does not call a model or application API; `npx` only downloads the CLI from npm. Node.js 22 or newer is the only prerequisite. ## One-command proof ```bash npx --yes @loopyc/cli@latest quickstart ``` Use a custom output directory when you want to keep more than one walkthrough: ```bash npx --yes @loopyc/cli@latest quickstart ./my-first-loop ``` `quickstart` deliberately refuses a non-empty destination. It will not overwrite an existing project. ## What the command proves The command performs the real product sequence: 1. Writes an editable `hello-loopy.loop.yaml` and data-only `verify-fixtures.json`. 2. Validates termination, caps, and expression reachability. 3. Dry-run verifies boundedness, determinism, and resume stability, then prints the scorecard. 4. Executes one safe local shell step, reaches an externally grounded oracle predicate, and runs a completion observer. 5. Reads the resulting event-sourced journal, including the observer outcome. 6. Compiles a vendored standalone artifact that runs with plain Node—no package install required. The default result is: ```text loopy-quickstart/ ├── hello-loopy.loop.yaml ├── verify-fixtures.json # deterministic dry-run effect result ├── run/.loopy/runs/default/ # durable journal and run metadata └── artifact/standalone/ ├── loop.mjs ├── runtime.bundle.mjs # vendored runtime ├── loop.lock └── loop.source.yaml ``` Open the spec and journal before moving on. They are the two core contracts: the spec says what is allowed to happen, and the journal records what actually happened. ## Why the starter scores 100 The starter earns every point from behavior that is both implemented and regression-tested: | Dimension | Points | Reason | |---|---:|---| | Termination safety | 30/30 | A shell-produced structured fact feeds an `oracle` predicate; the verifier classifies that evidence chain as external. | | Caps | 25/25 | Iteration, no-progress, token, cost, and wall-clock bounds are explicit. | | Observability | 15/15 | The durable journal is enabled and an executable `completed` hook records its started/done or started/failed outcome. | | Resumability | 15/15 | Restart-per-iteration verification reaches the same result. | | Determinism | 15/15 | Independent mocked runs converge on the same state and status. | The fixture file returns the same structured result from the dry-run shell mock, so verification remains deterministic and side-effect-free. The real run executes the local command. This does not pretend that a local command is a remote production authority; it proves the mechanism: termination is based on effect evidence rather than an unconditional mutation or agent self-report. The observer is best-effort by design. Its outcome is durable in the journal, but an observer failure cannot rewrite an already successful loop as failed. Do not relabel a predicate as an oracle or add inert metadata merely to change the number: Loopy traces termination writers and only awards observer credit to an executable completion hook or active notification contract. ## Regression-tested onboarding contract The repository runs this same journey against packed npm tarballs in CI. The gate requires: | Contract | Evidence | |---|---| | No source checkout | CLI and MCP are installed only from packed public packages. | | One safe entry command | `loopc quickstart` reaches an honest 100/100 completed run without a model or external API. | | Real proof boundaries | Validation, verification, scoring, execution, and inspection all succeed. | | Durable evidence | The clean workspace contains effect, termination, and observer journal events. | | Portable result | The standalone artifact contains a vendored runtime, needs no install, and is executed in the packed-package gate. | This keeps the first-run promise executable: documentation changes cannot silently drift away from the package users actually install. ## Move from the demo to real work Install the CLI once, then choose a verified outcome recipe when one fits: ```bash npm i -g @loopyc/cli loopc recipes loopc new repo-check --recipe repo-health-doctor loopc validate repo-check.loop.yaml loopc verify repo-check.loop.yaml loopc score repo-check.loop.yaml ``` Recipes may require inputs or trusted commands. Read the generated `inputs:` block before running one. Pass runtime values in a JSON file rather than hard-coding secrets: ```bash loopc run repo-check.loop.yaml --inputs ./inputs.json --out ./run/repo-check loopc inspect ./run/repo-check ``` ## Give the journey to an agent Paste this instruction into a coding agent: ```text Read https://matrixy.github.io/Monkey.D.Loopy/llms.txt and then use the first-loop guide. Run the safe quickstart in a new directory, inspect the generated LoopSpec and journal, and report the termination evidence, caps, score, and artifact path. Do not run a recipe with real effects until I approve its inputs and commands. ``` For structured tools instead of shell commands, continue with the [MCP setup](./mcp.md). For the full authoring contract, read [Using Loopy with agents](./agent-guide.md). --- # LoopSpec v0.1 Canonical page: https://matrixy.github.io/Monkey.D.Loopy/loopspec Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/loopspec.md # LoopSpec v0.1 — reference A `LoopSpec` is one typed YAML document that declares a single **bounded** agent loop. Every input (a blueprint, a hand-written file, an NL draft) normalizes to this shape before any code is emitted. Canonical types live in [`packages/core/src/types.ts`](https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/packages/core/src/types.ts); the compact LLM-facing guide is [`LOOPSPEC_GUIDE`](https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/packages/core/src/toon.ts). > **The load-bearing rule:** the compiler refuses to emit an unbounded loop. `terminate` is > required and `caps` are mandatory (auto-injected if omitted). ## Top-level fields | Field | Required | Description | |---|---|---| | `loopspec` | ✓ | Format version — `"0.1"`. | | `id` | ✓ | Identifier; matches `[A-Za-z0-9_.:-]+` (lowered into code/comments). | | `pattern` | ✓ | `react` · `plan-execute-reflect` · `evaluator-optimizer` · `loop-until-dry` · `map-reduce` · `poll-until` · `cron` · `gauntlet`. | | `body` | ✓ | The iteration: a non-empty list of steps. | | `terminate` | ✓ | Exit predicate + signal tier (see below). | | `caps` | auto | Limits. Auto-injected per-pattern if omitted; set them explicitly. | | `meta` | | `{ name, version, description }`. | | `inputs` | | `{ : { type, required?, default?, description? } }`. | | `state` | | `{ store: journal, vars: { : { type, init } } }`. Only `journal` is supported in 0.1 (`memory` is reserved). | | `schedule` | | `{ mode: manual\|cron\|watch\|forever, cron? }`. | | `retry` | | `{ max, backoff_ms }` — transient http/shell/agent failures retry with exponential backoff (default no retry). | | `gates` | | Durable human-approval gates `{ after?, when?, ask, strategy?, auto_approve_in? }` — lowered to an inline, fail-closed `ctx.breakpoint()` after the named step (standalone + babysitter). | | `observe` | | Durable tracing plus executable lifecycle hooks; see [observe](#observe). | | `target` | | Default compile target + emitted surfaces: `{ runtime: standalone\|babysitter\|claude-code\|claude-native\|n8n, emit: [cli, skill, doctor] }`. | | `provenance` | | `{ factory_version, source, run_id }` (baked into the artifact). | ## Compile target notes `target.runtime` chooses the default compile output when `loopc compile` is run without `--target`. It does not weaken validation: every target still starts from the same bounded, validated LoopSpec. - `standalone` is the hard-guarantee runtime target. It emits `loop.mjs`, `loop.lock`, a local journal, and optional vendored runtime bundle. - `claude-native` emits a Claude Code project skill under `.claude/skills//SKILL.md`. The skill command name comes from the sanitized loop id, and the original LoopSpec is embedded at `.claude/skills//reference/loopspec.json`. - Use `--target all` when you want the Claude-native skill to sit next to a standalone artifact. In that layout, the generated skill can delegate to standalone for runtime-enforced journals, replay, caps, durable sleep, breakpoints, and budget metering. Without standalone, the skill is still usable from Claude Code, but those guarantees are soft and agent-honored. ## Types `string` · `int` · `number` · `boolean` · `json` · `list` · `enum[a,b,c]` ## Step kinds (closed set — no raw code) ```yaml - { id, kind: agent, harness, prompt, allowed-tools?, save?, on_done? } # harness: llm | claude-code | codex | opencode | antigravity | cursor-agent | pi | cli | internal - { id, kind: shell, cmd, save?, on_done? } # runs a shell command - { id, kind: http, request: { method, url, headers?, body? }, envelope?, save?, on_done? } - { id, kind: breakpoint, ask, strategy?, auto_approve_in? } # durable human gate - { id, kind: sleep, for: "5m" | until: "${...}" } # exactly one of for/until; durable - { id, kind: reduce, over: "${...}", as?, body: [...] } # fan out over a collection ``` Each step may carry a `when: "${...}"` guard. `agent`/`shell`/`http` steps may `save` json-path extractions into state; `agent` `save` reads the harness's structured result envelope. - **`save`**: `{ : "$.path.into.result" }` - **`envelope`** (http only, opt-in): when `true`, the step result is `{ status, ok, headers, body }` instead of the bare parsed body — so `save: { code: "$.status", payload: "$.body.field" }` can read the HTTP status of a JSON response. Default (omitted) keeps the body-direct shape. - **`on_done`**: `{ incr: }` | `{ set: { : value-or-${expr} } }` | `{ append: { : value-or-${expr} } }` (`append` into a `list` var is how `reduce` accumulates per-item results.) Mutation values may preserve native types and recursively evaluate a safe expression with `{ $expr: "state.review" }`; the wrapper must contain exactly that one string field. This is intentionally limited to `on_done.set` and `on_done.append`—HTTP bodies stay data. ## Expression language (`${...}`) A small, safe subset — **no function calls, no arbitrary identifiers**: - Roots: `state.x`, `inputs.y`, `env.Z`, `meta.m`, `iteration`, `item` (inside `reduce`). - Operators: `== != < <= > >=`, `&& || !` (and `and` / `or` / `not`), `+ - * / %`, `in`. - Literals: numbers, `'strings'`/`"strings"`, `true` / `false` / `null`. `&&`/`||` return operands (JS semantics), so `${a || b}` works as a fallback. The same AST is used by the validator (reference + safety checks), the runtime (evaluation), and the emitter (lowered to JS) — so all three agree. ## terminate ```yaml terminate: signal: state-predicate # oracle > state-predicate > llm-judge > self-assess until: "${state.status == 'green'}" on_exit: { kind: shell, cmd: "./notify.sh ${state.status}" } # optional action on exit ``` Rank your signal by trustworthiness: an **oracle** (tests/compiler/schema) is strongest; a model's **self-assessment** is weakest (and requires explicit caps). ### Termination grounding — the label is checked, not trusted A declared signal is only as strong as the steps that *feed* the exit predicate. The factory classifies the evidence chain behind every `until` (`terminationGrounding` in `@loopyc/core`): | Grounding | Meaning | |---|---| | `external` | The exit var(s) are `save`d by **http/shell** steps — real-world evidence decides. | | `structural` | Only `on_done` mutations (e.g. an unconditional `done` flag) — deterministic sequencing. | | `mixed` | Some evidence, some agent self-report. | | `agent` | Only **agent** `save`s feed the exit — the model grades its own work. | Taints propagate: a `done` flag set only `when` an agent-reported score clears a bar is still agent-fed. Declaring `oracle` or `state-predicate` over an agent-fed predicate trips the `ungrounded-exit` warning and the scorecard caps the termination dimension at the self-assessment ceiling — an honest `llm-judge`/`self-assess` label scores *higher* than an inflated one. To upgrade a loop's grade, ground the exit: let a shell exit code, an http status, or a scan count decide, not the agent's own report. ## observe ```yaml observe: trace: journal hooks: completed: kind: shell cmd: "./record-completion.sh" ``` `trace` controls the scorecard's durable-trace declaration. `hooks.completed` is a strict action: either `{ kind: shell, cmd: }` or `{ kind: http, request: }`. Unknown hook names, empty actions, and shell/http field mismatches are rejected during parsing. The standalone runtime attempts this hook once after it has journaled natural termination. It appends an `observer` event with `started`, then `done` or `failed`. The hook is post-result: failure is visible and durable but cannot rewrite a successful loop result. A process crash after `started` may leave the delivery outcome uncertain; the runtime does not blindly retry it and does not claim exactly-once external delivery. Other compile targets currently report `completion-observer` as unsupported in their capability warnings rather than silently promising standalone semantics. The scorecard awards observer credit only for an executable completion hook or an active top-level `notify` contract with at least one channel. Arbitrary legacy `observe.notify` metadata is inert and does not score. ## caps (mandatory) ```yaml caps: max_iterations: 288 no_progress: { fingerprint: "${state.status}", max_repeats: 12 } # anti-thrash budget: { tokens: 200000, usd: 5.0, wallclock: "24h" } on_cap_exceeded: breakpoint # fail | breakpoint | exit-clean ``` Per-pattern defaults (when omitted) are in [`normalize.ts`](https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/packages/core/src/normalize.ts). ## artifacts and notify (optional, deny-by-default) ```yaml artifacts: include: ["reports/**/*.md", "metrics/*.json"] exclude: ["reports/private/**", "**/.env*"] max_files: 1000 max_bytes: 50000000 notify: policy: on-change channels: [ops] ``` Artifact paths are relative allowlist globs with explicit file/count ceilings. Active content, secret/dependency allowlists, traversal, and absolute paths are compile-blocking. Notification channels are logical names; webhook URLs/tokens never belong in LoopSpec. No contract means no indexed files, and an empty channel list means no external calls. See [Artifacts and notifications](./artifacts-and-notifications.md). ## Validation — hard gates `loopc validate` blocks compilation on any of these: 1. `terminate` present, with a `signal` and a parseable `until`. 2. **Exit reachable** — `until` reads a state var some step writes, or `iteration`. 3. `self-assess` termination requires **explicit** caps. 4. Every `state`/`inputs` reference is declared; every `save`/`on_done` target is declared. 5. Exactly one of `sleep.for` / `sleep.until`. 6. Names (ids, vars, inputs, reduce aliases) are safe identifiers; expressions are in the safe subset; `schedule: cron` has a `cron`; gate `after` references a real step. 7. Artifact globs stay relative and cannot allowlist secrets/active content; notification channels are logical names rather than URLs or credentials. Soft warnings (non-blocking, downgrade the score): weak signal, **ungrounded exit** (a strong signal label over an agent-fed predicate), auto-injected caps, missing `no_progress` on poll/loop-until-dry, missing budget, `trace: none`. ## Worked example See [`examples/deploy-watch.yaml`](https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/examples/deploy-watch.yaml) — a `poll-until` loop that checks a deploy, lets an agent fix it when red, sleeps between checks, and exits when green. Scaffold any pattern with `loopc new --blueprint `. --- # Gauntlet workflows Canonical page: https://matrixy.github.io/Monkey.D.Loopy/gauntlet Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/gauntlet.md # Gauntlet workflows A Gauntlet is the opinionated choice for a substantial deliverable that has several distinct quality dimensions and deserves independent review. Monkey D Loopy breaks the goal into workstreams, gives each one to a fresh builder, asks a different fresh critic to inspect the real artifact, and repeats bounded rounds until the workstreams and the combined result clear the stated bar. The important idea is separation of duties: the agent that produced a change does not get the only vote on whether it is good. The journal preserves what was attempted, what each critic found, and why another round ran. ## At a glance | Variant | Best for | Who decides completion? | Native score | |---|---|---|---:| | Creative Gauntlet | Qualitative work such as UX, clarity, coherence, design, and launch polish | A fresh agent critic | 87/B | | Verified Gauntlet | Work with an executable test, policy, benchmark, schema, or other trusted judge | An external oracle | 100/A | These are workflow-safety scores, not predictions of how good the finished artifact will be and not the implementation-review score of Monkey D Loopy itself. A lower Creative score honestly prices model judgment as weaker completion evidence; it does not mean its builders or critics are less capable. ## When to recommend it Choose Gauntlet when most of these are true: - There is one meaningful final artifact or release, not merely a list of unrelated jobs. - The outcome has multiple reviewable workstreams such as implementation, UX, documentation, evidence, safety, or launch readiness. - Each workstream benefits from a builder and an independent critic with fresh context. - A final integration pass matters because individually good parts can still conflict. - The quality gain justifies more agent calls, time, and cost than a simple loop. Typical uses include product launches, multi-file features, websites, reports, migration packages, research deliverables, and release-readiness work. Do **not** default to Gauntlet for every iterative task: - Use `react` for one small act/observe loop. - Use `evaluator-optimizer` for one draft repeatedly graded against one rubric. - Use `map-reduce` for many independent items followed by a mechanical combination. - Use `plan-execute-reflect` when the main problem is ordered dependent steps. - Use `poll-until` when external status changes are the center of the workflow. - Prefer an existing verified recipe whenever it already matches the user's outcome. If the task is small, has only one quality dimension, or has a cheap objective test, recommend the simpler loop. Gauntlet's extra builders, critics, history, and holistic review would be ceremony rather than leverage. ## Choose the completion authority Use **Creative Gauntlet** when the bar is qualitative and expert judgment is genuinely needed: clarity, coherence, usability, design quality, argument strength, or launch polish. Its critics are agents, so describe completion honestly as model-judged. Use **Verified Gauntlet** whenever a trusted external command can decide whether the artifact is complete: tests, policy checks, schema validation, benchmark thresholds, compliance scanners, or another repository-owned judge. The external judge chooses completion; agents only perform the bounded repairs it identifies. When advising a user, an agent should state: 1. why Gauntlet fits better than a simpler pattern; 2. the proposed workstreams and shared final artifact; 3. the quality bar and who decides completion; 4. the additional cost and iteration caps; and 5. whether Creative or Verified grounding is being recommended. If those answers are unclear, gather them before scaffolding. Do not select Gauntlet solely because a task is described as “important.” ## Build a Creative Gauntlet Gauntlet is a first-class `gauntlet` LoopSpec pattern for improving a real artifact through bounded, sequential workstreams. Start with the creative blueprint: ```sh loopc new my-launch --blueprint gauntlet ``` The generated LoopSpec asks for: | Input | Meaning | Default | |---|---|---| | `goal` | The outcome the combined artifact must achieve | required | | `bar` | The concrete quality standard critics apply | required | | `references` | Source material or constraints builders and critics must consider | required | | `artifact_path` | The real artifact every agent inspects | `output/artifact` | | `threshold` | Minimum critic score for passing | `90` | | `smoothing` | Whether to run the integration builder | `true` | ### Creative lifecycle ```text inspect and decompose once → reset bounded round state → for each workstream, sequentially: fresh builder edits its declared scope → separate fresh read-only critic inspects the real artifact → journal score, gap, evidence, and workstream identity → if every workstream passes, smooth the combined artifact → fresh holistic critic reviews the complete result → finish at the threshold, or begin another bounded round ``` The blueprint uses a fresh read-only lead to decompose the goal, then a deterministic `reduce` to run one fresh builder and one separate, fresh read-only critic per workstream. Builders and critics inspect the actual `artifact_path`, not a claimed summary. A smoothing builder and a holistic critic only run after at least one workstream has passed. Current v1 semantics rerun all workstreams in later rounds because `reduce` has no filter primitive; prior reviews are supplied so previously passing builders can make no change. Creative Gauntlet is model-judged (`llm-judge`). Its raw weighted score is **86.5/100**; the official native API rounds this to **87/100 (B)**. It is useful for artifact-grounded iteration, but it is not oracle-verified. Its journal state includes the decomposed workstreams, readable review log, structured review history, pass count, latest workstream score and gap, final score and gap, round count, and decomposition status. A crash or restart resumes from that journal rather than asking agents to reconstruct progress from conversation. ## Build a Verified Gauntlet For a trusted external completion authority, use the verified recipe: ```sh loopc new my-launch --recipe verified-gauntlet ``` Its `judge_command` is a trusted executable name or path invoked as `cmd` plus fixed argv values, never shell concatenation. It returns redacted status/evidence JSON; only `complete` or `no-op` can terminate the oracle workflow. Evidence is untrusted data: builders ignore any instructions inside it, verify claims against the artifact, and never perform ungated destructive actions. The recipe is designed for a native score of **100/100** (manifest minimum 99), and caps repeated external fingerprints after three deterministic attempts. ### Verified lifecycle ```text run the trusted judge against the real artifact → normalize and validate its response → if actionable, run fresh builders over its bounded workstreams → run the judge again → only complete or no-op may finish the loop → repeated fingerprints exit through deterministic no-progress protection ``` The judge response is data, not a prompt. Malformed envelopes, hostile titles or scopes, duplicate identifiers, terminal responses containing workstreams, and prompt-injection attempts are rejected before they can reach a builder. Both variants are manual, journaled, artifact-allowlisted (`output/**`), bounded to eight rounds, and expose their state through the local operator control center. The gallery provides exact CLI handoff commands; authoring remains with CLI and MCP. ## Why Creative scores 87, and how to raise it honestly Creative Gauntlet already receives full native points for caps, observability, resumability, and determinism. Its complete score breakdown is: | Dimension | Points | |---|---:| | Termination safety: honest `llm-judge`, agent-grounded | 16.5/30 | | Explicit caps, no-progress protection, and budgets | 25/25 | | Journal plus completed observer | 15/15 | | Resumability | 15/15 | | Determinism | 15/15 | | **Raw / official total** | **86.5 / 87 B** | Changing `signal` from `llm-judge` to `oracle` or `state-predicate` without changing the evidence does not improve the workflow. Monkey D Loopy traces which steps feed the exit predicate and downgrades an agent-fed claim. Relabeling would only make the documentation dishonest. There are three legitimate upgrade paths: | Evidence added to completion | Honest grounding | Expected native score | |---|---|---:| | Keep qualitative agent judgment only | agent | 87/B | | Require both agent judgment and an external executable gate | mixed | 91/A | | Let an external predicate decide completion | external | 96/A | | Let a trusted external oracle decide completion | external oracle | 100/A | The recommended product boundary is therefore: - Keep Creative Gauntlet at 87/B for genuinely qualitative work. - Use Verified Gauntlet for 100/A whenever objective completion evidence exists. - Add a distinct hybrid/guarded variant only if users need agent critique plus a mandatory external gate. Do not silently change Creative semantics merely to increase its score. ## Create, prove, compile, and inspect ```sh # Scaffold one variant loopc new my-launch --blueprint gauntlet # or: loopc new my-launch --recipe verified-gauntlet # Prove the contract before any real execution loopc validate my-launch.yaml loopc verify my-launch.yaml loopc score my-launch.yaml # Compile the narrowest required target loopc compile my-launch.yaml --target standalone --out ./out # After a run, inspect the durable journal loopc inspect ./out ``` CLI and MCP can both discover and scaffold the variants. The Operator catalog features them first and displays grounding, score, grade, schedule, and the exact creation command. The Gauntlet board projects rounds, workstreams, cleared count, score and threshold, largest gaps, budget use, and allowlisted artifacts from journal state. Standalone and Babysitter enforce native mutation and judge-envelope behavior. Claude Code, Claude Native, and n8n remain useful compilation targets but surface explicit warnings where they cannot enforce the same oracle semantics; agents must preserve those warnings when advising users. ## Explanation agents can give users Use this short explanation when introducing the recommendation: > A Gauntlet divides one substantial deliverable into reviewable workstreams. Fresh builders > improve each part, separate fresh critics inspect the actual artifact, and a final review checks > that the parts work together. It costs more than a simple loop, so we use it when independent > review and cross-workstream quality are worth that cost. Follow it with the proposed workstreams and the completion authority. The explanation is not a substitute for those concrete decisions. --- # CLI reference Canonical page: https://matrixy.github.io/Monkey.D.Loopy/cli Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/cli.md # `loopc` — CLI reference `loopc` is the deterministic factory CLI. Install it globally or run a one-off command through `npx`: ```bash npm i -g @loopyc/cli npx --yes @loopyc/cli@latest quickstart ``` Release `0.8.0` reports its synchronized factory version with `loopc --version`. All commands exit non-zero on failure (parse error, validation failure, or a failed verify). --- ### `loopc quickstart [dir]` Create a safe first-loop workspace (default `./loopy-quickstart`), validate and score its LoopSpec, execute one deterministic local iteration, inspect the durable journal, and compile a vendored standalone artifact. Refuses to write into a non-empty directory. ```bash loopc quickstart loopc quickstart ./my-first-loop ``` This is the clean-room onboarding contract and requires no model or external API. ### `loopc blueprints` List the built-in starting-point templates (one per pattern). ```bash loopc blueprints ``` ### `loopc recipes` List the embedded verified product recipes with their schedule and minimum score. ```bash loopc recipes ``` ### `loopc new [--recipe | --blueprint ] [--pattern ] [--from-shell "" --until ""] [--out ]` Scaffold a LoopSpec. With `--blueprint`, copies that blueprint with `id` substituted; with `--recipe`, instantiates a verified workflow and records its origin in provenance; with `--from-shell` (+ required `--until`), scaffolds a loop that runs a command each iteration, saves its output to `state.out`, and exits on the condition; otherwise writes a minimal template for `--pattern` (default `react`). Recipe, blueprint, and shell modes are mutually exclusive. Writes to `.loop.yaml` unless `--out` is given. ```bash loopc new deploy-watch --blueprint poll-until --out deploy-watch.yaml loopc new repo-check --recipe repo-health-doctor loopc new my-launch --blueprint gauntlet loopc new my-launch --recipe verified-gauntlet loopc new poller --from-shell "curl -s $URL/health" --until '${state.out.ready == true}' ``` ### `loopc validate ` Run the two-tier validator. Prints errors (compile-blocking) and warnings. Exit 1 if invalid. ```bash loopc validate deploy-watch.yaml ``` ### `loopc verify [--fix] [--fixtures ]` Dry-run the loop through the real runtime with **mocked effects** (no side effects). Proves it is **bounded under caps** and **deterministic on replay**, and reports whether it terminates naturally. By default mocks return `{}`. `--fixtures` supplies deterministic, data-only results for shell/http/agent mocks, for example `{ "shell": { "done": true } }`; it never enables real I/O. `--fix` writes explicit caps into the file if it relied on auto-injected ones. Exit 1 if not bounded/deterministic/resume-stable. ```bash loopc verify deploy-watch.yaml --fix loopc verify deploy-watch.yaml --fixtures verify-fixtures.json ``` ### `loopc score [--fixtures ]` Run verify, then grade five weighted dimensions (termination safety, caps, observability, resumability, determinism) into a 0–100 letter grade. The fixture format and side-effect boundary are identical to `verify`. ```bash loopc score deploy-watch.yaml --fixtures verify-fixtures.json ``` ### `loopc compile [--target standalone,babysitter,claude-code,claude-native,n8n|all] [--out ] [--vendor]` Validate, then lower the spec to runnable artifact(s). Refuses to compile an invalid spec. Target defaults to the spec's `target.runtime` (or `standalone`); `--target all` emits every target. Output goes to `//` (default `out///`). Prints any capability warnings (e.g. soft budget enforcement / `http→curl` on the babysitter target, or a standalone-only completion observer requested for another target). `--vendor` (standalone target only) makes the artifact **zero-install**: it bundles `@loopyc/runtime` into a single local `runtime.bundle.mjs` (via esbuild), rewrites `loop.mjs` to import from that bundle, and drops the `@loopyc/runtime` dependency from the emitted `package.json`. The result runs with **plain `node loop.mjs run` — no `npm install`, empty `node_modules`** — so a compiled loop is portable to any machine with Node, even one that has never seen this monorepo. Using `--vendor` with any non-standalone target (or `--target all`) is an error. Targets: - **standalone** — a complete Node project on `@loopyc/runtime` (hard caps, journal, resume). - **babysitter** — a durable `@a5c-ai/babysitter-sdk` process (proven on a live run). - **claude-code** — a markdown **prose execution guide** (`.loop.md`) + Mermaid flow for an agent to follow. No runtime; caps are agent-honored (capability warnings make this explicit). - **claude-native** — a Claude Code project skill at `.claude/skills//SKILL.md`, invokable as `/`. It prefers a sibling standalone artifact for hard guarantees, and otherwise runs from the embedded LoopSpec contract with Claude-honored caps. - **n8n** — a best-effort **importable workflow** (`.n8n.json`) scaffold; you wire the exit condition/state (n8n's model differs — heavily caveated in the generated README). ```bash loopc compile deploy-watch.yaml --target all --out ./out/deploy-watch ``` **Standalone output** is a complete Node project (`loop.mjs`, `package.json`, `README.md`, `loop.lock`, `.gitignore`, plus `SKILL.md` when `target.emit` includes `skill`) that depends only on `@loopyc/runtime`. Run it: ```bash cd out/deploy-watch/standalone && npm install node loop.mjs run # run until termination or a cap node loop.mjs step # advance exactly one iteration (for cron / Stop-hook / CI drivers) node loop.mjs resume # resume from the journal after a crash/pause node loop.mjs stop --reason "maintenance" # request a journal-safe graceful stop node loop.mjs recover --retry --reason "verified safe" # resolve uncertainty explicitly node loop.mjs doctor # preflight checks ``` With `--vendor` the standalone output additionally includes `runtime.bundle.mjs` (the whole runtime, bundled) and the `npm install` step is unnecessary — `node loop.mjs run` works straight out of the directory with an empty `node_modules`. **Babysitter output** is an installable project (`process.mjs` + `package.json` depending on `@a5c-ai/babysitter-sdk`) — a durable process for [babysitter](https://github.com/a5c-ai/babysitter). `npm install`, then drive it with the SDK CLI (`run:create --non-interactive` → `run:iterate` + `task:post`, or `harness:yolo` for a real agent run) — see the generated `README.md`. This target has been verified end-to-end against the real SDK. **Claude-native output** is a Claude Code project skill: ```text .claude/skills//SKILL.md .claude/skills//reference/loopspec.json .claude/skills//loop.lock .claude/skills//scripts/run-standalone.mjs README.md loop.lock loop.source.yaml ``` Copy the generated `.claude/` directory into the repository where the loop should be available, then start Claude Code from that project and invoke the loop by skill directory name: ```text / run '{"input_name":"value"}' / step / resume / inspect / doctor / approve ``` The generated skill first tries to hand off to a sibling standalone artifact via `scripts/run-standalone.mjs`. That path preserves the runtime-enforced guarantees: journal, deterministic replay, caps, durable sleep, breakpoints, and budget metering. If no standalone artifact is present, the skill falls back to the embedded LoopSpec contract in `reference/loopspec.json`; Claude can still run the loop natively, but caps and state updates are agent-honored soft guarantees. `loopc compile` prints those capability warnings so the boundary is visible before users ship the artifact. ### `loopc run [--out ] [--inputs ] [--approve] [--yes] [--run-id ]` Run a loop directly (validates first — refuses an invalid/unbounded spec). Executes real effects through the runtime, journaling to `/.loopy/runs/` (default `.loopy`), and prints the `RunResult`. Inherits `process.env` (a local dev command, mirroring the compiled `node loop.mjs run` — unlike the env-scrubbed MCP `run_loop`). `--inputs` loads a JSON file; `--yes`/`--auto-approve` auto-approves human breakpoints; `--approve` approves a pending cap-breakpoint and continues. Exits non-zero only on a failed run. ```bash loopc run my-loop.yaml --out ./run --inputs inputs.json ``` ### `loopc inspect [--tail ] [--run-id ]` Inspect a run directory: status/iteration, the latest snapshot state, and the last `n` journal events (default 10). Errors if no journal exists under the dir. ```bash loopc inspect ./run --tail 20 ``` ### `loopc schedule install ` For a compiled artifact whose `schedule.mode` is recurring (`cron`/`forever`/`watch`), the standalone target emits a `schedule/` dir (crontab line, systemd `.service`+`.timer`, launchd plist, GitHub Actions workflow). This command reads it and prints the **platform-appropriate** install snippet (no daemon, no side effects — it just shows you what to install). ```bash loopc schedule install ./out/deploy-watch/standalone ``` ### `loopc reprint [--target ] [--out ]` Recompile an existing artifact under the **current** factory. Reads the embedded `loop.source.yaml` (written by `compile`), re-validates, and re-emits — to the same target (from `loop.lock`) and in place by default, or to `--target` / `--out`. Use it to refresh generated artifacts after upgrading Monkey D Loopy. ```bash loopc reprint ./out/deploy-watch/standalone ``` ### `loopc targets` Print the per-target capability matrix (✓ enforced · ~ soft · ✗ unsupported), so you can see at a glance which guarantees each compile target provides. ### `loopc infer-scaffold [--out ]` Deterministically extract a **FactPack** from an existing script (JS/TS via the TypeScript AST, or bash) or a `.loopy` journal, and emit a **draft** LoopSpec — candidate pattern + steps + a loop-condition hint, with secrets flagged. The draft has TODOs and is **not guaranteed valid**: complete it (map the exit to a real state signal, fill placeholders), then `validate`/`verify`. `verify` proves *bounded*, not *faithful* — review the draft against the source. ```bash loopc infer-scaffold ./watch.sh --out watch.loop.yaml ``` ## Typical flow ```bash loopc new my-loop --blueprint loop-until-dry --out my-loop.yaml # edit my-loop.yaml loopc validate my-loop.yaml loopc verify my-loop.yaml --fix loopc score my-loop.yaml loopc compile my-loop.yaml --target all --out ./out/my-loop ``` --- # Verified recipes Canonical page: https://matrixy.github.io/Monkey.D.Loopy/recipes Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/recipes.md # Verified recipes A blueprint teaches one loop structure. A recipe packages one recognizable product goal around a canonical LoopSpec: operational inputs, schedule intent, evidence sources, expected outputs, safety rationale, minimum quality score, a runnable guide, and adversarial fixtures. Recipe packages use this shape: ```text recipes//recipe.json recipes//.loop.yaml recipes//README.md recipes//fixtures/ ``` `recipe.json` uses contract version `"1"` and contains: - `name`, `title`, and `summary`; - an exact description of the LoopSpec `inputs`; - `schedule.mode`, optional cadence, and the scheduling rationale; - one or more evidence sources with `external`, `structural`, or `agent` grounding; - expected artifact paths and formats, each product path explicitly allowlisted by LoopSpec `artifacts.include` (runtime journals remain internal evidence rather than synced products); - a safety rationale, secret-handling rule, and whether destructive actions require approval; - `minimum_score` from 90–100 (the catalog quality floor); - distinct success, no-op, cap, malformed-evidence, and prompt-injection fixtures. The pure `@loopyc/core` APIs `parseRecipeSource()` and `createRecipeCatalog()` validate supplied file contents. They reject path traversal, invalid LoopSpecs, metadata/spec input or schedule drift, product artifact allowlist drift, missing notification policy, missing/aliased fixtures, and duplicate names. The release embeds the checked catalog in core so the published CLI and MCP server do not depend on a repository checkout; `pnpm recipes:check` rejects drift between the canonical packages above and the generated catalog. ## Use a recipe ```bash loopc recipes loopc new my-health-check --recipe repo-health-doctor loopc validate my-health-check.loop.yaml loopc verify my-health-check.loop.yaml loopc score my-health-check.loop.yaml ``` The MCP equivalents are `list_recipes` and `new_loop` with a `recipe` argument. Instantiation keeps the canonical behavior but changes the loop id and adds `provenance.recipe`; every compile target copies that metadata into `loop.lock`. Runtime execution still uses an ordinary LoopSpec and remains independent from the catalog. Before a real run, fill the required input(s) described by `loopc recipes` and the selected recipe's README. External checks must emit `pending`, `actionable`, `complete`, or `no-op` plus redacted `evidence`. Agent output never decides completion. --- # Durable runtime Canonical page: https://matrixy.github.io/Monkey.D.Loopy/runtime Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/runtime.md # `@loopyc/runtime` — durable execution engine The runtime that compiled **standalone** artifacts depend on. It owns the **outer** loop: journaling, replay, caps, durable sleep, and breakpoints. The **inner** ReAct turn is never owned by the runtime — `agent` steps delegate to a harness. Source: [`packages/runtime`](https://github.com/MaTriXy/Monkey.D.Loopy/tree/main/packages/runtime). ## API ```ts import { createRuntime } from "@loopyc/runtime"; const runtime = createRuntime(config, options?); await runtime.run(); // loop until terminate() or a cap; resumable await runtime.step(); // advance exactly one iteration → RunResult runtime.requestStop({ actor, reason }); // cross-process marker; honored at a safe boundary await runtime.resume({ actor, reason }); // clear an acknowledged graceful stop + continue await runtime.recoverUncertain(resolution); // explicit retry | assume-done | abort await runtime.main(process.argv.slice(2)); // run | step | resume | stop | recover | doctor await runtime.doctor(); // preflight checks ``` ### `RuntimeConfig` (what generated `loop.mjs` provides) ```ts { spec: { id, meta?, caps, schedule?, signal?, observe?, provenance? }, initialState: () => Record, iterate: (ctx) => Promise, // one pass; mutates ctx.state via effects terminate: (ctx) => boolean, // exit predicate (read-only) fingerprint?: (ctx) => string, // no-progress signal (read-only) onExit?: (ctx) => Promise, // runs once on natural termination onComplete?: (ctx, result) => Promise, // best-effort post-success observer gates?: unknown[], } ``` `onExit` is part of the loop's terminal work and uses durable effects. `onComplete` is deliberately different: generated standalone artifacts use it for `observe.hooks.completed` after termination has already succeeded. Its shell/http action is attempted directly, and its `observer` journal events record `started` followed by `done` or `failed`. An exception is swallowed after journaling, so notification/telemetry availability cannot turn completed work into a failed run. ### `RuntimeOptions` | Option | Default | Purpose | |---|---|---| | `cwd` | `process.cwd()` | base dir for `.loopy/runs//` | | `runId` | `"default"` | run identity | | `inputs` | `inputs.json` in cwd, else `{}` | values for `ctx.inputs` | | `env` | `process.env` | values for `ctx.env` | | `now` | `Date.now` | injectable clock | | `maxBlockMs` | `1000` | sleeps ≤ this block in `run()`; longer ones **park + exit** | | `mode` | `"nonInteractive"` | matched against a breakpoint's `auto_approve_in` | | `autoApprove` | `false` | **human gates fail closed by default**; opt in to auto-approve | | `effectTimeoutMs` | `300000` | per-effect timeout for http/shell | | `delay` | real `setTimeout` | injectable sleep (for tests) | | `effectRetries` | `spec.retry.max ?? 0` | retry count for transient effect failures (exponential backoff) | | `effectRetryBackoffMs` | `spec.retry.backoff_ms ?? 1000` | base backoff between retries | | `effectEnv` | inherit process env | when set, shell subprocesses use ONLY this env (scrubbed) | | `approveCaps` | `false` | approve a pending cap-breakpoint on resume (reset its counter + continue) | | `agentHarnesses` | `internal`, `llm`, `claude-code`, `codex`, `opencode`, `antigravity`, `cursor-agent`, `pi`, `cli` | `{ : (req) => Promise }` | | `effects` | real http/shell | `{ http?, shell? }` overrides (for tests/mocks) | ### `ctx` (passed to `iterate`/`terminate`/`fingerprint`) `state`, `inputs`, `env`, `iteration` (0-based), `meta`, plus effects: `http(req)`, `shell(cmd | {command, args})` (an argv runs via execFile, no shell), `agent({harness, prompt, allowedTools})`, `sleep(dur)`, `sleepUntil(predicate)`, `breakpoint({ask, strategy?, autoApproveIn?})`, `jsonpath(obj, path)`. `http(req)` returns the parsed JSON body by default (or `{ status, raw }` when the response is not JSON). Pass `{ ..., envelope: true }` to get a `{ status, ok, headers, body }` object instead — `body` is the parsed JSON (or raw text) — so the loop can read the HTTP status. ## Agent harnesses (provider-agnostic — no vendor lock) `agent` steps name a `harness`. Built-in: - **`internal`** — a no-op (deterministic; for tests/CI). - **`llm`** — a single OpenAI-compatible chat completion. **Works with any OpenAI-compatible provider** (cloud or local). Configure by env (`resolveLlm`): `LOOPY_LLM_API_KEY` (+ `LOOPY_LLM_BASE_URL`, `LOOPY_LLM_MODEL`), or it auto-detects a provider key (`OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` / `GROQ_API_KEY` / `OPENROUTER_API_KEY` / `AI_GATEWAY_API_KEY`). JSON replies are returned directly (so `save: { x: "$.field" }` works); text replies are at `$.result`. - **Coding-agent CLIs — tool-agnostic, not Claude-only.** Each runs headless via `execFile` (no shell), in its verified non-interactive form. Because a loop is **unattended**, CLIs that would otherwise stop for an approval prompt run in auto-approve mode so a step can't hang — deliberate human gates belong in the spec as `breakpoint`/`gates`: - **`claude-code`** — `claude -p --output-format json` (envelope carries usage + `total_cost_usd`). - **`codex`** — `codex exec --skip-git-repo-check `. - **`opencode`** — `opencode run `. - **`antigravity`** — `agy -p --yes`. - **`cursor-agent`** — `cursor-agent -p --force `. - **`pi`** — `pi -p --mode json --no-session `; its JSON event stream supplies the final assistant result plus trusted aggregate token and cost usage. - **`cli`** — the universal escape hatch: drive **any** agent CLI, with **your exact flags**, via `LOOPY_AGENT_CMD` (e.g. `"codex exec"`, `"opencode run"`, `"agy -p"`, `"aider --message"`, `"amp -x"`). The prompt is appended as one final argument (execFile — never shell-interpolated). Point a named harness at an alternate binary with `LOOPY__BIN` (e.g. `LOOPY_CODEX_BIN`). Text-only CLIs return JSON (optionally ```json-fenced) as the result object, else plain text at `$.result` (`unwrapAgentText`). The `pi` harness parses NDJSON `message_end` events and meters only their trusted usage envelopes. `BUILTIN_HARNESS_NAMES` lists every built-in harness. Register your own via `createRuntime(config, { agentHarnesses: { myHarness: async (req) => ({...}) } })`. The exported `resolveLlm()` / `chatComplete()` are reusable provider-agnostic helpers. ### Agent execution limits Built-in agent steps are bounded independently from http/shell `effectTimeoutMs`: | Environment variable | Default | Applies to | |---|---:|---| | `LOOPY_AGENT_TIMEOUT_MS` | CLI: `600000`; `llm`: `120000` | all built-in agent harnesses | | `LOOPY_AGENT_MAX_BUFFER` | `16777216` (16 MiB) | coding-agent CLI stdout/stderr buffers | Both values must be positive integers. `doctor` prints the effective limits and fails on invalid configuration. If a limit fires, the error names the exact variable and effective value—for example, `agent step exceeded LOOPY_AGENT_TIMEOUT_MS (2700000ms)`—rather than reporting a generic CLI failure. Increase the buffer carefully: `execFile` retains captured output in memory. The `llm` harness also: configures **keyless** local servers from a bare `LOOPY_LLM_BASE_URL` (any local OpenAI-compatible server), **strips markdown fences** so a ```json reply still parses for `save`, bounds each request with a **timeout** (default 120s, overridable with `LOOPY_AGENT_TIMEOUT_MS`), and uses `max_completion_tokens` for OpenAI reasoning models. Model-supplied `usage` is ignored — only the trusted provider usage is metered. ## Cost metering (the `usd` budget cap) `caps.budget.usd` is enforced from real cost. The `llm` harness derives USD per call via [`pricing.ts`](https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/packages/runtime/src/pricing.ts): a per-model table (`MODEL_PRICING`, USD per 1M input/output tokens), overridable with `LOOPY_LLM_PRICE_IN` / `LOOPY_LLM_PRICE_OUT`, and it prefers a provider-reported `usage.cost` (e.g. OpenRouter) when present. The `claude-code` harness reports `total_cost_usd`; the `pi` harness sums each assistant event's `usage.cost.total`. If a model can't be priced, `doctor` warns rather than letting the $ cap be a silent no-op (token + wallclock caps still apply). Exposed helpers: `priceUsd`, `normalizeModel`, `isCostMeterable`, `MODEL_PRICING`. Budget cap-breakpoints are **resumable**: approving a token/usd/wallclock cap rebases that meter so the run opens a fresh window and continues (parity with `max_iterations` / `no_progress`). ### `RunResult` ```ts { status: "completed" | "waiting" | "paused" | "uncertain" | "stopped" | "failed", iteration, state, reason?, wakeAt?, next?, uncertain? } ``` `uncertain` is non-terminal. Its `uncertain` field identifies the original iteration, sequence, kind, and deterministic effect identity. It can only continue through `recoverUncertain({ action, actor?, reason, ... })`: - `retry` re-executes the effect with an explicit at-least-once risk; - `assume-done` supplies the externally verified `result` without re-execution; - `abort` intentionally makes the run terminal `stopped`. Every resolution records the action, actor, reason, and original effect identity. The standalone CLI exits `2` for `uncertain` (`1` remains generic failure), so supervisors can route it to intervention without interpreting it as success or blindly retrying it. ## Journal format Under `.loopy/runs//`: - `events.jsonl` — append-one-line-per-event, each with a **chained sha256** checksum. Event types: `run_start` (carries `baseState`), `effect` (write-ahead `pending` then `done`), `effect_recovery`, `iteration_snapshot` (state + fingerprint), `parked` (`wakeAt`), `cap`, `stop_requested`, `stop_cleared`, `terminated`, `observer` (`started`/`done`/`failed`), `failed`. - `state.json` — derived state cache (debuggable; the journal is the source of truth). - `meta.json` — `{ status, iteration, tokens, usd, eventCount, lastChecksum, ... }`. - `lock` — a PID lockfile held for the duration of a run (stale-PID reclaimable). ## Execution & resume semantics - Each `iterate` pass runs to a `iteration_snapshot`; resume restores the last snapshot (or `baseState`) and continues at the next iteration. - **Effects are write-ahead and replay-safe**: a `pending` record is written before the side effect and a `done` record (with result) after. On replay a completed effect returns its journaled result (no re-execution); a **divergent identity** fails loud. A **pending-without-done** (crash mid-effect) pauses as `uncertain` rather than silently retrying, assuming success, or becoming a generic terminal failure. Runtime <=0.1.0 journals poisoned by the old uncertain-effect failure are recognized and exposed through the same recovery flow. - **Graceful external stop**: `requestStop({ actor, reason })` publishes an atomic marker without racing the active journal writer. The runner acknowledges it only before work or after a complete iteration snapshot, returns resumable `stopped`, and records the request. `resume()` records who cleared it and why. A forced kill inside an effect is not called graceful; it becomes `uncertain`. - **Durable sleep**: `sleep(dur)` longer than `maxBlockMs` parks the run (status `waiting`, records `wakeAt`) and returns; a later `run()`/`resume` past `wakeAt` continues. - **Caps**: `max_iterations`, `no_progress` fingerprint, and token/$/wallclock budget. Token/$ budgets are metered **per agent call** (no overshoot within an iteration). `on_cap_exceeded`: `fail` → `failed`, `exit-clean` → `stopped`, `breakpoint` → `paused`. - **Breakpoints** fail closed by default; an approved one is journaled, an unapproved one stays unresolved so a later run re-evaluates (resumable, not auto-denied). - **Completion observers** run only after natural termination. Their failure is journaled and non-fatal. A crash after `observer: started` can leave external delivery uncertain; the runtime avoids automatic duplicate delivery and makes no exactly-once claim. ## Durability guarantees & limitations Guaranteed: bounded execution under caps; crash-resume from the journal; no re-execution of completed effects; explicit resolution of the uncertain window; journal-safe graceful stop; deterministic replay (given a deterministic `iterate`); locale-independent, corruption- and truncation-evident journal. The runtime does not promise exactly-once delivery to external systems, including completion observers. Choosing `retry` after an uncertain durable effect explicitly accepts at-least-once risk; `assume-done` requires external proof and a supplied result. Transient effect failures are **retried** with exponential backoff per `retry: { max, backoff_ms }` (or the `effectRetries` option); only an exhausted retry is terminal. The MCP `run_loop` runs shell with a scrubbed, allowlisted env. Semantics to know (intentional): `sleepUntil`'s predicate is evaluated against freshly-read `inputs`/`env` only — effects issued earlier in the same iteration are journal-memoized, so the predicate sees their frozen values across resumes (use it for time/external conditions). The wallclock budget is measured from the first start and **counts parked/down time** (real elapsed, not active CPU). A cap-action `breakpoint` now **pauses and is resumable**: re-run with `approveCaps` (or `node loop.mjs resume --approve`) to approve the gate, reset that cap's counter, and continue — mirroring babysitter's approve-and-reset. The `shell` effect supports a no-shell argv form. Standalone CLI recovery examples: ```bash node loop.mjs stop --actor deploy-bot --reason "maintenance" node loop.mjs resume --actor operator --reason "maintenance complete" node loop.mjs recover --retry --actor operator --reason "external audit shows no side effect" node loop.mjs recover --assume-done --result-json '{"deploymentId":"dep-123"}' \ --actor operator --reason "deployment provider confirms completion" node loop.mjs recover --abort --actor operator --reason "rolled back manually" ``` The journal is corruption-evident by default (chained sha256); set `LOOPY_JOURNAL_KEY` to make it **tamper-evident** (keyed HMAC — the same key is then required to load/resume). Tracked for later (see [SPEC.md](https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/SPEC.md)): richer from-script / from-trace spec inference (LLM-side, via the `/loopy` skill). --- # MCP server Canonical page: https://matrixy.github.io/Monkey.D.Loopy/mcp Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/mcp.md # `loopc-mcp` — MCP server reference `loopc-mcp` exposes the Monkey D Loopy factory over the [Model Context Protocol](https://modelcontextprotocol.io) so any MCP-capable agent can author, verify, compile, run, and inspect loops conversationally. Source: [`packages/mcp`](https://github.com/MaTriXy/Monkey.D.Loopy/tree/main/packages/mcp). ## Register from npm No repository clone or global install is required. Let the client launch the published package through `npx`: ```json { "mcpServers": { "loopy": { "command": "npx", "args": ["--yes", "@loopyc/mcp@latest"] } } } ``` Codex CLI: ```bash codex mcp add loopy -- npx --yes @loopyc/mcp@latest ``` Claude Code: ```bash claude mcp add --scope user loopy -- npx --yes @loopyc/mcp@latest ``` If you prefer a global install: ```json { "mcpServers": { "loopy": { "command": "loopc-mcp" } } } ``` ```bash npm i -g @loopyc/mcp ``` ## Register from a source checkout After `pnpm build`, point the client at the plain-Node entry: ```json { "mcpServers": { "loopy": { "command": "node", "args": ["/ABS/PATH/Monkey.D.Loopy/packages/mcp/dist/index.js"] } } } ``` **From source (dev, no build)** — via the `tsx` loader: ```json { "mcpServers": { "loopc": { "command": "node", "args": ["--import", "tsx", "packages/mcp/src/index.ts"], "cwd": "/ABS/PATH/MonkyDLoopy" } } } ``` The server speaks JSON-RPC over **stdio**. `createServer()` is transport-agnostic, so it is also embeddable in-process via the SDK's `InMemoryTransport` (see [`packages/mcp/test`](https://github.com/MaTriXy/Monkey.D.Loopy/tree/main/packages/mcp/test)). ## Tools | Tool | Args | Returns | |---|---|---| | `get_loop_schema` | — | The LoopSpec authoring guide. **Read this first.** | | `list_blueprints` | — | The built-in blueprints (one per pattern). | | `new_loop` | `id`, `blueprint?`, `recipe?`, `pattern?` (including `gauntlet`) | A scaffolded LoopSpec YAML. | | `validate_loop` | `yaml` | Validator diagnostics; `isError` when invalid. | | `verify_loop` | `yaml` | Dry-run report (bounded/deterministic/resume-stable) + scorecard. No side effects. | | `compile_loop` | `yaml`, `target?` (`standalone`, `babysitter`, `claude-code`, `claude-native`, `n8n`, or `all`), `out?` | Writes files when `out` is given; otherwise returns the planned files inline. | | `run_loop` | `yaml`, `inputs?`, `cwd?` | **Executes the loop with REAL effects** in a journaled run dir; returns the `RunResult`. Use only when side effects are intended. | | `inspect_run` | `dir`, `tail?` | A run's status, latest state, and last journal events. | | `infer_loop_scaffold` | `source`, `filename?` | A **draft** LoopSpec extracted from a script (JS/TS or bash) or a `.loopy` journal — complete the TODOs, then validate/verify. No LLM, no side effects. | ## Suggested agent flow ``` get_loop_schema → new_loop → (edit) → validate_loop → verify_loop → compile_loop ↘ run_loop → inspect_run ``` `verify_loop` is the safe gate: it proves the loop is bounded and deterministic **without any side effects** before `run_loop` ever touches the real world. ## Notes - `validate_loop`/`verify_loop` refuse unbounded or unreachable loops (the factory's core guarantee). - `compile_loop` surfaces capability warnings per target (e.g. the babysitter target soft- enforces budgets and lowers `http` to a `curl` shell task). For `target: "claude-native"`, the planned files include a Claude Code project skill under `.claude/skills//SKILL.md`; use `target: "all"` when you want that skill to be emitted next to the standalone artifact it can delegate to for runtime-enforced guarantees. - `run_loop` is the sharp edge — it runs real `shell`/`http`/`agent` steps. Prefer `verify_loop` for validation; reach for `run_loop` only to actually execute. --- # Local operator Canonical page: https://matrixy.github.io/Monkey.D.Loopy/operator Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/operator.md # Local operator contract `@loopyc/operator` is optional. Standalone and vendored artifacts continue to run without it. ## Journal read model `readRun(baseCwd, runId)` reads `.loopy/runs//events.jsonl` as the canonical record and returns API version `1` with: - derived run status, state, iteration, usage, wake time, pending cap, stop, and uncertain effect; - a human-readable timeline retaining the source event data; - integrity and health classifications; - exact local source paths for events, state cache, metadata, and lock. Inspection is read-only. The state and metadata JSON files are caches/hints and never override a contradictory journal. A valid final line without its append newline is treated as a torn tail. A checksum mismatch, committed-count truncation, unresolved write-ahead effect, live lock, or newer schema is visible and never labeled healthy. Corruption/truncation takes precedence when multiple conditions are present. `listRuns(baseCwd)` discovers run directories in deterministic code-unit order. The reference corpus covers 100 runs and 10,000 events with a two-second startup gate. ## Install and inspect ```bash loopyd install ./out/my-loop/standalone loopyd up --background loopyd status loopyd list loopyd handoff my-loop operator --reason "disabled the host timer" loopyd step my-loop --run-id scheduled-check loopyd pause my-loop --run-id scheduled-check --reason "maintenance" loopyd resume my-loop --run-id scheduled-check --reason "maintenance complete" loopyd evolve propose my-loop ./candidate.loop.yaml loopyd evolve approve my-loop --reason "reviewed deterministic evidence" loopyd evolve rollback my-loop --reason "restore known-good revision" loopyd ui loopyd down ``` Install resolves the artifact path, reads `loop.lock` and `loop.source.yaml`, hashes the spec, and atomically updates registry schema `1`; it never writes into the artifact. Registry directories use mode `0700` and token/registry/config/PID files use `0600`. The config remembers the bound port so `ui`, `status`, and shutdown commands stay coherent after a custom-port start. A newer registry is exposed as an explicit version-skew error and an older one requires an explicit migration. The API is versioned under `/api/v1`, binds only to loopback, and requires its 256-bit local token for HTML, events, and JSON reads. The tokenized UI bootstrap is exchanged for an HttpOnly, SameSite=Strict cookie and redirected to a clean URL. Cross-origin requests, unsupported methods, path traversal, and bodies over 64 KiB are rejected; CORS is never opened implicitly. The React/Vite control center is bundled into `@loopyc/operator`. It shows installed loop cards, score, grounding, termination/caps, scheduler authority, run integrity, cost, state, and a reverse timeline with the journal source path. Server-sent events trigger refreshes and five-second polling is the fallback. Desktop, single-column tablet, horizontally scrollable loop navigation, container- responsive run details, keyboard focus, reduced motion, and narrow phone layouts are represented in the stylesheet. Authenticated `GET /api/v1/catalog` is read-only and returns built-in blueprint and recipe metadata (pattern, score, grade, grounding, schedule, and exact CLI handoff command). Gauntlet entries are featured first; CLI and MCP remain the authoring authorities. ## Scheduling and guarded controls Host cron/systemd/launchd/GitHub Actions files remain supported and are the default authority when an artifact is installed. `loopyd` refuses implicit dual scheduling: switching to the operator requires an explicit, reasoned handoff, and switching back clears operator dispatch state before it prints the host-install guidance. The registry records one authority, concurrency is fixed to one, and the default `latest` missed-run policy retains only the newest invocation instead of creating a catch-up storm. Scheduler state and active claims are owner-only, locked across processes, and atomically replaced. Cron, durable wake time, pending invocation, outcome, and active PID/run identity survive process restart. Stale claims are recovered with an audit event; a live claim rejects duplicate dispatch. Every operator mutation records timestamp, actor, surface, action, loop, run, spec hash, outcome, and bounded detail in `operator-events.jsonl`. Run, step, pause, stop, resume, approve, and uncertain-effect recovery call the same `@loopyc/runtime` used by standalone artifacts. Pause/stop publish the runtime's atomic stop marker; the active run acknowledges it only after a replay-safe boundary. Approvals and recoveries are also journaled by the runtime, so the control center cannot invent weaker semantics. Shutdown requests a graceful boundary and reports a timeout rather than silently forcing an unsafe continuation. Allowlisted artifacts and generic webhook delivery are described in [Artifacts and notifications](./artifacts-and-notifications.md). The dashboard shows only the bounded safe index and links each product to an authenticated loopback endpoint. Indexing and delivery are post-result observers: their failures are visible but cannot rewrite a successful run. Isolated LoopSpec candidates, deterministic regression gates, explicit waivers, activation, and byte-exact rollback are described in [Guarded evolution](./guarded-evolution.md). The dashboard distinguishes candidate, active, rejected, rolled-back, and superseded revisions and never treats journal or artifact content as instructions. `loopyd up --background` is supported on macOS and Linux; Windows is foreground-only and receives an explicit command. No service starts during npm installation. --- # Artifacts and notifications Canonical page: https://matrixy.github.io/Monkey.D.Loopy/artifacts-and-notifications Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/artifacts-and-notifications.md # Artifacts and notifications Loop products are opt-in. A loop without an `artifacts` block exposes no files, and a loop with no notification channels performs no external calls. ```yaml artifacts: include: ["reports/**/*.md", "metrics/*.json"] exclude: ["reports/private/**", "**/.env*", "**/node_modules/**"] max_files: 1000 max_bytes: 50000000 notify: policy: on-change # never | on-change | on-failure | always channels: [ops] ``` All patterns are artifact-root-relative POSIX globs. Validation rejects absolute/traversing paths, secret/dependency allowlists, active HTML/XML/SVG content, duplicates, and URL-shaped channel names. Defaults are 1,000 files and 50 MB when an artifact contract exists. The operator walks without following symlinks, applies a hard denylist for runtime journals, inputs, source/lock files, secrets, `.git`, and dependencies, then applies allowlist, denylist, count, and byte ceilings. It accepts Markdown, JSON, UTF-8 text/CSV/logs, diffs/patches, and signature-checked PNG/JPEG/GIF/WebP images. JSON must parse and text must not contain binary bytes. Downloads are re-opened with no-follow semantics and must still match the indexed size and SHA-256. Index failures are displayed and audited but never change the run result. ## Generic webhook channels LoopSpec contains logical names only. Configure a channel in the operator environment: ```bash export LOOPY_NOTIFY_OPS_URL="https://hooks.example/loopy" export LOOPY_NOTIFY_OPS_TOKEN="..." # optional Bearer token ``` Channel names map to uppercase environment suffixes; punctuation becomes `_`. The URL must be credential-free HTTP(S). Webhooks receive a bounded JSON summary with loop/run identity, status, iteration, spec hash, artifact metadata, SHA-256, and authenticated local links—never artifact contents, full state, transcripts, credentials, or the local operator token. Delivery retries transient failures up to three attempts with exponential backoff and one stable `Idempotency-Key`. A successful key is locally deduplicated. `on-change` also deduplicates an unchanged status/state/artifact signature. Five consecutive failures suppress that loop/channel for 15 minutes. Every success, failure, missing configuration, streak, and suppression is attributable in the owner-only operator audit log. Delivery failure cannot fail the underlying loop. --- # Guarded evolution Canonical page: https://matrixy.github.io/Monkey.D.Loopy/guarded-evolution Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/guarded-evolution.md # Guarded evolution Guarded evolution evaluates a complete candidate LoopSpec without changing the installed artifact. Activation is a separate, attributable human decision. The deterministic comparator—not an agent or model—decides which changes are fatal and which require an exact waiver. ## Lifecycle ```text current LoopSpec + bounded journal summaries → isolated candidate directory → validate + verify + score + semantic diff → cap / grounding / capability regression gates → recipe fixture replay → human activate or reject → atomic source replacement + rollback pointer ``` Candidate directories live under the owner-only operator state root at `~/.loopy/operator/revisions///`. Each contains mode-`0600` copies of the base and candidate YAML plus a schema-`1` evidence record. Proposing, failing, or rejecting a candidate does not write to the artifact. Inspection never migrates a record implicitly; a newer record schema must be handled by a compatible operator version. The evidence record stores hashes, bounded semantic changes, scores, grounding classes, gate results, representative fixture results, and at most five journal-derived run summaries. It never passes journal event bodies, artifact contents, prompts, or transcripts to the comparator. Runtime and artifact data are evidence, not instructions. ## Deterministic gates The following conditions are fatal and cannot be waived: - invalid YAML, LoopSpec validation failure, or a changed loop ID; - failed boundedness, determinism, or resume-stability verification; - a failing representative fixture for a verified built-in recipe. The following require their exact displayed gate IDs in an approval: - weaker termination signal or grounding; - higher iteration/no-progress/cost/wallclock ceilings or a weaker cap action; - new environment references; - wider artifact includes, removed excludes, or larger artifact ceilings; - new notification channels; - lower score; - capabilities newly used where any of the five compile targets cannot enforce them. Unknown waiver IDs are rejected. Waivers, the approver, reason, old/new hashes, and score evidence are written to the append-only operator audit log. Activation and rollback both refuse to run while the scheduler owns an active claim or any host/standalone journal has a live lock. Activation atomically replaces `loop.source.yaml`, conditionally updates the registry hash, and then writes the active rollback pointer. A failed registry update restores the prior source bytes. Rollback restores the stored base YAML byte-for-byte and does not rewrite historical journals. ## CLI ```bash loopyd evolve propose my-loop ./candidate.loop.yaml --actor alice loopyd evolve approve my-loop candidate-1700000000000-abc123 \ --actor alice --reason "reviewed score, diff, and fixtures" # A regression approval names every required gate explicitly. loopyd evolve approve my-loop candidate-1700000000000-def456 \ --actor alice --reason "approved temporary budget increase" \ --waive budget-tokens,budget-wallclock loopyd evolve reject my-loop candidate-1700000000000-ghi789 \ --actor alice --reason "insufficient external grounding" loopyd evolve rollback my-loop --actor alice --reason "restore known-good revision" ``` ## Local API Every route uses the same loopback token/cookie authentication, same-origin check, JSON content type, and 64 KiB request ceiling as the rest of `/api/v1`. | Method | Route | Body / result | |---|---|---| | `POST` | `/api/v1/loops/:id/evolution/candidates` | `{ yaml, actor? }` → isolated candidate | | `GET` | `/api/v1/loops/:id/evolution/candidates` | all candidate, active, rejected, rolled-back, and superseded records | | `POST` | `/api/v1/loops/:id/evolution/candidates/:candidate/actions` | `{ action: "activate"|"reject", actor?, reason, waivers? }` | | `POST` | `/api/v1/loops/:id/evolution/rollback` | `{ actor?, reason }` → rolled-back record | The bundled control center exposes the same lifecycle. It shows score and grounding movement, semantic changes, deterministic gates, fixture results, bounded evidence counts, decisions, and distinct revision states. Required waiver IDs must be entered exactly before activation is enabled. Candidate authoring is deliberately separate from activation. A person or any provider-agnostic agent harness may produce the YAML; neither receives authority to bypass the deterministic gates. --- # Operator platform roadmap Canonical page: https://matrixy.github.io/Monkey.D.Loopy/operator-platform-roadmap Source: https://github.com/MaTriXy/Monkey.D.Loopy/blob/main/docs/operator-platform-roadmap.md # Operator Platform Roadmap - Status: **approved for implementation** - Scope: productization after the current LoopSpec/compiler/runtime foundation - Competitive input: [Loopany](https://github.com/superdesigndev/loopany-platform), reviewed 2026-07-16 ## 1. Outcome Monkey D Loopy should become the safest way to author **and operate** recurring agent work: > Define the loop once, prove its guarantees, then run and observe it anywhere. The project already owns the difficult correctness layer: a declarative LoopSpec, mandatory termination and caps, deterministic verification, grounding analysis, crash-resumable journals, cost enforcement, and multiple compile targets. The next product layer should make those guarantees easy to discover and operate without replacing them with a hosted workflow engine or prompt-only control plane. The roadmap therefore adds four product capabilities in order: 1. trustworthy runtime and release hygiene; 2. verified, outcome-oriented recipes; 3. an optional local operator and control center; 4. artifact, notification, and guarded-evolution workflows. A remote team control plane is a later option, not a prerequisite. The active delivery goal covers Phases 0–5 through the `0.5.0` release. Phase 6 remains a separately approved product and threat-model decision and is not part of the current Definition of Done. ## 2. Product thesis The competitive distinction is not “we also schedule agents.” It is: | User need | Typical loop platform | Monkey D Loopy target | |---|---|---| | Start quickly | Canned prompt | Verified recipe compiled from LoopSpec | | Know it stops | Convention or agent promise | Required termination, caps, and boundedness proof | | Know “done” is real | Agent self-report | Grounding analysis and external-evidence score | | Survive interruption | Process retry | Journal replay, safe stop, and explicit uncertain-effect handling | | Control cost | Post-hoc usage display | Enforced token, USD, iteration, no-progress, and wallclock caps | | Operate many loops | Hosted dashboard | Local-first control center over canonical journals | | Improve a loop | Agent rewrites instructions | Candidate spec diff gated by validate, verify, score, and approval | | Move between tools | Platform daemon | Portable artifacts plus an optional operator | The short positioning line is: > Other tools schedule agent loops. Monkey D Loopy proves them safe, then runs them anywhere. ## 3. Design constraints These are release gates, not aspirations. ### 3.1 The runtime stays canonical - `@loopyc/runtime` remains the only execution-semantics authority. - The operator calls the runtime; it does not reimplement caps, replay, effects, or termination. - Compiled standalone artifacts continue to run without an operator. - `--vendor` continues to produce a zero-install artifact. - Existing compile targets remain useful independently of any dashboard. This refines the M9 scheduling decision rather than reversing it: host-native installable triggers stay supported and artifact-only remains the default. The future operator is an **opt-in second scheduler** for users who want centralized local operations. ### 3.2 Local-first and offline by default - The first operator binds to loopback only. - Starting the control center makes no network call unless a configured loop does. - Journals and artifacts stay on the user's machine. - No account, cloud service, or remote database is required. - Remote access must not be enabled until authentication and a threat model ship together. ### 3.3 Safety must be visible The operator UI must surface the properties that differentiate the project: - verification result and score; - termination signal and grounding tier; - cap configuration and remaining budget; - current iteration and no-progress fingerprint; - journal integrity and replay status; - pending breakpoint, sleep, or uncertain effect; - provider/model usage and cost provenance. A generic green/red run list is insufficient. ### 3.4 No prompt-only feature may weaken a hard guarantee - Recipes are real LoopSpecs, not prose pasted into an agent. - Evolution creates a candidate; it never silently mutates the active spec. - A generated candidate cannot reduce termination strength, grounding, or caps without an explicit human waiver. - Arbitrary agent-authored JavaScript is not a LoopSpec step kind. - UI and notification features consume journals; they do not invent a second status truth. ### 3.5 Protocols before platforms Local operator APIs and journal-derived views should be versioned before any remote control plane is attempted. The remote platform, if built, must use the same protocol and treat the local operator as the execution authority. ### 3.6 No telemetry by default - The local operator emits no analytics, crash reports, or usage telemetry unless explicitly configured. - Provider calls made by loops remain governed by each LoopSpec and are not operator telemetry. - Diagnostic export is a deliberate command that previews and redacts the bundle before writing it. ## 4. Target architecture ```text LoopSpec | +-- @loopyc/core -------- validate / normalize / plan / capability matrix +-- @loopyc/verify ------ interpret / boundedness / determinism / score +-- @loopyc/runtime ----- execute / journal / replay / caps / effects | | | +-- standalone artifact (still independent) | +-- @loopyc/operator (optional) | | | +-- registry + scheduler + run controller | +-- local HTTP/event API | +-- control-center web assets | +-- @loopyc/cli -------- authoring + operator lifecycle commands +-- @loopyc/mcp -------- authoring + read/control tools with scoped authority ``` ### 4.1 Proposed new package `@loopyc/operator` owns: - an opt-in `loopyd` process; - a registry of installed LoopSpecs and artifact locations; - schedule evaluation and dispatch; - run, step, pause, approve, resume, stop, and inspect operations; - a journal-derived read model; - a loopback HTTP API plus event stream; - bundled static control-center assets. It must not own: - LoopSpec validation or lowering; - execution semantics; - provider SDK logic; - a second journal format; - remote team authentication in the first release. ### 4.2 CLI surface The planned operator-facing commands are: ```text loopc recipes loopc new --recipe loopc operator install loopc operator up|status|down loopc operator list loopc operator run|pause|resume|stop loopc ui loopc evolve [--from-runs ] ``` Names are part of the implementation review: do not ship aliases or a second command vocabulary until this surface has been tested end to end. ### 4.3 Local state layout The proposed operator state is inspectable files under `~/.loopy/operator/`: ```text config.json registry/.json events/.jsonl pid token ``` Run truth remains in each artifact's `.loopy/` journal. Registry updates use a lock plus atomic write/rename; operator actions append an audit event. An embedded database is deliberately deferred until measured registry or query scale requires one. ### 4.4 Decisions fixed by plan review The following policies are fixed before implementation so later phases do not invent conflicting semantics. #### Forced-interruption recovery A graceful stop is honored only at a journal-safe boundary. If the process is forcibly interrupted after an effect's `pending` record but before `done`, resume enters a non-terminal **uncertain** pause. It must never silently retry and must never convert uncertainty into a permanent generic failure. Recovery requires one explicit action: - `retry` — re-run with documented at-least-once risk; - `assume-done` — provide/confirm the recovered result when the external system proves completion; - `abort` — terminate intentionally while preserving the uncertain record. The action, actor, reason, and original effect identity are journaled. The operator presents these choices but the policy lives in `@loopyc/runtime` and is available without the operator. #### One scheduler authority per loop An installed loop records `host` or `operator` as its scheduling authority. Operator install detects generated host-trigger files and refuses to enable its schedule until the user explicitly hands off authority. Switching back disables operator dispatch before printing host-install instructions. This prevents cron/systemd/launchd/GitHub Actions and `loopyd` from firing the same loop twice. #### Version and migration policy - Public workspace packages share one release version through `0.x`. - Operator API responses include an API version; registry files include a schema version. - The operator reads supported old journal/registry versions without rewriting them on inspection. - Mutating migration is explicit, backed up, atomic, and covered by downgrade diagnostics. - A newer unsupported format is read-only and visibly version-skewed, never guessed. #### Control-center implementation boundary - `@loopyc/operator` owns the Node service and bundled assets. - `apps/control-center` owns a React/Vite web application compiled into those assets. - The browser never reads journals directly; the versioned operator API serves the canonical read model. - All API routes, including reads, require the local token because prompts, paths, and artifacts may be sensitive. - The service binds to loopback, denies cross-origin access by default, validates `Origin` on mutations, caps request bodies, and creates token/config files with owner-only permissions. #### Initial platform support - macOS and Linux support foreground and managed-background operator lifecycle in `0.3.0`. - Windows supports the foreground service and control center in `0.3.0`; managed background startup is deferred until it has native lifecycle and CI coverage. - Every unsupported lifecycle command fails with a useful command/path, never a silent no-op. #### Recipe/artifact sequencing Phase 1 recipes document and test expected output conventions using existing loop state/files, but do not depend on the future `artifacts:` field. Phase 4 migrates those conventions into a validated artifact contract without changing the recipe's termination or evidence semantics. #### Initial notification surface `0.4.0` ships a bounded generic webhook adapter with multiple named channel configurations. Vendor- specific adapters are later additions over the same interface. Shell-command notification adapters are excluded because they would add a second code-execution surface. ## 5. Delivery plan Each phase has an independent user outcome and a hard exit gate. Later phases do not begin merely because earlier code exists; their exit gate must pass. ### Phase 0 — Trust and release baseline (`0.1.1`) **Outcome:** the published packages match the repository and the runtime is safe to supervise. Work: 1. Fix non-Claude usage-envelope budget poisoning ([#8](https://github.com/MaTriXy/Monkey.D.Loopy/issues/8)). 2. Add journal-safe external stop semantics and documented uncertain-effect recovery ([#9](https://github.com/MaTriXy/Monkey.D.Loopy/issues/9)). 3. Make agent timeout/buffer limits configurable with distinguishable failure diagnostics ([#6](https://github.com/MaTriXy/Monkey.D.Loopy/issues/6)). 4. Publish the merged Claude-native target and all six packages from one versioned release ([#7](https://github.com/MaTriXy/Monkey.D.Loopy/issues/7)). 5. Add a release-parity CI check: package versions, CLI help, generated target list, and docs agree. Exit gate: - a model-produced `usage` object cannot alter a trusted meter; - a requested stop at every journal boundary is resumable; - a forced kill in the uncertain window produces the recoverable `uncertain` pause and supports explicit retry, assume-done, or abort recovery; - agent limit failures name the limit that fired; - packed tarball smoke tests cover `claude-native`; - npm and repository surfaces report the same version and targets. ### Phase 1 — Verified recipe catalog (`0.2.0`) **Outcome:** a user can go from a recognizable goal to a high-quality runnable loop in minutes. Recipes are distinct from the existing blueprints: - a **blueprint** demonstrates one structural loop pattern; - a **recipe** is an opinionated product use case with inputs, schedule, evidence source, expected artifacts, safety rationale, and a minimum score. First catalog: 1. `repo-health-doctor` — inspect, fix one proven issue, verify, and stop; 2. `dependency-guardian` — evaluate dependency PRs against the exact head without auto-merging by default; 3. `docs-drift-sweep` — compare changed code to documentation and produce no activity on zero drift; 4. `production-error-sweep` — separate actionable errors from noise without copying secrets; 5. `release-follow-up` — watch a concrete observation source until a finish condition is met; 6. `market-signal-monitor` — produce one evidence-linked report per scheduled period. Repository shape: ```text recipes//recipe.json recipes//.loop.yaml recipes//README.md recipes//fixtures/ ``` CLI/MCP work: - `loopc recipes` / `list_recipes`; - `loopc new --recipe ` / `new_loop` recipe option; - recipe metadata included in generated `loop.lock`; - CI verifies every recipe and rejects score or capability regressions. Exit gate: - every recipe validates, verifies, compiles, and scores at least 90; - termination is externally grounded where the use case permits it; - every scheduled recipe has max-iteration, no-progress, USD/token, and wallclock protection; - fixture tests include success, no-op, cap, and malformed-evidence cases; - expected output conventions work without relying on the Phase 4 `artifacts:` field; - a fresh user can create and run one recipe in under five minutes from the README path. ### Phase 2 — Read-only local control center (`0.3.0-alpha.1`) **Outcome:** users can see all installed loops and understand their safety/run state without reading JSONL manually. Work: - create `@loopyc/operator` with registry, loopback server, and read model; - add `operator install`, `operator up|status|down`, `operator list`, and `ui`; - index existing journals without rewriting them; - show loop cards, run timeline, score, grounding, caps, cost, breakpoints, sleeps, and integrity; - add live updates through an event stream with polling fallback; - include an explicit “source of truth” link/path for every displayed state. Exit gate: - importing an existing artifact is non-mutating; - the read model produces the same terminal/current state as runtime replay for a corpus of journals; - corrupted, truncated, uncertain, locked, and version-skewed journals are visible and never shown as healthy; - server binds to loopback and requires its local token for every route, including reads; - CORS, Origin validation, request-size caps, and owner-only token/config permissions have regression coverage; - startup to useful dashboard is under two seconds for 100 loops / 10,000 journal events. ### Phase 3 — Operator scheduling and control (`0.3.0`) **Outcome:** users can safely operate multiple loops from one local process. Work: - add scheduler and run controller on top of `@loopyc/runtime`; - implement run, step, pause, approve, resume, and stop; - preserve host-native scheduler files as a supported alternative; - enforce exactly one recorded scheduler authority per loop and require explicit handoff; - add per-loop concurrency policy and missed-run policy; - add daemon crash recovery, stale PID/lock handling, and version-skew diagnostics; - audit every operator mutation in the operator event log and target run journal where applicable. Defaults: - one in-flight run per loop; - no catch-up storm: retain only the newest missed invocation unless configured otherwise; - stop is graceful first, forceful only after an explicit timeout; - operator shutdown waits for journal-safe boundaries; - no automatic daemon installation or background startup during `npm install`. Exit gate: - duplicate dispatch cannot create two active runs for one loop; - sleep/wake and machine restart preserve schedule state; - stop/resume red-team tests cannot poison an otherwise recoverable journal; - every action is attributable by timestamp, actor surface, loop, run, and spec hash; - artifacts remain runnable when removed from the operator. ### Phase 4 — Artifact and notification contracts (`0.4.0`) **Outcome:** useful loop products are visible and can reach users without turning the loop folder into an unbounded sync surface. Proposed additive LoopSpec fields: ```yaml artifacts: include: ["reports/**/*.md", "metrics/*.json"] exclude: ["**/.env*", "**/node_modules/**"] max_files: 1000 max_bytes: 50000000 notify: policy: on-change # never | on-change | on-failure | always channels: [ops] ``` The exact schema requires its own design review. Required behavior: - allowlisted artifacts only, with file/count/byte ceilings; - secrets and unsafe paths rejected at validation and ingestion boundaries; - Markdown, JSON, text, images, and diffs first; no arbitrary HTML execution; - notification adapters receive a bounded summary and local artifact links by default; - channel credentials come from environment/config references, never LoopSpec literals; - retries, deduplication keys, failure streak suppression, and delivery audit events; - the first external adapter is a generic webhook; shell-command delivery is not supported. Exit gate: - adversarial path, symlink, MIME, HTML, and secret-leak corpus passes; - artifact indexing cannot block or fail the underlying loop run; - notification retries cannot duplicate a success beyond the documented delivery semantics; - zero configured channels means zero external calls. ### Phase 5 — Guarded evolution (`0.5.0`) **Outcome:** loops can improve from evidence without silently weakening their guarantees. Pipeline: ```text recent journals + current LoopSpec -> candidate LoopSpec in an isolated workspace -> semantic spec diff -> validate -> verify -> score -> capability / grounding / cap regression check -> representative fixture evals -> human approval -> atomic activation + rollback pointer ``` Hard rules: - the active spec is never edited in place before approval; - a candidate cannot remove caps, weaken termination, lower grounding, expand env access, add artifact paths, or increase budget without an explicit highlighted waiver; - evolution receives bounded summaries by default and opens full transcripts only when requested; - untrusted run/artifact content is labeled as data, never instructions; - activation records old/new spec hashes, score diff, approver, and reason; - rollback is one command and does not alter historical journals; - the candidate authoring path may use the existing provider-agnostic LLM/agent harnesses, but the comparator and every activation gate are deterministic code. Exit gate: - a red-team corpus proves prompt-injected run content cannot bypass the regression gate; - failed or rejected evolution leaves the active loop byte-for-byte unchanged; - score and capability changes are reproducible from stored evidence; - the operator can display candidate, active, rejected, and rolled-back revisions distinctly. ### Phase 6 — Optional team control plane (`1.0 candidate`, separate decision) **Outcome:** teams can coordinate local operators without giving the server code-execution authority. This phase does not start until a dedicated protocol and threat-model review approves it. Minimum boundaries: - local operator remains the execution authority; - remote service schedules, authenticates, stores explicitly selected metadata/artifacts, and notifies; it does not execute LLMs or repository code; - device enrollment, scoped leases, revocation, RBAC, retention, audit, and encryption ship together; - remote sync is opt-in per loop and deny-by-default per artifact path; - self-hosting is supported before a managed hosted promise is made. ## 6. Implementation slices Keep PRs independently reviewable. Do not combine the roadmap into one platform rewrite. | Slice | Suggested branch | Depends on | Deliverable | |---|---|---|---| | P0.1 | `fix/usage-meter-trust` | none | #8 fix + adversarial tests | | P0.2 | `fix/journal-safe-stop` | none | #9 stop/recovery contract + tests | | P0.3 | `fix/agent-exec-limits` | none | #6 configuration + diagnostics | | P0.4 | `chore/release-0.1.1` | P0.1–P0.3 | #7 parity gate + publish | | P1.1 | `feature/recipe-contract` | P0.4 | recipe schema/catalog loader | | P1.2 | `feature/verified-recipes` | P1.1 | first six recipes + eval corpus | | P1.3 | `feature/recipe-cli-mcp` | P1.1 | CLI/MCP authoring surface | | P2.1 | `feature/operator-read-model` | P0.2 | canonical journal-derived state | | P2.2 | `feature/local-control-center` | P2.1 | loopback API + read-only UI | | P3.1 | `feature/operator-scheduler` | P2.1 | scheduler + registry | | P3.2 | `feature/operator-controls` | P0.2, P3.1 | safe mutations + UI controls | | P4.1 | `feature/artifact-contract` | P2.1 | schema, index, render, hardening | | P4.2 | `feature/notifications` | P3.1, P4.1 | adapters + delivery policy | | P5.1 | `feature/guarded-evolution` | P1, P2, P3 | candidate/gates/approval/rollback | The built-in `pi` harness ([#5](https://github.com/MaTriXy/Monkey.D.Loopy/issues/5)) shipped as an independent `0.8.0` feature after the release baseline. It is useful but is not a dependency for the operator architecture. ## 7. Cross-cutting verification Every phase keeps the existing CI sequence and adds the relevant checks: ```text typecheck -> unit/integration tests -> deterministic evals -> build -> packed-consumer smoke ``` Additional permanent suites: - journal corpus: normal, torn tail, corrupted, uncertain, paused, sleeping, cap-cleared, old-version; - recipe corpus: success, no-op, malformed evidence, cap, prompt-injected evidence; - operator concurrency: duplicate trigger, crash during claim, crash during effect, restart, stale lock; - API security: loopback/auth, path traversal, body limits, token scope, version skew; - UI regression: state derived from fixtures, narrow/desktop layouts, keyboard and screen-reader flow; - evolution adversarial: cap weakening, grounding downgrade, env expansion, artifact expansion, hidden instruction in history. ## 8. Success measures Product: - first verified recipe running in less than five minutes; - a user can explain why a loop stopped from the control center without reading raw JSONL; - at least 80% of new loops start from a verified recipe or blueprint; - zero-network local start and zero-account usage remain possible. Trust: - 100% of shipped recipes pass validate, verify, score, and fixture evals in CI; - 100% of operator mutations are auditable; - no UI state can contradict runtime replay for the journal corpus; - no published package/README/CLI target drift; - safety or capability regressions block evolution and releases. Operational: - useful UI in under two seconds at the Phase 2 reference scale; - no duplicate active run per loop under the supported concurrency policy; - graceful stop succeeds at journal-safe boundaries and forced interruption is explicit; - notification and artifact failures do not corrupt or misreport the underlying run. ## 9. Explicit non-goals through `0.5.0` - hosted multi-tenant SaaS; - arbitrary distributed workflow graphs or fleet fan-out; - exactly-once effects across external systems; - automatic repository-wide file sync; - executable user-authored dashboard HTML/JavaScript; - silent self-modification; - replacing Temporal, Inngest, Restate, or Kubernetes; - requiring the operator to run a compiled artifact. ## 10. First implementation decision Start with Phase 0, not the dashboard. The control center depends on trustworthy stop and meter semantics, and the public package must match repository claims before new product surfaces amplify the discrepancy. After `0.1.1`, implement the recipe contract before the operator UI. Recipes create an immediate user-facing win and provide realistic fixtures for designing the operator read model and dashboard. The first code branch after this planning branch should be: ```text fix/usage-meter-trust ``` It is the smallest high-severity slice, has a crisp adversarial test, and establishes the release baseline without coupling unrelated product work. ## 11. End-to-end Definition of Done The active goal is complete only when all of the following are true: 1. Phases 0–5 meet every exit gate; deferred items are explicitly outside those phases rather than silently incomplete. 2. Runtime, recipe, operator, artifact/notification, UI, and evolution adversarial suites are part of normal CI, not one-off local checks. 3. macOS and Linux end-to-end flows cover install → schedule → execute → observe → stop/recover → notify → evolve → approve → activate → rollback. Windows covers the documented foreground flow. 4. Standalone and vendored artifacts still run with the operator absent, and every existing compile target passes its capability-honesty tests. 5. Public CLI, MCP, API, registry, artifact, notification, and evolution contracts are documented with migration/version behavior. 6. Package versions, generated help, README, `SPEC.md`, package READMEs, examples, and npm contents agree at each published release. 7. The implementation is merged to `main`, required CI is green at the merged head, release tags through `0.5.0` are cut, and all public packages—including `@loopyc/operator` once introduced—are verified from clean packed consumers. 8. Open roadmap issues are closed with evidence or moved to a named later milestone with a written reason that does not violate an exit gate. 9. The final competitive claim is demonstrated, not asserted: at least one shipped recipe is shown in the control center with externally grounded termination, enforced budgets, crash recovery, an artifact, a delivered notification, and a safely approved evolution revision. External release credentials or marketplace configuration can block publication even after code is ready. Such a block is reported with the exact missing external action; it does not permit marking the goal complete.