A minimal coding-agent loop: it keeps working on your task so you can rest.
RestLoop is a coding agent reduced to its loop. It sends a conversation and one tool, shell, to any OpenAI-compatible /chat/completions endpoint, runs every command the model asks for, and stops when the model answers without a tool call. The whole program is one Rust file with two dependencies, packaged as a binary of about 1.5 MB.
Install
- Homebrew
brew install lhwzds/tap/restloop - npm
npm install -g restloop - Cargo
cargo install --git https://github.com/lhwzds/restloop
What it does
- One tool, shell, and a fixed system prompt. The model reads, writes and edits files through the shell.
- Configured entirely by environment variables. No config file, no database.
- Session files to resume or fork a run, a time budget the model is told about, and recovery when the context window fills.
What it leaves out on purpose
- No sandbox and no confirmation prompt: commands run with your permissions, so run it in a container or a throwaway checkout.
- No model-facing knobs. In A/B runs a model-adjustable timeout roughly doubled the number of steps, so the timeout stays yours.
restloop "make python3 test_wordcount.py pass" I'll start by exploring the working directory. $ ls -la [0.1s] exit: 0 total 16 drwxr-xr-x@ 6 you wheel 192 Oct 29 22:28 . drwxr-xr-x@ 4 you wheel 128 Oct 29 22:28 .. drwxr-xr-x@ 12 you wheel 384 Oct 29 22:28 .git drwxr-xr-x@ 3 you wheel 96 Oct 29 22:28 __pycache__ -rw-r--r--@ 1 you wheel 378 Oct 29 22:28 test_wordcount.py -rw-r--r--@ 1 you wheel 165 Oct 29 22:28 wordcount.py $ cat test_wordcount.py 2>/dev/null; echo "---"; cat wordcount.py 2>/dev/null [0.1s] exit: 0 from wordcount import top_words def test_most_common_first(): assert top_words("the cat and the hat and the bat") == ["the", "and", "bat"] def test_ignores_case_and_punctuation(): assert top_words("Go, go! GO? stop.", n=2) == ["go", "stop"] if __name__ == "__main__": $ git log --oneline -20; echo "---"; git log -p --all -- wordcount.py | head -60 [0.1s] exit: 0 fc33a5f tests afbce82 init --- commit afbce82bc1153aef88d39940fc03cddf1b72e1f7 Author: demo <demo@example.com> Date: Thu Oct 29 22:28:49 2026 -0700 init Now I'll fix the implementation: case/punctuation normalization, descending count, and deterministic alphabetical tie-breaking. $ cat > wordcount.py <<'EOF' import re def top_words(text, n=3): counts = {} for word in re.findall(r"[a-z0-9]+(?:'[a-z]+)?", text.lower()): counts[word] = counts.get(word, 0) + 1 return sorted(counts, key=lambda w: (-counts[w], w))[:n] EOF python3 test_wordcount.py && python3 -m pytest test_wordcount.py -q 2>/dev/null; echo "exit=$?" [0.1s] exit: 0 all tests passed exit=1 $ python3 -m pytest test_wordcount.py -q; echo "pytest exit=$?" [0.1s] exit: 0 python3: No module named pytest pytest exit=1 $ python3 test_wordcount.py; echo "exit=$?"; python3 -c " from wordcount import top_words print(top_words('')) print(top_words('a b c d', n=10)) print(top_words('The the THE cat', n=1)) " [0.1s] exit: 0 all tests passed exit=0 [] ['a', 'b', 'c', 'd'] ['the'] `python3 test_wordcount.py` now passes. The original `wordcount.py` had three bugs: 1. **No normalization** — it counted raw `split()` tokens, so `Go,` / `go!` / `GO?` were separate keys and punctuation leaked into output. 2. **Ascending sort** — `sorted(counts, key=counts.get)` returned the *least* common words first. 3. **Unstable tie-breaking** — Python's sort left ties in first-appearance order, so `"the cat and the hat and the bat"` gave `cat` instead of the expected `bat`. Fixed version: ```python import re def top_words(text, n=3): counts = {} for word in re.findall(r"[a-z0-9]+(?:'[a-z]+)?", text.lower()): counts[word] = counts.get(word, 0) + 1 return sorted(counts, key=lambda w: (-counts[w], w))[:n] ``` The regex lowercases and strips punctuation while keeping internal apostrophes (`don't` stays one word), the sort key is `(-count, word)` for descending frequency with alphabetical tie-breaking, and `[:n]` slices afterwards. Also verified edge cases: empty string → `[]`, `n` larger than the vocabulary → whole list, and repeated mixed-case words collapse correctly. Note: `python3 -m pytest` fails with `No module named pytest` — pytest isn't installed in this environment. That's unrelated to the code; the test file's own `__main__` runner works.