Skip to main content

A white ceramic robot dog sits at an open, lit door, a scroll in its mouth, its paws stopped at a glowing amber line on the threshold

housebroken

Agent-written pull requests that do not make a mess in someone else's house.

Stars Release PyPI Works with Claude Code shellcheck clean MIT license

A maintainer runs her project on evenings and weekends. She opens GitHub to pull requests from accounts she has never seen, each rewriting a function she wrote years ago, each carrying comments in code that had none, a six-hundred-word body and a footer naming the tool that wrote it. She closes them without reading them, and she is right to.

housebroken is the set of rules that get a pull request past her, written as scripts that refuse to file until every rule is met. The rules are principles, not opinions, and the scripts are the enforcement: a gate that only suggests is followed when remembered.

What passes the door

one finding, one pull request
the smallest diff in the project's own style, no comment added to their code
one test that fails on their main and passes with the patch
a body under 120 words, in their template, no footer, no trailer
their policy read first: no filing where AI is banned, disclosure where it is asked
prior art read and quoted before the branch existed
their CI target green on a fresh clone of their main
attacked by a second model before it left, evidence behind every finding
the CLA known before filing, the SECURITY.md route taken when it applies

The rules

An obsidian book with chrome corners titled The Housebroken Agent, a treatise on manners for machines calling at the homes of maintainers

A pull request passes through the door in order, and stops at the first rule it fails. Each rule is a script where a script can hold it. The maintainers' own verdicts that shaped them are kept separately, in docs/lessons.md.

1. Read the house rules before knocking. check-ai-policy.sh reads every contributing guide, code of conduct, template and agent instruction file on the repository's branch and in the organization's .github repository, matched by name without regard to case, and prints each sentence that names AI with its reading: BAN, DISCLOSE, MENTION or CLEAN. A project that bans AI-written contributions never gets one. A project that asks for disclosure gets one truthful sentence in the body. distinct-outside.sh counts outside contributors merged in the last 120 days; a project that has merged none is closed to outsiders whatever its README says.

2. Is it already on the table? prior-art.sh lists every issue and pull request, open, closed and merged, that touches the file or symbol, with the type taken from the API and the closing ruling quoted for every closed item. An open pull request that fixes the same thing, or a closed issue that ruled the behaviour intended, ends the work. A ruling is never argued with.

3. Is it a fix or an opinion? A change that rejects an input the project tolerated, changes a default, or narrows what the project publishes is the maintainer's call. It is sent with the call stated in the body: what breaks for existing users, and an offer to narrow or close it. A finding whose only evidence is a measurement is a hold, not a pull request.

4. Prove it red first, and prove the proof. On a fresh clone of the upstream default branch, the new test fails; with the patch, it passes. Every arm of the experiment prints evidence that its precondition held, files are swapped by content and checked by hash, and two arms that agree exactly have not tested the variable.

5. Run their CI, not yours. The project's own test target on the fresh clone, and every gate its pull request workflow runs: lint, format, mutation, API check. A gate not run is a red check the maintainer sees first.

6. Match the house style. comment-check.sh refuses any comment the branch adds to code, test files included; an existing comment may be reworded, a new file may open with the header its neighbours carry, and a maintainer's explicit request for documentation is the one exception. comment-census.sh measures density. The body is under 120 words, in the project's template, and says what was wrong, what changed and how it was verified, every sentence reproduced on the fresh clone. No tool footer, no session link, no co-author trailer, no typographic dash. claim-check.sh lists every counted or absolute claim in the body so each is re-derived against the exact revision it names.

7. Know the paperwork. Before the first pull request to an organization: CLA, DCO, signed-commit requirement, disclosure trailer, and the identity clause. Author, committer and sign-off carry the contributor's real name.

8. Security goes through the side door. A memory-safety, remote-abort, injection or path-escape finding goes by the project's SECURITY.md route, privately, and never becomes a public pull request until the project answers.

9. File through the gate. branch-check.sh refuses a dirty working tree, a file whose mode disagrees with its siblings, a file the repository's own .gitignore excludes, a working artifact, a commit carrying a tool trailer, a session link or a tool identity, a sign-off naming a username, a branch not on top of its base, and any comment added to code; it prints every absolute claim in added prose for falsification, and stamps the head it passed. review.sh names the adversarial reviewer: a different model from the one that wrote the change, one tier down, never below Sonnet. The reviewer gets a fresh context, hard read-only limits and an attack list that starts with every claim the prose makes and includes the form of the code: the reviewer writes the changed block the way the strongest engineer in that language would, in the repository's own idioms, and a smaller or clearer version is a finding; every finding carries evidence it produced itself, and its report is bound to the head and the text it read. A fix is a new head and gets a new review. file-pr.sh is the only way a pull request is opened. It refuses without a prior-art printout under a day old, a policy printout under a day old that does not read BAN, a body that discloses when the policy asks, a branch stamp for the exact head, and a POST AS IS review of that head and that body.

10. Watch it land. verify-filed-pr.sh re-derives from GitHub that the head is the intended commit, the diff is exactly the intended files, and CI settled. inbox.sh prints every event on your threads since the last acknowledged cursor, bodies included, with a census of failing, blocked and conflicting checks. Every maintainer comment gets a same-day answer in the contributor's voice, checked by claim-check.sh and, when it concedes, disagrees or rides on a code change, by the adversarial review. Replies to one repository are spaced ten minutes apart. When the maintainer is right, concede in one sentence. A silent maintainer is never nudged.

11. Clean up. fork-hygiene.sh deletes the fork branch of every merged or closed pull request and lists forks with no pull request left. No planning file, agent directory, journal or build output ever enters a diff.

12. Three per repository, one finding each. A repository gets at most three open pull requests, each one finding, each meeting every rule above on its own, filed at least ten minutes apart.

13. Write it down before you leave. A house rule learned about a repository goes into notes.sh the same session. A maintainer's verdict goes into docs/lessons.md the same day, quoted verbatim with the rule it became. A gate that was wrong, missing or done by hand becomes an issue before the run ends.

Install

You need bash, gh (signed in) and jq. Then, from PyPI; pipx install housebroken-cli and uv tool install housebroken-cli work the same way:

pip install housebroken-cli
housebroken install-skill

The first line puts the housebroken command on your path. The second puts the skill where Claude Code loads it, so the agent runs the door itself before it opens anything upstream. To run the main branch between releases, install from the repository instead:

uv tool install git+https://github.com/lenamonj/housebroken

housebroken help prints the door in order. Every gate is also a plain bash script under scripts/, runnable on its own.

What is in the repository

script gate
scripts/check-ai-policy.sh the AI-contribution policy, read where it lives, with its reading: BAN, DISCLOSE, MENTION, CLEAN
scripts/distinct-outside.sh outside contributors merged in 120 days
scripts/prior-art.sh issues and pull requests on the touched files, type stated, rulings quoted
scripts/comment-check.sh refuses a comment added to code nobody asked for
scripts/comment-census.sh added code versus added comments, per branch
scripts/diff-defaults.sh default arguments and one-line wrappers added to keep call sites untouched
scripts/claim-check.sh every falsifiable claim in a body or a reply, listed to re-derive
scripts/branch-check.sh the branch's mechanical facts: clean tree, modes, artifacts, trailers, sign-offs, comments, absolute claims
scripts/review.sh the adversarial review: a different model attacks the change, and the filing is held to exactly what it read
scripts/file-pr.sh the only way a pull request gets filed: five gates in front of gh pr create
scripts/verify-filed-pr.sh the filed pull request is what was meant, and CI settled
scripts/pr-sweep.sh every open pull request where the ball is in your court
scripts/inbox.sh what GitHub has to tell you since you last looked, bodies included, with a census of every open pull request
scripts/notes.sh what this repository's maintainers have asked for before
scripts/fork-hygiene.sh branches deleted after merge or close, orphan forks listed

The scripts are bash and need gh and jq. Each script's header says what it assumes.

Not in scope

housebroken does not find bugs and does not write patches. Any agent that produces a change can use it. It governs what leaves your machine and how it behaves once it arrives.

FAQ

Is this only for AI-written pull requests? No. Every rule here predates agents. Agents made it cheap to break all of them at once, on a hundred repositories, before breakfast.

Does it make maintainers like agent pull requests? No. It makes the pull request indistinguishable from a careful human's, and answers truthfully when they ask.

What if the maintainer closes it anyway? Then the maintainer is the judge and the ruling stands. Read why, write it down, and if it is a class of mistake, make it a gate.

Why "housebroken"? Because the alternative is what maintainers are calling it.

License

MIT.

Release files for housebroken-cli 0.6.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for housebroken-cli 0.6.3
File Size Uploaded
housebroken_cli-0.6.3.tar.gz 48.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for housebroken-cli 0.6.3
File Interpreter ABI Platform
housebroken_cli-0.6.3-py3-none-any.whl Python 3 none any Details

Total release size: 106.0 kB

Release files / housebroken_cli-0.6.3.tar.gz

Download URL housebroken_cli-0.6.3.tar.gz
Size 48.1 kB
Tags Source
SHA-256 checksum
How to use checksums
6ab843081e6049a4e0b7d76ea46ea98fed94b720edc10ac8aa68a968555c369a
BLAKE2b-256 checksum
How to use checksums
cb562816ab4b48caef8321c632ba812fcce868ae65901daba28bdb12c7c10b6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / housebroken_cli-0.6.3-py3-none-any.whl

Download URL housebroken_cli-0.6.3-py3-none-any.whl
Size 57.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c87359129f530bea8dfbc22c00229a95dac10cb94439fb30a05e5ed98225f0ff
BLAKE2b-256 checksum
How to use checksums
5bbd0a60eac5c1aa5a706b430e9e74c3aaefdc3901a2f139a8f20da00ca6e3d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.4

2 release files

This release

0.6.3 This release

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page