Runcastle

Test Coverage Booster

MIT1 downloads

by runcastle

v1.0.1

A single Claude Code agent that finds the least-tested modules in your repo, writes focused unit tests for them one module at a time, and verifies the suite stays green after every batch — stopping once it hits your coverage target.

Topology

Disclosures

Disclosures — declared side-effect surface

Everything below runs on your machine or inside the sandbox when you use this workflow. Mismatches between these declarations and the actual code block publishing.

Host hooks

Commands executed on YOUR host machine by Sandcastle lifecycle hooks.

None declared.

Sandbox hooks

Commands executed inside the sandbox container.

  • npm install

Network access

None. The agent reads and writes only the local repository inside the sandbox; the sandbox hook runs `npm install` against your declared package registry.

Shell expansion

No shell-expansion blocks in prompt files.

Files

Diff vs the stock Sandcastle 0.12.0 template Dockerfile — green lines were added by the author, red lines were removed from stock.

+# Sandbox image for the Test Coverage Booster workflow.
+# Node 22 + git + the Claude Code CLI, running as a non-root `agent` user.
+# Add your project's toolchain (python, go, ...) here if your suite needs it.
FROM node:22-bookworm
-# System dependencies.
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
jq \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Claude Code CLI (the agent runtime).
RUN npm install -g @anthropic-ai/claude-code
# Non-root agent user. `sandcastle docker build-image` aligns AGENT_UID/GID to
# the host user via --build-arg to avoid permission errors on bind mounts.
+# node:22-bookworm already ships a "node" user at UID/GID 1000, so we RENAME it
+# (the stock Sandcastle template pattern) — groupadd/useradd would collide with
+# the existing IDs on a default build.
ARG AGENT_UID=1000
ARG AGENT_GID=1000
-RUN groupadd --gid ${AGENT_GID} agent \
- && useradd --uid ${AGENT_UID} --gid ${AGENT_GID} --create-home --shell /bin/bash agent
+RUN groupmod -o -g ${AGENT_GID} node \
+ && usermod -o -u ${AGENT_UID} -g ${AGENT_GID} -d /home/agent -m -l agent node
-USER agent
-WORKDIR /workspace
+USER ${AGENT_UID}:${AGENT_GID}
+WORKDIR /home/agent
+
+# Sandcastle bind-mounts the worktree and sets the working directory at
+# container start; the container just needs to stay alive until then.
+ENTRYPOINT ["sleep", "infinity"]
Show full Dockerfile (highlighted)
# Sandbox image for the Test Coverage Booster workflow.
# Node 22 + git + the Claude Code CLI, running as a non-root `agent` user.
# Add your project's toolchain (python, go, ...) here if your suite needs it.
FROM node:22-bookworm

RUN apt-get update && apt-get install -y --no-install-recommends \
      git \
      curl \
      jq \
      ca-certificates \
 && rm -rf /var/lib/apt/lists/*

# Claude Code CLI (the agent runtime).
RUN npm install -g @anthropic-ai/claude-code

# Non-root agent user. `sandcastle docker build-image` aligns AGENT_UID/GID to
# the host user via --build-arg to avoid permission errors on bind mounts.
# node:22-bookworm already ships a "node" user at UID/GID 1000, so we RENAME it
# (the stock Sandcastle template pattern) — groupadd/useradd would collide with
# the existing IDs on a default build.
ARG AGENT_UID=1000
ARG AGENT_GID=1000
RUN groupmod -o -g ${AGENT_GID} node \
 && usermod -o -u ${AGENT_UID} -g ${AGENT_GID} -d /home/agent -m -l agent node

USER ${AGENT_UID}:${AGENT_GID}
WORKDIR /home/agent

# Sandcastle bind-mounts the worktree and sets the working directory at
# container start; the container just needs to stay alive until then.
ENTRYPOINT ["sleep", "infinity"]

README

Test Coverage Booster

Point a single Claude Code agent at a repository with thin test coverage and let it grind the number up — safely, one module at a time, never touching the code under test.

What it does

Low coverage is boring, high-value work that rarely gets prioritised. This workflow automates the grind: on each pass the agent runs your coverage report, finds the single least-covered module that carries real logic, writes focused unit tests for its happy path, key branches, and an edge case, then commits. It repeats until it reaches an 85% line-coverage target (or runs out of meaningful untested code), at which point it emits <promise>TARGET_MET</promise> and stops.

How it works

main.ts creates one warm Docker sandbox with createSandbox() and installs dependencies exactly once via an onSandboxReady hook. It then loops for up to six rounds. Every round is an agent pass followed by a hard npm test gate run through sandbox.exec() — if a round ever leaves the suite red, the run aborts loudly instead of stacking broken tests. Because the container stays warm between rounds, npm install and build artifacts are paid for once, not per round.

The topology is a tight loop: install → write tests → verify → back to write.

Requirements

Set CLAUDE_CODE_OAUTH_TOKEN in .sandcastle/.env (run claude setup-token on your host). Your repo should expose a working npm test that reports coverage; adjust the prompt if your stack uses pytest --cov, go test -cover, etc. Build the image once with npx @ai-hero/sandcastle docker build-image, then run it with npx tsx .sandcastle/main.ts.