Deterministic agent invocation. Define a chain of agent calls that will get invoked, in sequence, on every commit. Get alerted via the Claude Code statusline when downstream agents make changes, and use the /detergent-rebase skill to automatically pull them in.
Kinda like CI, but local.
Everything is in Git, so you lose nothing. If you also use claudit, your agent can automatically attach chat history as Git Notes.
curl -fsSL https://raw.githubusercontent.com/re-cinq/detergent/master/scripts/install.sh | bashThen, in your repo:
detergent init # Set up skills
detergent run # Start the daemon (there's a skill for this too)
detergent status # See what's going on
detergent status -f -n 1 # Follow the status, refreshing every 1 secondCreate a config file detergent.yaml:
agent:
command: claude
args: ["--dangerously-skip-permissions", "-p"]
settings:
poll_interval: 5s
watches: main
concerns:
- name: security
prompt: "Review for security vulnerabilities. Fix any issues found."
- name: docs
prompt: "Ensure public functions have clear documentation."
- name: style
prompt: "Fix any code style issues."Concerns are processed as an ordered chain: each concern watches the one before it, and the first concern watches the branch specified in settings.watches (defaults to main).
Note: Detergent automatically prepends "You are running non-interactively. Do not ask questions or wait for confirmation." to every concern prompt, so agents proceed autonomously without pausing for user input.
If your agent is Claude Code, you can pre-approve tool permissions instead of using --dangerously-skip-permissions. Add an optional permissions block — detergent writes it as .claude/settings.json in each worktree before invoking the agent:
permissions:
allow:
- Edit
- Write
- "Bash(*)"Models will absolutely forget things, especially if context is overloaded (there's too much) or polluted (too many different topics). However, if you prompt them with a clear context, they'll spot what they overlooked straight away.
- ...do it yourself? As a human, trying to remember to run the same set of quality-check prompts before every commit is a hassle.
- ...do it in CI? Leaving these tasks until CI delays feedback, your agent might not be configured to read from CI, and sometimes you don't want to push.
- ...use a Git hook? Not being able to commit in a hurry would be inconvenient. Plus, with
detergentyou can tell your main agent to commit withskip detergentif you want.
# Validate your config (defaults to detergent.yaml)
detergent validate
# See the concern chain
detergent viz
# Run once and exit
detergent run --once
# Run as daemon (polls for changes)
detergent run
# Check status of each concern
detergent status
# Live-updating status (like watch, tails active agent logs)
detergent status -f
# View agent logs for a concern
detergent logs security
# Follow agent logs in real-time
detergent logs -f security
# Use a different config file
detergent run --path my-config.yaml
# Initialize Claude Code integration (statusline + skills)
detergent init- Detergent watches branches for new commits
- When a commit arrives, it creates a worktree for each triggered concern
- The agent receives: the prompt + upstream commit messages + diffs
- Agent changes are committed with
[CONCERN]tags andTriggered-By:trailers - If no changes needed, a git note records the review
- Downstream concerns see upstream commits and can build on them
- The statusline shows
*next to concerns that produced changes — use/detergent-rebaseto pull them back into your working branch
Agent work accumulates on concern branches (detergent/security, detergent/style, etc.). The /detergent-rebase skill merges the terminal concern's branch back into main:
- Finds the terminal concern (the end of the chain — nothing watches it)
- Verifies the chain is complete (no concerns still running or failed)
- Creates a backup branch (
pre-rebase-backup) and stashes uncommitted work - Rebases main onto the terminal branch, resolving conflicts if needed
- Restores stash and reports what happened
If anything goes wrong: git reset --hard pre-rebase-backup
Note: When running as a daemon, detergent automatically reloads detergent.yaml at the start of each poll cycle. Config changes take effect immediately without requiring a restart.
detergent init sets up:
- Statusline — shows the concern pipeline in Claude Code's status bar:
main ─── security ✓ ── docs ⟳ ── style ·- When on a terminal concern branch that's behind HEAD, displays a bold yellow warning:
⚠ use /detergent-rebase to pick up latest changes
- When on a terminal concern branch that's behind HEAD, displays a bold yellow warning:
- Skills — adds
/detergent-startto start the daemon as a background task and/detergent-rebasefor rebasing concern branch changes onto their upstream
| Symbol | Meaning |
|---|---|
◎ |
Change detected |
⟳ |
Agent running / committing |
◯ |
Pending (behind HEAD) |
✗ |
Failed |
⊘ |
Skipped |
* |
Done, produced modifications |
✓ |
Done, no changes needed |
· |
Never run |
- Branches:
detergent/{concern-name}(configurable prefix) - Commits:
[SECURITY] Fix SQL injection in loginwithTriggered-By: abc123trailer - Notes:
[SECURITY] Reviewed, no changes neededwhen agent makes no changes - Skipping processing: Add
[skip ci],[ci skip],[skip detergent], or[detergent skip]to commit messages to prevent detergent from processing them
make build # Build binary (bin/detergent)
make test # Run acceptance tests
make lint # Run linter (requires golangci-lint)
make fmt # Format code