This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
Somewhere in your repo there is a comment like this one:
# TODO: blows up with a traceback on a fresh install (empty ledger).
It has been there for months. Fixing it would take ten minutes. You will not fix it today, because
today there is always something more interesting. Same goes for the deprecation warning that
prints on every run, the README that drifted three releases ago, and the function with no tests
"because it's simple".
nightshift-sloth is built to do one of those chores every night while I sleep. It picks the next open
item from a CHORES.md checklist and hands it to Backboard R-CLI,
the open-source terminal coding agent, running headless on a cheap open-weight model. The agent
works on a throwaway branch with a strict time budget, then the harness runs the tests and
writes a morning report. It never merges and never pushes. In the morning I read one page, and
either keep the branch or delete it.
To find out whether that holds up, I gave four open-weight models the same six chores on a small
demo app, one run each. That is 24 nights' worth of work, which I ran back to back in one morning.
All 24 together cost 39 cents. MiniMax M3.1 Flash got
all six right. DeepSeek V4 Flash got five right for about a quarter of a cent each. And the most
useful thing I learned was not about models at all: green tests are not the same as done.
Who gets to be lazier: anyone who maintains a small project and has a list of chores that are
too boring to start and too small to delegate. The chore still gets a human review, but reviewing
a 6-line diff with green tests takes a minute. Doing it takes a context switch I never make.
Demo
One take, nothing mocked. Bedtime is one command. The sloth takes the first open chore, DeepSeek V4
Flash fixes it in 9 seconds for $0.0016, the tests go from 12 to 14, and the work sits on its own
branch while main stays where it was. Here is a
full morning report
from the bench.
Code
Bowen1314
/
nightshift-sloth
One chore a night: Backboard R-CLI + open-weight models on a throwaway branch, with a morning report. Never merges, never pushes.
nightshift-sloth
One chore a night. While you sleep, an open-weight model picks the next item off your
CHORES.md, does it on a throwaway branch with a strict time budget, runs your tests, and
leaves a morning report. It never merges, never pushes, never touches main. You read the
report over coffee and decide: keep it or bin it.
Built on Backboard R-CLI (MIT), the open-source terminal coding agent, running headless against open-weight models on Nebius Token Factory. No Backboard account needed.
Results: four open-weight models, six chores
Each model took each of the six chores in the demo repo once: 24 nights of work, run back to back on 24 October 2026. A chore counts as done only if the repo's tests pass and a hidden acceptance check, which the agent never sees, passes on the sloth branch.
| Model (on Nebius Token Factory) | Done | Tests green | Median |
|---|
Everything the sloth did for this post is in the repo: each run's morning report, its diff, the raw
R-CLI event stream, a readable transcript, and a spend ledger with every model call priced.
How I Built It
The agent: Backboard R-CLI, headless. R-CLI is an MIT-licensed terminal coding agent. Its
headless mode is what a night shift needs:
backboard --cwd <clone> --model nebius/deepseek-ai/DeepSeek-V4-Flash-0731 \
--print "<the chore>" --timer 600 --format json --permission-mode bypass \
--memory off --no-lsp --excluded-tools WebSearch,FetchUrl
--format json streams every event (tool calls, results, token usage) as JSON lines. --timer
tells the model how long it has and reminds it as the clock runs down.
The models: open weights on Nebius Token Factory. R-CLI can talk to any OpenAI-compatible
endpoint you define in ~/.backboard/config.json. The key stays in an environment variable:
{ "providers": [{
"id": "nebius", "protocol": "openai-chat",
"baseUrl": "https://api.tokenfactory.nebius.com/v1",
"auth": { "type": "env", "variable": "NEBIUS_API_KEY" },
"extraArgs": { "stream_options": { "include_usage": true } },
"models": [{ "id": "deepseek-ai/DeepSeek-V4-Flash-0731", "contextLimit": 131072 }]
}] }
The include_usage line matters. Without it a custom provider's stream carries no token counts,
and you can't put a price on a run.
I benchmarked four models from four labs: DeepSeek V4 Flash, MiniMax M3.1 Flash,
Qwen3-235B-A22B-Instruct-2507 and OpenAI's open-weight gpt-oss-120b. GLM-5.3-Flash also passed my
smoke test; I left it out of the full run to keep the bench small.
The harness: a short leash. R-CLI runs with --permission-mode bypass, because nobody is awake
to approve prompts. That is only acceptable because of what surrounds it. nightshift-sloth is about
1,500 lines of standard-library Python that:
- makes a private clone holding only the base commit's history, on a fresh
sloth/<chore>/<stamp>-<model>branch, with no remote. The agent can't see my other branches or move my refs. When the night is over, the harness fetches that one branch back; - gives R-CLI a throwaway
HOMEwhose config knows exactly one provider, and an environment scrubbed down toPATH, locale and that one key. My shell has other API keys in it; the agent never sees them; - writes R-CLI deny rules for
git push,git commit, branch switching,gh,curl, package installs and environment dumps. I read R-CLI's permission engine to check that deny rules outrank bypass mode, and the bench confirmed it: one agent triedgit branch --alland was refused; - prices every
usageevent as it streams in, appends it to a ledger, and kills the run when it reaches its dollar cap (25 cents). The ledger also refuses to start a run that could push the project past its total cap (mine was $3); - kills the whole process group at timer + 2 minutes, because R-CLI's
--timeris advisory: the model is told about it, but nothing gets cancelled; - stops a run after six tool errors in a row (more on why below);
- runs the tests before and after, makes the one local commit itself, and writes the morning report.
It is not a sandbox. The agent can still run shell commands as my user. I treat it like a junior
colleague with no push access, not like a VM.
Measuring honestly. "Tests pass" means the agent graded its own homework. So for the bench every
chore also has a hidden acceptance check. It lives outside the repo, runs after the agent has gone,
and was validated against the untouched repo (must reject) and a reference solution (must accept).
For example:
-
test-parse-amountasks for unit tests without changing the function. The check confirmsmoney.pyis byte-for-byte unchanged, then runs the new tests against four mutants ofparse_amount. The tests have to catch all four. -
readme-usage-driftimports the real argparse parser and checks that every subcommand and every option shows up in the README's Usage section, and that the other sections were left alone. -
utcnow-deprecationbuilds a ledger that mixes old naive timestamps with new timezone-aware ones, exactly as the chore describes, and runs every command on it.
The first wall, and the way round it. I started with the R-CLI binary from the official
download link (3.0.5 for macOS arm64, fetched on 24 October 2026). It refused my Nebius provider
with "No credentials found". That build's bring-your-own-key list is Anthropic, OpenAI, Google and
OpenRouter, and it has no --timer flag. Because R-CLI is open source, I could go and look: custom
providers and the timer had both landed on main two weeks earlier, in
51bee17
("Add per-turn timer and todo budget feedback"). I built that commit with Bun and everything
worked. One oddity if you try it: that main build calls itself 3.0.4, one below the release.
Why Does Open Innovation Matter?
Here is what open source made possible this week that a closed API or a closed agent would not have.
When the release was missing a feature, I built main. With a closed agent, "the shipped
build doesn't support my provider" ends the project. Here it cost a git checkout and
bun run build. Reading the source also told me things no doc did: that --timer doesn't cancel
anything, that deny rules beat bypass mode, and which event carries token usage. The harness's
safety and its cost meter are built on those three facts.
Swapping models is one line. The same agent, prompt and checks ran against four models from four
labs. Nothing in the harness is model-specific, and the provider is two lines of config. When a
better or cheaper open-weight model ships next month, I change one line and re-run the bench.
The price makes "every night" sensible. DeepSeek V4 Flash spent 1.3 cents on all six chores and
finished five of them. At a quarter of a cent per finished chore, a chore every night for a year costs
less than a dollar. MiniMax, the only model to get all six right, works out at about $4 a year. The
number that matters on the price page turned out to be the cached-input price: an agent re-sends the
same growing conversation on every call, so 70% to 98% of each model's input tokens were cache hits.
DeepSeek bills those at $0.01 per million tokens. Qwen gets no cache discount on this provider,
which is most of why it cost seven times as much as DeepSeek for the same six chores.
No account, no lock-in. I never created a Backboard account for this. The agent is MIT-licensed,
the models are open weights behind an OpenAI-compatible endpoint, and the only key is for that
endpoint. If my provider vanished tomorrow I would change base_url and keep going.
What I am not claiming: this is not offline or private. The code goes to a hosted inference
endpoint, as it would with a closed API. I also didn't run a closed model, so I can't tell you open
models are better at this. My claim is narrower: for a small chore, a model that costs a fraction of
a cent did the job, and when the tooling got in my way, open source let me fix it myself instead of
waiting.
My Agent Session
R-CLI keeps its own session log, and nightshift-sloth saves it for every run, so instead of DevRelay
I am linking the night-shift sessions directly. Each folder in
docs/runs has a readable
TRANSCRIPT.md next to the raw events.jsonl. Four are worth reading:
Green but wrong. DeepSeek V4 Flash on utcnow-deprecation:
four model calls, eight seconds, a two-line diff and a green suite. The chore said that old ledgers
hold naive timestamps and that list, report and export must keep working on a ledger mixing
old and new entries. DeepSeek reasoned about it instead of trying it, and its summary says
"downstream code (list, report, export) only reads e.when/sorts, so mixed ledgers keep
working." The hidden check tried it: all three commands crashed comparing naive and aware datetimes.
Qwen made the same two-line change.
Slow and right. MiniMax M3.1 Flash on the same chore:
twelve calls and almost two minutes. It normalised old timestamps to UTC on load, wrote tests for a
mixed ledger, and ran the suite a second time with -W error::DeprecationWarning, which nobody asked
it to do. It was the slowest model in the bench and the only one to finish all six chores.
The loop. gpt-oss-120b on fix-empty-report:
the fix was in place after 26 seconds, and it passes the hidden check. Then the model kept going:
92 model calls, and 79 of its 93 tool calls failed, with missing arguments, an empty tool name, and
harmony <|channel|> tokens leaking into tool names. It stopped when the provider returned an
error, at $0.14, ten times what DeepSeek spent on all six chores. That run is why the harness now stops
after six tool errors in a row. gpt-oss produced malformed tool calls in every run. I didn't work out
whether the model, the provider's translation layer or the agent's OpenAI adapter is at fault, so I
read its column as "this combination doesn't work yet", not as a verdict on gpt-oss.
The peek. An excluded run.
The first version of the harness used git worktree, which shares refs with your repo. Early in
the bench, MiniMax ran git log --oneline --all, found DeepSeek's attempt at the same chore
from a few minutes earlier, and read it with git show. A night-shift worker reading the day
shift's notes is fine; a bench contestant reading another's answer is not. So now every night works
in a private clone that holds only the base commit's history. I kept the original run as evidence,
re-ran it in a clean clone (MiniMax still got it right, in half the time), and counted only the
re-run.
The Lazy Payoff
Six chores on the demo app, and here is how the night shift did:
| Model | Done | Tests green | Median time | Cost, all 6 | Per done chore |
|---|---|---|---|---|---|
| MiniMax M3.1 Flash | 6/6 | 6/6 | 50s | $0.068 | $0.011 |
| DeepSeek V4 Flash | 5/6 | 6/6 | 13s | $0.013 | $0.0026 |
| Qwen3-235B-A22B-Instruct-2507 | 3/6 | 6/6 | 16s | $0.093 | $0.031 |
| gpt-oss-120b | 3/6 | 3/6 | 11s | $0.216 | $0.072 |
"Done" means the repo's tests pass and the hidden check passes. Every chore was done by at least
one model, so every chore now has a branch I would merge. Four branches had green tests and were
still wrong: you can see them in the gap between the "Done" and "Tests green" columns. The
chore-by-chore table
links every morning report.
The whole project, including smoke tests, the bench, one aborted run, the excluded run and the demo
recording, cost $0.45 according to the
ledger. That's 15% of
the $3 cap I set before starting.
Two honest caveats. This is one run per model per chore, so treat it as anecdotes with receipts, not
a benchmark. And the demo app and its chores were written for this project; the hidden checks were
validated before any model saw the chores, but this is not a year of nights on a real codebase.
What I took away is the reason the sloth never merges. If I had run only DeepSeek, five chores
would have been done for a little over a cent, and the sixth would have arrived marked READY FOR
REVIEW with green tests and a bug in it. The cheap model is good enough to do the work. It is not
good enough to skip reading the diff. That suits me: reading one short diff over coffee is the kind
of slow and steady I can keep up.
Prize Categories
Best Use of Backboard. nightshift-sloth is built on Backboard R-CLI as a component, not a chat
window: headless --print, the --format json event stream for live cost metering, --timer,
custom OpenAI-compatible providers and project deny rules. The bench compares four open-weight
models through the same R-CLI build. I did that through R-CLI's custom-provider config with my own
inference key, not a Backboard API key; I didn't create a Backboard account.
Things I ran into that might be useful to the R-CLI team:
- The binary from the download link (3.0.5) is behind
main: no custom providers, no--timer. Andmainreports itself as 3.0.4. - Custom providers report no token usage unless
stream_options.include_usageis set inextraArgs. Turning that on by default foropenai-chatproviders would make cost tracking work out of the box. -
--timeris advisory. A hard wall-clock limit or spend limit for--printruns would make unattended use safer; I had to build both outside the agent. - With gpt-oss-120b, malformed tool calls repeated until the provider gave up. An option to stop after N consecutive tool errors would have saved most of that run's cost.
AI use: I built nightshift-sloth with an AI coding assistant (Claude Code), which wrote most of the
harness, the demo app, the hidden checks and a first draft of this post, working to my brief. The
night-shift work in the bench was done by R-CLI with the open-weight models named above, and every
one of those sessions is in the repo.


Top comments (0)