Important: you must clone both this repo and the open-source Codex repo. slop-janitor talks directly to Codex's app-server implementation, so it will not work with only this repository checked out.
slop-janitor automatically makes a repo cleaner, simpler, and more reliable.
Using Codex well usually means manually queuing a long chain of follow-up messages:
- ask Codex for materially different refactor candidates
- ask it to pressure-test the shortlist and lock one refactor
- ask it to turn that decision into an exec plan
- ask it to improve the plan
- ask it to implement the plan
- ask it to review the result
slop-janitor janitor runs that loop for you on one thread.
slop-janitor builder is for bigger feature work. It turns an explicit project
brief into a parent Meta Exec Plan, then executes each slice through the normal
ExecPlan loop.
slop-janitor goals run is for a simpler goal-plan workflow. You chat freely
with Codex, invoke create-goals to write .agent/goals/<id-slug>/ and point
.agent/goals/active at it, approve or edit that plan, then let slop-janitor
execute the ordered goals one at a time through Codex's thread goal API.
It follows the PLANS.md pattern from OpenAI's Codex exec plans guide: plan, improve the plan, implement, and review. That is the basic trick for keeping an agent on the same problem for a long time instead of resetting every turn. Background: Codex Exec Plans.
This tool uses the account you sign into Codex with for inference and token usage.
It also writes a complete run log, so the session is inspectable after the fact rather than something that only existed in the terminal.
By default, one janitor cycle is:
find-refactor-candidatesselect-refactorexecplan-createexecplan-improveimplement-execplanreview-recent-work
You can change the number of janitor cycles, improvement passes, and review
passes. The follow-up skills are intentionally fixed to execplan-improve and
review-recent-work.
The loop is built from a small set of repo-local skills in .agents/skills:
create-meta-plan: creates a parent Meta Exec Plan under.agent/meta-plans/for builder mode.create-goals: creates a sequential goal plan under.agent/goals/for goal mode.complete-goals: launches the approved active goal plan throughslop-janitor goals run.find-refactor-candidates: searches the repo from first principles and writes a candidate shortlist into a work item.select-refactor: pressure-tests that shortlist and locks the winning refactor before planning starts.execplan-create: turns a locked refactor decision into an ExecPlan.execplan-improve: rewrites that plan with code-grounded corrections and missing details.implement-execplan: executes the active work-item ExecPlan while updating work-item state.review-recent-work: reviews the most recently implemented ExecPlan work and fixes obvious issues immediately.
- Python 3.11 or newer.
- Rust and
cargo. - A separate clone of the open-source Codex repository.
- A Codex login.
The bundled skills used by slop-janitor live in .agents/skills inside this repository.
Clone this repository and clone Codex separately:
git clone https://github.com/grp06/slop-janitor.git
git clone https://github.com/openai/codex.gitPoint slop-janitor at the Codex Rust workspace:
export CODEX_WORKSPACE=/path/to/codex/codex-rsYou can also pass the path per command with --codex-workspace /path/to/codex/codex-rs.
Authenticate through the wrapped Codex login flow:
cd slop-janitor
./slop-janitor auth login
./slop-janitor auth login --device-auth
./slop-janitor auth status
./slop-janitor auth logoutThe auth wrapper keeps stdin, stdout, and stderr attached to the terminal, so it behaves like native codex login. If your Codex access comes through ChatGPT, it will use that account. Details: Using Codex with your ChatGPT plan.
Run it from the repository you want to improve:
cd /path/to/target-repo
/path/to/slop-janitor/slop-janitorThe no-subcommand form is kept as shorthand for janitor:
cd /path/to/target-repo
/path/to/slop-janitor/slop-janitor janitorAdd guidance if you want to steer the refactor:
cd /path/to/target-repo
/path/to/slop-janitor/slop-janitor --prompt "focus on testability and simplifying boundaries"Increase the amount of iteration:
cd /path/to/target-repo
/path/to/slop-janitor/slop-janitor --prompt "focus on testability and simplifying boundaries" --cycles 2 --improvements 5 --review 3Use builder mode for a larger project with explicit direction:
cd /path/to/target-repo
/path/to/slop-janitor/slop-janitor builder --prompt "build the new project workflow" --slices 5Use an existing Meta Exec Plan:
cd /path/to/target-repo
/path/to/slop-janitor/slop-janitor builder --meta-plan .agent/meta-plans/my-project-planUse goal mode after creating and approving a goal plan:
cd /path/to/target-repo
# In chat: invoke create-goals, review .agent/goals/<id-slug>/, then approve it.
/path/to/slop-janitor/slop-janitor goals run
# Or run a specific plan explicitly:
/path/to/slop-janitor/slop-janitor goals run .agent/goals/<id-slug>Make sibling repos writable and auto-managed explicitly when one run needs to touch both:
cd /path/to/openclaw-cloud
/path/to/slop-janitor/slop-janitor --linked-repo /path/to/openclaw-studio-privateIf you want to restrict Codex to writable managed repo roots, opt in explicitly:
cd /path/to/target-repo
/path/to/slop-janitor/slop-janitor --prompt "focus on testability and simplifying boundaries" --sandbox workspace-writeslop-janitor always targets the directory you launch it from, not the slop-janitor repository.
janitor mode finds and executes one refactor loop. builder mode either
creates a parent Meta Exec Plan or executes an existing one.
--prompt is optional in janitor mode. If you omit it, stage 1 asks for materially different refactor candidates in the current repository.
--prompt is required in builder mode only when creating a new Meta Exec Plan.
--slices is required in builder mode only when creating a new Meta Exec Plan. It controls how many slices are created and attempted in the run.
--meta-plan PATH runs an existing active Meta Exec Plan instead of creating a new one. The path may point to .agent/meta-plans/<id>/ or .agent/meta-plans/active; it cannot be combined with --prompt or --slices.
goals run [PATH] runs an existing active goal plan under .agent/goals/<id>/.
If PATH is omitted, it uses .agent/goals/active. The plan must contain
brief.md, goals.json, and ledger.jsonl. Each goal is loaded from
goals.json, installed into the Codex thread with thread/goal/set, executed,
observed with thread/goal/get, persisted back to the plan, and checkpointed
before the next goal starts.
--cycles controls how many times the janitor loop runs.
--improvements controls how many plan-improvement turns run inside each cycle.
--review controls how many review turns run inside each cycle.
--linked-repo /abs/path adds another git repo to the managed run scope. Repeat it for more repos. These repos are checked for cleanliness, included in checkpoint commits, and added to the writable sandbox roots.
--sandbox controls the Codex filesystem sandbox. Choices are workspace-write and danger-full-access. The default is danger-full-access.
--stage-idle-timeout-seconds controls how long a stage may go without any app-server activity before slop-janitor treats it as stuck and restarts recovery. The default is 900.
--max-stage-retries controls how many retry attempts are allowed after the first failure for a single stage. The default is 6.
--retry-initial-delay-seconds and --retry-max-delay-seconds control the capped exponential backoff between retry attempts. The defaults are 15 and 300.
Defaults:
--cycles 1--improvements 1--review 1--sandbox danger-full-access--stage-idle-timeout-seconds 900--max-stage-retries 6--retry-initial-delay-seconds 15--retry-max-delay-seconds 300
When --cycles is greater than 1, janitor stage labels in the run log are cycle-qualified, for example cycle-2-execplan-create. Builder stage labels are slice-qualified, for example slice-2-execplan-create.
Prompt path detection is still supported as a convenience for linked repos, but explicit --linked-repo flags are the durable interface and avoid punctuation/parsing ambiguity.
When slop-janitor launches the real Codex app-server or wrapped auth commands, it resolves the Codex workspace in this order:
--codex-workspace /path/to/codex-rsCODEX_WORKSPACE
If neither is set, the command fails with a clear setup error.
Examples:
./slop-janitor --codex-workspace /path/to/codex/codex-rs --prompt "focus on testability and simplifying boundaries"
./slop-janitor builder --codex-workspace /path/to/codex/codex-rs --prompt "build the new project workflow" --slices 5
./slop-janitor builder --codex-workspace /path/to/codex/codex-rs --meta-plan .agent/meta-plans/my-project-plan
./slop-janitor auth --codex-workspace /path/to/codex/codex-rs loginBefore stage 1, the client performs:
initializewithcapabilities.experimentalApi = trueinitializedaccount/readthread/start
Goal mode additionally uses the experimental app-server methods
thread/goal/set, thread/goal/get, and thread/goal/clear directly. It does
not send /goal slash commands.
If account/read says OpenAI auth is required and no account is logged in, the command fails immediately and tells you to run ./slop-janitor auth login.
After that, every janitor stage in a cycle runs as a turn/start on the same thread. Builder creates the parent Meta Exec Plan on one thread, then starts a fresh thread for each slice so each child ExecPlan relies on durable artifacts instead of long conversational context.
The terminal is intentionally sparse. During a run, it shows:
- agent-message commentary
- final agent-message text
- token usage
Everything else goes to the run log:
- stage banners
- command output
- file-change progress
- MCP progress
- item lifecycle notices
- failure details
Each run writes a full log to runs/. Log filenames start with the basename of the directory you launched from, followed by a UTC timestamp, for example my-repo-20260317T213000Z.log.
Each run also writes a machine-readable state file next to the log, using the same basename with a .state.json suffix. The state file tracks the current stage, retry attempt, thread id, and recovery status so long autonomous runs stay inspectable.
This split is deliberate. The terminal stays readable while the log remains complete.
slop-janitorrequires a clean starting state in the primary repo and every linked repo it auto-manages. If any of them have pre-existing changes, it exits before stage 1 and tells you to commit, stash, or discard them first.- Model settings are inherited from your current Codex config.
slop-janitoroverrides the threadcwd, forcesapprovalPolicy: "never", and applies the selected sandbox mode for the whole run. - In the default
danger-full-accesssandbox, Codex runs without filesystem sandboxing. If you pass--sandbox workspace-write,slop-janitormakes every managed repo root writable, not just the launch directory, and records the exact writable roots before stage 1. - The thread uses
approvalPolicy: "never". - Auto-managed repos that start clean are required to stay clean at stage boundaries, except for the workflow artifacts under
.agent/in the primary repo while candidate selection, planning, or implementation is in progress. - Auto-managed repos are checkpointed after the final planning pass, after
implement-execplan, and after the final review pass when those stages leave code changes behind. Builder also checkpoints aftercreate-meta-planwhen it creates a new parent plan. - Transient model-capacity failures such as
serverOverloadedare retried automatically with capped exponential backoff. - If a stage stops producing app-server activity, or the app-server process dies mid-stage,
slop-janitorrestarts the app-server and retries the current stage on a fresh thread. - Before replaying a failed stage,
slop-janitorcompares the current workspace against a stage-start snapshot. If the stage appears to have partially changed repo state without satisfying a strong postcondition, the run stops instead of retrying blindly. - If a cycle-start stage already refreshed its primary workflow artifact, or
implement-execplanalready marked the active work item as completed,slop-janitortreats that stage as completed and continues rather than replaying it. - If the server asks for approvals, user input, permissions, MCP elicitation, or ChatGPT token refresh,
slop-janitorresponds deterministically, marks the stage failed, and exits after the matchingturn/completed. - Successful turns require real token data from
thread/tokenUsage/updated. If a turn completes successfully without token usage, the run fails instead of printing invented zeros. - Skill paths are validated before the app-server starts, so broken local setup fails early.
The tool is strict on purpose. When something is wrong, it should stop in a way you can diagnose.
Run the test suite from the repository root:
python3 -m unittest discover -s tests -p 'test_*.py' -v