DEV Community

AI ThinkLab
AI ThinkLab

Posted on

Why We Built a Self-Improving AI Coding Runtime Using Only Python's Standard Library (Zero Dependencies)

Runesmith is an open-source runtime that wraps whatever AI model you have (a free Gemini or Groq key, a model on your own machine through Ollama, or even a chat window you copy and paste into) and uses it to plan, write, check and repair software. It can also rewrite parts of itself, and it keeps such a change only when the change wins on work it has never seen.

Here is the part that surprises people when they open the repository:

[project]
name = "runesmith"
requires-python = ">=3.11"
dependencies = []
Enter fullscreen mode Exit fullscreen mode

No requests. No pydantic. No LangChain, no FastAPI, no Node.js build step for the browser UI. The runtime is Python 3.11 and the standard library. The only extra package you ever install is pytest, and only if you want to run the test suite or repair existing Python projects.

This post explains why we made that choice, what it cost us, and what the standard library turned out to be good at.

The short version: a self-modifying system has to be auditable

Most agent frameworks treat dependencies as free. For a normal app that is mostly fine. For a system that is allowed to change its own code, it is not.

Runesmith's design splits the program in two. A small kernel is fixed: identity, the ledger, generations, the instrument router, budgets and confinement. Around it sit organs, such as organs/repair.py, which the self-improvement loop (we call it Kaizen) may rewrite. A new version of an organ is accepted only after it passes a static check, a confined smoke test, held-out replays and then a live trial against the current version.

Every one of those gates is easier to reason about when the trusted base is small and readable. If the kernel depended on thirty packages, "what does this system actually do?" would include thirty other projects' release cycles. With zero dependencies, the whole trusted surface is in one repository, and anyone can read it.

1. The rewrite gate is an allow-list of standard-library modules

When a model proposes a new version of an organ, the first check is a plain AST walk. This is the real code from runesmith/kaizen/improve.py:

ALLOWED_IMPORTS = frozenset({
    "__future__", "ast", "bisect", "collections", "copy", "dataclasses", "difflib", "enum", "fnmatch",
    "functools", "hashlib", "heapq", "io", "itertools", "json", "keyword", "math", "operator", "re",
    "statistics", "string", "textwrap", "time", "tokenize", "typing",
})

def static_check(source: str) -> list[str]:
    problems = []
    if len(source.encode("utf-8")) > 200_000:
        problems.append("module larger than 200 KB")
    try:
        tree = ast.parse(source)
    except SyntaxError as error:
        return [f"syntax error: {error}"]
    if not any(isinstance(node, ast.FunctionDef) and node.name == "run" for node in tree.body):
        problems.append("no top-level run(view, cockpit)")
    for node in ast.walk(tree):
        names = []
        if isinstance(node, ast.Import):
            names = [alias.name.split(".")[0] for alias in node.names]
        elif isinstance(node, ast.ImportFrom):
            names = [(node.module or "").split(".")[0]]
        for name in names:
            if name not in ALLOWED_IMPORTS:
                problems.append(f"import of {name!r} is not allowed")
    return problems
Enter fullscreen mode Exit fullscreen mode

Notice what is missing from that list: os, socket, subprocess, urllib. An organ cannot open a file, a socket or a process on its own. Anything it wants (a model call, a test run, a log line) goes through a narrow "cockpit" that the kernel controls and charges against a fixed budget.

This rule only makes sense in a zero-dependency codebase. If the runtime itself leaned on third-party packages, an allow-list for the parts it rewrites would be a fig leaf.

2. Confinement with python -I and a PEP 578 audit hook

Even after the static check, an organ runs in a separate process started with python -I -B organ_child.py, with a secret-free environment and an audit hook installed. A trimmed excerpt from runesmith/organ_child.py:

_DENY_PREFIX = ("socket.", "os.exec", "os.spawn", "os.posix_spawn", "ctypes.", "winreg.", "_ssl.",
                "sqlite3.", "resource.",
                "_winapi.",     # OpenProcess/TerminateProcess would let an organ kill other processes
                "gc.",          # gc.get_objects/get_referrers could reach and widen this guard's allow-list
                "signal.")
Enter fullscreen mode Exit fullscreen mode

Under the hook, the operating system adds limits that hold even against code that gets past it: a Job Object on Windows, setrlimit on POSIX.

We want to be precise here, because it matters: PEP 578 audit hooks are defense in depth, not a hardened sandbox. The README says so, and recommends a container or VM for organs you do not trust. But the important point for this post is that all of it, the isolated interpreter, the hook, the resource limits, ships with CPython. No sandboxing library was needed to get a useful first layer.

3. An append-only, hash-chained ledger in about a page of code

Self-improvement claims are only worth something if you can check what happened. Runesmith records every decision in a JSON Lines ledger where each record binds the hash of the one before it. The core of Ledger.append in runesmith/ledger.py:

body = {"seq": self._seq + 1, "utc": utc_now(), "kind": kind,
        "data": data or {}, "prev": self._head}
record = dict(body, hash=digest(body))
line = canonical(record) + "\n"
with open(self.path, "a", encoding="ascii", newline="\n") as stream:
    stream.write(line)
    stream.flush()
    os.fsync(stream.fileno())
Enter fullscreen mode Exit fullscreen mode

canonical is json.dumps(value, sort_keys=True, ensure_ascii=True, separators=(",", ":")) and digest is SHA-256 from hashlib. Cross-process safety comes from fcntl.flock on POSIX and msvcrt.locking on Windows. Any edit, deletion or reordering of history shows up when you run python -m runesmith ledger.

No database, no ORM, no event-sourcing framework. json, hashlib, os and a lock file.

4. Talking to any model with urllib

Every hosted model Runesmith supports (Gemini, Groq, NVIDIA, OpenRouter, Mistral, DeepSeek, OpenAI, Anthropic's OpenAI-compatible layer, Together, or any OpenAI-compatible server) goes through one function built on urllib.request:

def http_json(method, url, headers, body, timeout_s):
    data = None if body is None else json.dumps(body).encode("utf-8")
    request = Request(url, data=data, headers=dict(headers), method=method)
    try:
        with urlopen(request, timeout=timeout_s) as response:
            return response.status, json.loads(response.read().decode("utf-8") or "{}")
    except HTTPError as error:
        ...  # parse the error body; on 429/503 read Retry-After and the provider's own wording
Enter fullscreen mode Exit fullscreen mode

That one function is where free tiers become practical. Runesmith ships ready-made presets for five providers with a free tier: Google Gemini (through Google AI Studio), Groq, NVIDIA, OpenRouter and Mistral. The Quick start walks you through Gemini and NVIDIA, and Runesmith itself suggests Groq as the second free provider to add. A 429 is remembered in the home folder until the provider's reset, so a free key's small allowance is not burned on retries. An instrument on a free tier gets at most one retry per call. A request too large for Groq's free window (8,000 tokens a minute) is turned away before it is sent, and the role's next model is asked. Google publishes no fixed free-tier numbers, so Runesmith tells newcomers a free Gemini key allows "about 20 requests a day for each model", the figure Google's own refusal named in our testing, and it can use several free Gemini models on one key, in turn.

Because the transport is a plain function, the tests replace it with a fake that returns canned status codes. No HTTP mocking library required.

5. File-tree scanning with os.scandir

Before Runesmith can help with a project, it maps the folder. runesmith/envmap.py walks it with os.scandir, skips .git, node_modules, virtual environments and caches, never follows a symlink or junction, and stops at 20,000 files. On Windows the sizes and modification times come with the directory listing, so a large folder costs one pass. The resulting fingerprint (names, sizes, times through SHA-256) tells Runesmith whether a project changed since the last measurement.

The browser UI, Runesmith Studio, is served by the standard library too, on 127.0.0.1 only, with plain HTML, CSS and JavaScript files in runesmith/app/static. No bundler.

What it cost us

We would be misleading you if we said zero dependencies was free:

  • We wrote things that libraries already do. Retry and backoff logic, tolerant JSON extraction for small models that wrap JSON in prose, rate-limit parsing, a statistical drift detector (a Bernoulli CUSUM) that raises the share of work spent on self-improvement from a standing 15% to 25 to 40% when performance drifts down.
  • Cross-platform details are ours to handle. File locking, junctions on Windows, line endings. The repository enforces LF endings because the kernel and organ digests are computed over bytes.
  • The test suite carries the weight. Every capability claim in the README points to a test or a sealed experiment, and every change ships with a test that fails without it.

What it bought us

  • Install is "have Python 3.11". Download the ZIP, run sh runesmith.sh on Linux or sh Runesmith.command on macOS (or double-click Runesmith.cmd on Windows), and the Studio opens in your browser. No virtual environment, no resolver conflicts.
  • Everything a reviewer needs is in one repo. That matters when the system's main claim is about changing itself.
  • It runs on small and free models. Nothing in the runtime assumes a paid API. With no key at all, the "chat window" instrument writes each request to a file, you paste it into any chat model, and paste the answer back.

Does the self-improvement actually work?

Carefully stated: in a narrow, sealed sense, yes once, and not yet in a general one. In the SR7 experiment, a repair-step generation written inside Runesmith's own Kaizen loop (C7) repaired 57 of 162 attempts against its predecessor's 35 of 162 (exact one-sided p = 0.000845), on synthetic single-line bugs with a cheap repair model. In a second sealed test, LOC1, C7 repaired 42 of 168 sessions against 17 for the step Runesmith ships with, on fresh bugs planted in three large public repositories (p = 0.00278).

The same paper reports what did not work. A hand-written trace-aware rule repaired 65 of 168 in LOC1, more than C7. Earlier attempts such as SR5 were not shown (36 vs 50 of 180), and no study shows cumulative improvement across generations. The evidence dataset on Hugging Face has the per-session tables and scripts that recompute the exact tests, so you do not have to take our word for any of these numbers.

Try it

git clone https://github.com/Veristria/runesmith
cd runesmith
sh runesmith.sh            # macOS: sh Runesmith.command, Windows: double-click Runesmith.cmd
Enter fullscreen mode Exit fullscreen mode

Or, to watch the self-improvement machinery end to end, offline, with a scripted stand-in model (it shows the machinery, not that the change helps):

python -m pip install pytest
python -m runesmith --home .runesmith demo --kaizen
Enter fullscreen mode Exit fullscreen mode

We are opening "good first issue" tickets for people who want to contribute: benchmarks, stdlib-only tests and translations of the Quick start. Find the open ones here: https://github.com/Veristria/runesmith/issues?q=is%3Aopen+label%3A%22good+first+issue%22 If you have strong opinions about where a zero-dependency design breaks down, we would genuinely like to hear them.

Star the repo on GitHub: https://github.com/Veristria/runesmith
Read the paper: https://aithinklab.com
Explore on Hugging Face: https://huggingface.co/datasets/aithinklab/runesmith-evidence

Top comments (0)