@dharun7/agentloops
v0.3.0
Published
Adaptive multi-agent orchestration for AI agents: route work to typed specialist agents, learn from outcomes, mine patterns, and run propose-dispatch-verify-retry agent loops. Zero-dependency TypeScript library + CLI with a Claude Code hook generator.
Maintainers
Readme
agentloop — adaptive multi-agent orchestration & AI agent loops
Route work to typed AI agents, learn from every outcome, and run self-correcting agent loops.
agentloop is a multi-agent orchestration framework for building AI agents
that improve as they run. It routes each request to the right typed specialist
agent, logs what happened, and gets better over time — it adapts its routing
weights from outcomes, mines the log for recurring patterns, and drives every task
through a self-correcting agent loop: propose → dispatch → verify → retry.
It generalizes a battle-tested pattern — a dispatcher, a roster of
restricted-tool specialist subagents, and a UserPromptSubmit routing hook —
into a small, zero-dependency TypeScript library + CLI. It can even emit a
ready-to-use Claude Code dispatch-router.cjs hook straight from your registry.
Status: early (v0.1). Zero runtime dependencies. TypeScript / ESM / Node ≥ 18.
Keywords: AI agents · agent loop · agentic AI · multi-agent orchestration · LLM agent routing · autonomous agents · agent framework · loop engineering · Claude Code.
Why
A static instruction file is read once and then competes with everything else in context. Under pressure the model does the work itself in the main thread — with full, unrestricted tool permissions — instead of delegating to a specialist that is structurally limited to its job.
agentloop fixes that with three moving parts:
- Routing re-injected every turn, so delegation is never "forgotten".
- Typed specialists whose tool allowlist is the real safety boundary (a
review agent that literally cannot
Edit; an ops agent that cannotWriteto product code). - A learning loop so the routing policy improves as the project grows, instead of rotting.
The four pillars
| Pillar | What it does | Where |
|---|---|---|
| Type-based routing | Score a prompt against each agent's weighted signals; pick the best fit (or answer trivial reads inline). | router.ts, classifier.ts |
| Adaptive learning | Nudge signal weights from logged outcomes (perceptron-style, auditable). | learning/adapt.ts |
| Pattern mining | Find tokens strongly associated with an agent and propose them as new signals. | learning/patterns.ts |
| Loop engineering | A re-injected routing/verify directive + a generic propose→dispatch→verify→retry runner with a budget. | loop/directive.ts, loop/engine.ts |
Install
# Install the CLI globally, then use the `agentloops` command:
npm install -g @dharun7/agentloops
# …or add it as a library to a project:
npm install @dharun7/agentloops
# …or run a one-off without installing:
npx @dharun7/agentloops init
# …or build from source:
git clone https://github.com/Dharundp6/agentloop && cd agentloop
npm install && npm run buildPublished on npm as
@dharun7/agentloops(the unscopedagentloop/agentloopsnames were unavailable). The CLI command isagentloops(withagentloopas an alias). Repo:Dharundp6/agentloop.
Quick start (CLI)
# 1. Scaffold a starter registry (builder / reviewer / researcher / ops)
agentloops init
# 2. See how prompts route
agentloops route "implement JWT refresh in the auth service" # -> builder
agentloops route "audit the payments module for security bugs" # -> reviewer
agentloops route "what does src/router.ts do?" # -> skip (inline)
# 3. Print the directive you'd re-inject each turn
agentloops directive
# 4. Record how each routed task went — THIS is what feeds the learning.
# Nothing writes outcomes automatically; without them learn/patterns/evolve
# have nothing to learn from.
agentloops outcome --last --success # the routed agent handled it
agentloops outcome --last --corrected reviewer # it should have gone to reviewer
# 5. As outcomes accumulate, learn and mine patterns
agentloops evolve # capture new signals from usage, then reweight
agentloops learn # (or) adapt weights only
agentloops patterns --apply # (or) fold discovered signals in, no reweight
# 6. Emit a Claude Code hook from your registry
agentloops gen-hook --out .claude/hooksHow learning works
route()produces aRouteDecision; append it to.agentloop/decisions.jsonl.- Record how it went as an
Outcome—agentloop outcome --last --success(or--corrected <agent>) appends it to.agentloop/outcomes.jsonl. This step is the learning signal. Nothing writes outcomes automatically; if you skip it,learn/patterns/evolvehave an empty log and the router stays static. agentloop learnrunsadapt(): reinforce signals behind confirmed-correct routes, penalize the ones behind wrong routes, reward the correction. The registry version bumps.agentloop patternsrunsminePatterns(): tokens with high lift toward an agent — not yet in its signals — become proposals you can--apply.
Everything is transparent JSON and pure functions — no opaque model, no training job, fully auditable.
Closing the loop automatically
In a Claude Code workspace, the natural place to record outcomes is a Stop (or
SubagentStop) hook that appends an Outcome for the session's routed tasks —
via the appendOutcome() API or by shelling out to agentloop outcome. Until
you wire that up, make the one-liner a habit at the end of each dispatched task:
agentloop outcome --last --success # or --corrected <agent>Tuning the skip gate
The classifier is dispatch-biased: anything that isn't clearly a short read or
calculation falls through to route. That's right for detached / unattended
sessions, but in interactive use over-dispatch on simple asks is the more likely
annoyance. Set triviality.fallback: "skip" in the registry to flip the
unmatched default to inline (strong build/action verbs still route); the
generated hook honors the same knob.
Cold starts: reach for evolve()
adapt() can only reweight signals that already fire on a prompt. On a cold
or sparse registry, a misrouted prompt often matches none of the correct
agent's signals — so there's nothing to reinforce and adaptation flatlines no
matter how many epochs you run. (Independently reproduced: on a sparse
4-domain benchmark, adapt() alone moved p50 routing accuracy 0 points; pattern
mining took it from ~37% to ~94%.)
The fix is to capture coverage first, then reweight — which is exactly what
evolve() does in one call:
import { evolve } from "@dharun7/agentloops";
// Call it as usage accumulates (every N logged outcomes, or on a schedule).
const { registry, captured, changes } = evolve(registry, labeledDecisions, {
mine: { minSupport: 2, minLift: 1.5 }, // discover new signals from usage…
adaptEpochs: 10, // …then sharpen weights on top of them
});evolve() runs minePatterns() → applyProposals() → adapt() as a single
online step, so routing improves from real usage without hand-editing signals.
Pass mine: false to get plain multi-epoch adaptation, or adapt: false to
capture patterns without reweighting. Same pure-function contract — a new
registry, no clock, no I/O.
Relationship to Claude Code
agentloop gen-hook emits a self-contained dispatch-router.cjs
UserPromptSubmit hook. Register it per-user in .claude/settings.local.json
(gitignored) so it never lands on collaborators, restart Claude Code, and every
non-trivial prompt gets the routing directive re-injected. See
docs/architecture.md for the full picture and the
project-vs-global / shared-repo guidance.
Two operational notes:
- Stacking with existing hooks. The generated hook composes with other
UserPromptSubmithooks (context injectors, watchers, …) — each hook's stdout is appended to the prompt context independently. Execution order between hooks is not guaranteed, so don't write hooks that depend on the directive already being present; the router hook itself reads only the raw prompt. - Roster names must be real agents. Each registry
nameis used as thesubagent_typeat dispatch time, so it must match a definition in.claude/agents/<name>.md.agentloop validatecross-checks the roster against that directory (override with--agents-dir) and warns on any agent that has no definition file.
FAQ
What is an AI agent loop?
An agent loop is a control cycle where an agent proposes an action, executes it,
verifies the result, and retries with feedback until it succeeds or a budget runs
out — instead of a single one-shot response. agentloop's runLoop() implements
exactly this propose → dispatch → verify → retry cycle with a bounded number of
attempts.
What is multi-agent orchestration?
Coordinating several specialized agents — each with a narrow remit and restricted
tools — so the right one handles each request. agentloop does this by scoring a
request against every agent type and dispatching to the best fit.
How is this different from a big prompt or a single agent?
A single general agent runs everything with full permissions and forgets your
routing rules under pressure. agentloop re-injects the routing policy every turn
and enforces what each agent can do via a per-agent tool allowlist — a reviewer
that literally cannot edit code, an ops agent that cannot write to product source.
Do I need Claude Code to use it?
No. The core library and CLI are framework-agnostic — wire route() and
runLoop() to any LLM or agent runtime. The Claude Code hook generator is an
optional convenience.
How does it "learn"?
It logs every routing decision and its outcome, then nudges signal weights toward
what actually worked (agentloop learn) and mines the log for new routing signals
(agentloop patterns). Fully transparent JSON — no opaque training job.
Contributing
See CONTRIBUTING.md. Issues, ideas, and PRs are welcome — if
agentloop is useful to you, a ⭐ helps others find it. Maintained by
@Dharundp6.
License
MIT © 2026 Dharun Prasanth
