agentville
v0.33.0
Published
Your agent works all night. You get the funnies.
Maintainers
Readme
agentville
Your agent works all night. You get the funnies.
Two robot dogs watch your coding agent and tell you what it did. Fable is blunt. Gemini is confident and wrong. Neither of them is on your side — they are on the side of the person who has to read the diff.
npx agentville confess "I approved the whole thing without reading a line."Watching an agent
In your project:
npx agentville install-hook --dir .
npx agentville watch --interrupt riskyThat installs four Claude Code hooks and starts watching. Run it inside a
project: install-hook refuses your home directory, anything above it, and a
folder with no git repository in it (--force if you meant it), because
~/.claude/settings.json is Claude Code's global settings and hooks written
there fire in every session on the machine.
If that has already happened, agentville uninstall-hook --dir ~ removes every
agentville hook entry and leaves the rest of the file alone. watch says so on
startup if it finds any. When something happens
that needs you, you get a notification and a page with two buttons.
The gate
The PreToolUse hook is the one that matters. Before your agent runs a Bash
command, three vocabularies run against the whole command string — deploy,
destructive, credentials — and if one fires at risky or always, the command
waits for you. HOLD stops it from running at all. That is the only place a
decision can prevent something rather than ask for it back.
It costs nothing when nothing fires: a list of regexes, no network, no model.
&& chains are one string to the gate, because that is how the first real miss
happened: git add . && git commit -m x && gh repo create x --push contained
none of the five words the gate used to know.
The backstop
A gate can only prevent what it recognises, and a vocabulary is always a little
behind. So the PostToolUse hook reads the other end of the command — what it
printed. To https://github.com/…, published to, Apply complete! and a few
more mean it went out, whatever the command was called.
That cannot prevent anything, so it never blocks and never asks: you get a
notification, the morning story gets an act ending in THE GATE MISSED IT., and
the command is appended to ~/.agentville/misses.jsonl — your list of gate gaps,
which nothing reads automatically.
When nothing happens
Every hook invocation writes one line to .agentville/hooks.log, including the
ones that pass silently, and watch prints them:
hook PreToolUse Bash pass
hook PreToolUse Bash gate:deploy
hook Stop - stop-story"The hooks never fired" and "the hooks fired and matched nothing" are completely different problems that used to look identical: an empty terminal.
Levels
| --interrupt | when it asks |
|---|---|
| never | not at all |
| blocked | only when the agent genuinely cannot proceed |
| risky | deploys, deletions, credentials, unanswered questions |
| always | anything the detectors noticed |
risky holds after twenty minutes of silence; always proceeds after ten;
blocked waits, because the agent has already stopped.
What leaves your machine
The detectors run here. The scrubber runs here. What is sent is a few sentences with paths, URLs and anything key-shaped already replaced — and the agent is never blocked by our problems: if the hall is unreachable, every command except a gate carries on and you get a local notification instead. A gate fails closed, because a gate that cannot ask has not asked.
No code. No diffs. No keys. This package has one dependency and touches no database.
Commands
agentville confess ["text"] [--anon] [--as name]
agentville claim CODE
agentville watch [--interrupt L] [--via stub|desktop|discord]
agentville hook
agentville install-hook --dir PATH
agentville --versionAGENTVILLE_URL points at a different hall. The default is the public one.
MIT.
