Loop Agent
You sleep. I’ll loop.
External-write boundary: Normal help and environment checks are read-only. Formal runs write only within user-authorized targets; a release writes to the public GitHub repository, npm registry, and plugin marketplaces only after an explicitly approved frozen plan.
Safe first command: Ask to use
loop-agent:help; it performs no writes or network requests.
Loop Agent is a Codex and Claude Code compatible plugin that helps capable—but imperfect—models complete long-running work through layered planning, isolated execution, evidence-backed review, repair, and acceptance.
The plugin separates the loop roles into distinct processes:
- L0: Private development support. Not a public plugin capability.
- L1 Supervisor: Entry and meta-supervisor. Selects the delivery Profile, commissions one fresh L2 process per Delivery Cycle, owns Client Acceptance, and samples L3 evidence only for risk or anomaly.
- L1 Bootstrap Generator: Turns a short user request into an Engagement Brief and command-plane launch package.
- L2 Planner: Plans and supervises one Delivery Cycle. Two planner routes: goal workflow planner for multi-step objectives, narrow planner for bounded single-target work. Owns Vendor Acceptance.
- L3 Worker: Executes one assigned leaf task. The canonical Skill is
loop-l3-delivery-task-runner. The legacy nameloop-l3-workflow-workeris a compatibility alias that resolves to the same Skill.
Delivery Profiles
Profiles reuse the common L1/L2/L3 runtime protocol and add no additional layer:
post_design_automated_delivery: Automates technical design/development/test when Requirements and Product Design baselines are approved.full_software_delivery: Models each approved stage as a separate Delivery Cycle, pausing at declared HITL gates.editorial_delivery: Same task/phase machinery with editor, researcher, writer, fact-checker, and reviewer Expert Roles.
Process Model
Each layer runs as a separate process:
- L1 launches L2 via
launch-layer-process.mjswith a bounded timeout. - L2 launches L3 via the same launcher for each leaf task.
- L3 writes a
delivery-task-result.jsonterminal contract. - L2 writes a Vendor Acceptance Decision (
acceptance-decision.json). - L1 reads the Delivery Package and writes a Client Acceptance Decision.
- Rework at the Vendor level uses new task IDs and fresh L3 processes. Rework at the Client level creates a new Delivery Cycle with a fresh L2 process.
External Run Root
The run directory is external to the plugin. The Engagement Brief records the run_root and
target_repository paths. The plugin never embeds project-specific paths in generic skills.
Status
The runtime scripts and contract schemas are stable. The integration test exercises the full L1→L2→L3 delivery chain with rework and acceptance separation using fake child processes and real deterministic runtime scripts.
Stable Gate
npm test is the stable long-task gate. It runs all shared deterministic, contract, and integration
tests. The stable boundary covers:
- L1 supervisor and bootstrap generator
- L2 goal-workflow-planner and narrow-planner
- L3 delivery-task-runner and workflow-worker
- Workflow execution packages and process evidence
- Acceptance chains (vendor and client)
- Layer launcher and watchdog
- Adapter build, install, and package distribution
Experimental Gate
npm run test:self-iteration is the experimental self-learning gate. It is not part of the
stable gate and carries known failures.
Current self-learning status: 1065 tests total, 1047 pass, 18 fail, 0 skip.
The experimental boundary covers:
- Self-iteration state machine
- Oracle vault (deterministic control plane)
- Case isolation domains
- Self-learning round gates
- Skill self-learning integration
Layout
.codex-plugin/plugin.json
skills/
scripts/
references/
profiles/
Project-specific rules belong in profiles. The generic skills should not hard-code a target repository, product, or private workflow.
Method Lock Resolution
scripts/resolve-method-lock.mjs is the stable executable for L2 method-lock
operations. It reads a validated method-registry config and explicit query
filters, invokes queryMethods, resolveMethod, selectAndLockMethod (no
duplication), and writes exactly one validated method-lock JSON result.
# Lock the first matching method (default selection policy)
node scripts/resolve-method-lock.mjs \
--config method-registry.json \
--output method-lock.json
# Lock an explicit method reference
node scripts/resolve-method-lock.mjs \
--config method-registry.json \
--output method-lock.json \
--ref plugin:my-skill
# Strict mode — fails closed on any registry error
node scripts/resolve-method-lock.mjs \
--config method-registry.json \
--output method-lock.json \
--mode strict
# With query filters
node scripts/resolve-method-lock.mjs \
--config method-registry.json \
--output method-lock.json \
--domain delivery --kind workflow
Config fields: command, command_args, index_path, plugin_roots,
project_roots, timeout_ms, max_output_bytes, mode.
Modes: compatible (default) falls back to a builtin lock on soft errors
(COMMAND_MISSING, NO_QUERY_MATCH, UNCONFIGURED). strict fails closed.
Error codes: COMMAND_MISSING, NO_QUERY_MATCH, INPUT_READ_FAILED,
STALE_EFFECTIVE_INDEX, INVALID_SELECTION, REGISTRY_LOCK_FAILED.
Lock fields: ref, kind, provider, index_content_hashes,
verification, diagnostics, selection_source.
The script is generated into both adapters (adapters/claude/scripts/,
adapters/codex/scripts/) by npm run build.
Validation
node scripts/check-skills.mjs
node scripts/check-loop-token-budgets.mjs
npm test # stable long-task gate (all shared tests)
npm run test:self-iteration # experimental self-learning gate (18 known failures)
npm run build:check
Smoke Tests
Smoke tests launch real Claude processes and exercise the full L1/L2/L3 delivery chain.
They are opt-in and never run during default npm test.
# Skip (default) — exits 0 with a clear skip reason
npm run test:smoke
# Direct layered smoke — L0-L3 real Claude delivery
LOOP_AGENT_REAL_SMOKE=1 npm run test:smoke
# Direct filter only
LOOP_AGENT_REAL_SMOKE=1 LOOP_AGENT_REAL_SMOKE_FILTER=direct npm run test:smoke
# Self-iteration — deterministic harness + real self-iteration smoke
LOOP_AGENT_REAL_SMOKE=1 LOOP_AGENT_REAL_SMOKE_FILTER=self-iteration npm run test:smoke
# L1-L2-L3 chain — full three-layer acceptance with real Claude (~30-60 min)
LOOP_AGENT_REAL_SMOKE=1 LOOP_AGENT_CHAIN_SMOKE=1 LOOP_AGENT_REAL_SMOKE_FILTER=chain npm run test:smoke
Filters: direct, l0-l3, self-iteration, chain. Unknown filters exit nonzero with a clear error.
Runtime cost: The direct smoke test launches a real Claude process with a 15-minute timeout. The self-iteration smoke launches a multi-phase workflow with two trial cycles. Budget 20+ minutes for a full smoke run. The chain test launches three real Claude processes (L1→L2→L3) with the full delivery chain; budget 30-60 minutes.
Evidence location: Run artifacts are preserved under runs/real-smoke/direct-<timestamp>/ or
runs/real-smoke/self-iteration-<timestamp>/. Each run contains target-review snapshots, workflow
evidence, delivery-task-result, and watchdog evidence.
Troubleshooting:
- Claude CLI not found: Install Claude CLI and ensure
claude --versionreports >= 2.1.172. - Version below floor: Update Claude CLI. The minimum supported version is 2.1.172.
- Smoke test hangs: Check the watchdog evidence JSON under the run directory. The stale timer defaults to 600 seconds and the max timer to 900 seconds.
- Unknown filter error: Use one of the known filters:
direct,l0-l3,self-iteration,chain. - Chain test timeout: The chain test has a 95-minute timeout. If it hangs, check L1/L2/L3 process evidence and execution logs under the run directory. Each layer has a 600-second stream idle timer.
Install from npm
npm install loop-agent@0.1.1
Start with the read-only entry:
Please use loop-agent:help
Install Locally
npm run build
npm run install:global
codex plugin add loop-agent@personal
The installer writes the Codex adapter to ~/plugins/loop-agent, registers it in the personal
Codex marketplace, writes the Claude Code adapter to ~/.claude/plugins/loop-agent, and syncs the
skill folders into ~/.claude/skills.
Version Floor
Requires Node.js >= 22.0.0.