Skip to content

ryanda9910/selfloop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

selfloop

A flexible, zero-dependency self-improving loop harness. Capture trajectories → reflect → adapt → persist. Pluggable memory, an independent grader, and fail-safe guards. Runs in Node and Cloudflare Workers, and drops into Claude Code, Cursor, Windsurf and any AI coding platform.

zero-dep node workers license

   ┌─────────────────────────────────────────────────────────────────┐
   │   capture ──▶ reflect ──▶ adapt ──▶ persist ──▶ (memory) ──┐     │
   │      ▲          the continual-learning loop                │     │
   │      └──────────────── next run starts smarter ◀───────────┘     │
   │                                                                   │
   │   same model.  a SYSTEM that gets sharper run over run.           │
   └─────────────────────────────────────────────────────────────────┘

Most agents are prompters: you send a prompt, watch, send the next. selfloop is the other thing — a system that prompts itself, checks its own work against a goal with an independent grader, remembers between runs, and learns which of its own moves lose so it stops making them. Extracted from a live trading loop that was silently losing to an overfit backtest; now it self-corrects.


Install

npm install selfloop      # or: git clone https://github.com/ryanda9910/selfloop

Zero runtime dependencies. Node ≥ 22 (uses native type-stripping) or any Cloudflare Worker.

30-second demo

import { Learner, MemoryStore } from "selfloop";

const learner = new Learner(new MemoryStore(), "trades", { minSamples: 6, explore: 0.14 });

// each action carries a coarse "setup" key. fold its outcome AFTER it commits.
learner.resetExploration();
const learn = await learner.load();
if (!learner.gate(learn, "2|SHORT|fear").suppress) {
  const score = doTheThing();            // e.g. realized PnL, test pass = +1 / fail = -1
  await learner.fold([{ key: "2|SHORT|fear", score }]);
}

// after a while: which of my own setups lose? suppress them.
console.log(await learner.reflect());     // [{ key, n, wins, avg }] worst-first
console.log(await learner.distillSkill("my-setups"));  // a .md skill you can commit
node --experimental-strip-types examples/trading.ts     # the learner in action
node --experimental-strip-types examples/ci-triage.ts   # maker → independent grader → goal

Before / after

Before — the loop trusts a backtest / its own optimism, and repeats a losing move forever:

if (signal.ok) placeTrade(signal);   // no memory of whether THIS kind of trade ever works

After — the loop learns from its own outcomes and stops the losers, keeping a slice of exploration so they can recover:

learner.resetExploration();
if (!learner.gate(learn, key(signal)).suppress) {   // key = "2|SHORT|fear"
  placeTrade(signal);
  pending.push({ id: signal.id, key: key(signal) });
}
// on close: await learner.fold(pending.map(p => ({ key: p.key, score: p.pnl })));

Same model. The system got smarter.


The four pieces (use one or all)

Piece What it does File
Learner capture setup→outcome, reflect, suppress proven losers, distill a skill src/learn.ts
runLoop maker → independent grader → iterate until the goal holds (hard cap) src/loop.ts
graders predicate, vote (adversarial majority), shell (run a test/lint) src/grader.ts
Memory + stores facts + lessons + last session; FileStore / KvStore / MemoryStore src/memory.ts

Independent grader (the maker never grades itself)

import { runLoop, vote, predicate, shell } from "selfloop";

const result = await runLoop({
  goal: "tests pass and the config is stable",
  maker: (goal, i) => produceCandidate(i),
  grader: vote([
    shell("npm test"),                                  // a real check
    predicate("has retries", (c) => c.retries >= 3),    // a different lens
  ], 2),                                                // BOTH must pass
  maxIterations: 5,                                     // fail-safe: never loops forever
});

Memory that survives runs

import { Memory, FileStore } from "selfloop";
const mem = new Memory(new FileStore("./state"));
await mem.addLesson("e2e checkout flakes on a webhook race — add a settle delay");
console.log(await mem.render());   // load this into your agent's context each run

Works with your AI platform

selfloop is a plain zero-dep library, so it runs anywhere. The repo also ships drop-in agent config:

  • Claude Code.claude/ has a verifier subagent (the independent grader), a selfloop skill, fail-safe permission denies, and CLAUDE.md.
  • Cursor / Windsurf / Copilot / Aider — read AGENTS.md (the cross-platform standard) for how to work the loop.
  • Cloudflare Workers — back memory + the learner with KV: new KvStore(env.MY_KV).
  • Any LLM API — wire a grader that calls your model, or spawn a subagent as the checker. The grader is just (artifact, goal) => { pass, reasons }.

Fail-safe by design

  • A suppressor never gates the system off: it keeps an exploration epsilon, and the first candidate of every batch always passes (resetExploration() before each batch).
  • Only suppresses a setup after minSamples and a losing average — never on a hunch.
  • runLoop has a hard maxIterations cap — it can't loop forever.
  • Fold outcomes after the action commits, so a retry never double-counts.
  • No runtime dependencies; nothing to audit but this repo.

Configure

new Learner(store, "key", {
  minSamples: 6,      // don't judge a setup until this many closed trajectories
  explore: 0.14,      // fraction of a losing setup's candidates still allowed through
  losingBelow: 0,     // "losing" = average score below this
});

Why "self-improving" honestly

The model doesn't change. What improves is the system around it: the memory it accumulates, the skills it distills, and the grader that keeps it honest. That's the whole idea — and it's ~300 lines of zero-dep TypeScript.

License

MIT © ryanda9910

About

Zero-dependency self-improving loop harness: capture trajectories, reflect, adapt, persist. Pluggable memory + independent grader + fail-safe guards. Node & Cloudflare Workers; drops into Claude Code / Cursor / Windsurf.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors