simug is a local single-repo orchestrator for Codex-driven pull request workflows.
It watches one GitHub PR lane at a time, feeds new PR events/comments to Codex, validates Codex output, and applies GitHub mutations (push/comments/PR creation) only through the orchestrator.
simug is intended to run as a reliable coordinator between:
- the manager (human operator),
- the orchestrator (
simugitself), - the coding agent session (Codex).
Contract:
simugowns coordination and GitHub side effects (push, PR/comment mutations, issue analysis comments, PR linking).- Codex produces protocol output and repository content changes;
simugshould not directly edit project planning/workflow/source files. - Manager steering enters through authorized commands/comments and is validated by
simug. - Protocol and repository-state validations must pass before
simugperforms remote mutations. - State is persisted so the loop can stop/restart safely and resume deterministically.
Operating model:
- Primary loop handles managed PR task work.
- After merge, loop can switch to issue triage before continuing planned tasks.
- A paused/manual-steering mode is expected where manager messages temporarily gate autonomous progression.
- Enforces one worker process per repo (
.simug/lock). - Finds at most one managed open PR for the authenticated user.
- Fails fast on ambiguous or desynchronized state.
- Polls issue comments, review comments, and reviews.
- Tracks processed events with persistent cursors in
.simug/state.json. - Invokes Codex with a strict
SIMUG: {json}protocol. - Validates branch policy, clean working tree, and commit expectations.
- Pushes/creates/updates PRs from the orchestrator only.
- Linux/macOS shell environment
gitgo(1.22+)gh(GitHub CLI)codexCLI available onPATH(recommended default mode:codex exec)- Authenticated GitHub session (
gh auth login) - Environment-configured Codex runtime (auth configured and writable Codex runtime paths such as
~/.codex, or explicitCODEX_HOME/CODEX_SQLITE_HOME)
Run this once before starting simug:
- Install required CLIs:
git,go,gh, andcodex. - Authenticate GitHub CLI:
gh auth login
gh auth status- Verify Codex CLI is installed and callable:
codex exec --help- Mark the target repository as trusted in Codex config (recommended for non-interactive runs):
[projects."/absolute/path/to/your/repo"]
trust_level = "trusted"- Ensure target repository prerequisites:
- repository has an
originremote pointing to GitHub, - working tree is clean.
- Build and run one deterministic tick:
make build
./bin/simug run --onceIf Codex auth or runtime paths are misconfigured, simug/canary preflight fails early with actionable diagnostics.
sudo apt-get update
sudo apt-get install -y golang-go curl
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null
sudo apt-get update
sudo apt-get install -y ghInstall Codex CLI separately (platform-specific) before running simug:
- project: https://github.com/openai/codex
Verify:
go version
gh --version
git --version
codex exec --helpAuthenticate GitHub CLI:
gh auth loginFrom simug repo root:
go build -o bin/simug ./cmd/simug
# or:
make buildThis creates the binary at ./bin/simug (inside this repo).
Install globally to your Go bin directory (recommended if you want simug available in any repo):
go install ./cmd/simug
# or:
make installThen ensure your Go bin directory is on PATH (commonly ~/go/bin).
Run without building a binary (only from the simug source repo):
go run ./cmd/simug runVerbose console tracing during a run:
./bin/simug run --verboseQuick target discovery:
make helpCommon targets:
make buildmake testmake covermake runmake run-oncemake selfhost-loop ITERATIONS=5make canary-gate CODEX_CMD="codex exec"make chaosmake sandbox-dry-run REPO=. ISSUE_PR=<n> PLANNING_PR=<n> [ISSUE=<n>]
Yes, once built/installed you can run simug from any GitHub repository checkout.
- If installed on
PATH: runsimug runfrom the target repo. - If not on
PATH: use an absolute path (for example/path/to/simug/bin/simug run). - Relative paths also work, but they are relative to your current directory.
simug detects the repository from your current working directory (git rev-parse --show-toplevel), so start it inside the repo you want to manage (repo root or any subdirectory).
Current interface: environment variables plus a small run command flag surface.
Current run flags:
--once-v,--verbose
Current variables:
SIMUG_AGENT_CMD(default: auto-detected:codex execwhen available, elsecodex)SIMUG_POLL_SECONDS(default:30)SIMUG_MAIN_BRANCH(default:main)SIMUG_BRANCH_PREFIX(default:agent/)SIMUG_MAX_REPAIR_ATTEMPTS(default:2)SIMUG_ALLOWED_COMMAND_USERS(default: current authenticated user)SIMUG_ALLOWED_COMMAND_VERBS(default:do,retry,status,continue,comment,report,help)SIMUG_GUIDANCE_PATHS(default: prepend repo-relative bootstrap guidance candidates ahead of built-in discovery such asAGENTS.md, workflow/planning docs, andREADME.md)SIMUG_PLANNING_PATHS(default: prepend repo-relative planning-status candidates ahead of built-indocs/PLANNING.md,PLANNING.md)
Example:
export SIMUG_AGENT_CMD="codex exec"
export SIMUG_POLL_SECONDS=20
export SIMUG_ALLOWED_COMMAND_USERS="my-github-login,teammate-login"
export SIMUG_ALLOWED_COMMAND_VERBS="do,retry,status,comment"
export SIMUG_GUIDANCE_PATHS="meta/BOOTSTRAP.md,meta/PLAYBOOK.md"
export SIMUG_PLANNING_PATHS="meta/TASKS.md"This section is only for developing simug itself with Codex.
For normal simug usage on another project repository:
simug(the orchestrator process) needsgh/gitnetwork access.- Codex does not need direct
ghCLI access, becausesimugowns GitHub mutations.
If you do run Codex directly in this repo while developing simug, sandboxed gh/git network operations can fail even when local shell auth is valid.
Example Codex configuration for self-hosted simug development:
- Enable network in workspace-write sandbox.
- Keep approvals enabled (
on-request) or run with full access for unattended flows. - Ensure Codex sees valid GitHub auth (
~/.config/gh/hosts.ymlorGH_TOKEN/GITHUB_TOKEN).
Example ~/.codex/config.toml:
[projects."/absolute/path/to/repo"]
trust_level = "trusted"
[profiles.simug]
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = trueWithout a trusted project entry, Codex may prompt/block on repository trust in non-interactive flows.
Use that profile in non-interactive mode (or in SIMUG_AGENT_CMD) for this self-hosted workflow:
codex exec --profile simug
export SIMUG_AGENT_CMD="codex exec --profile simug"One-off equivalent without editing config file (self-hosted workflow):
codex exec --sandbox workspace-write --ask-for-approval on-request \
--config sandbox_workspace_write.network_access=trueIf you need fully unattended execution (no approval prompts), use only in a trusted/dev container:
codex exec --sandbox danger-full-access --ask-for-approval never
# or: codex exec --dangerously-bypass-approvals-and-sandboxQuick verification from the same Codex session (self-hosted workflow):
gh auth status
gh api user -q .login
gh pr list --limit 1
git ls-remote origin >/dev/null
curl -I https://api.github.comIf gh auth status reports token ... is invalid but curl cannot resolve api.github.com, the root cause is sandbox/network restriction, not token validity.
cdinto a GitHub repository checkout.- Ensure
originpoints to GitHub. - Ensure working tree is clean.
- Start worker:
simug run
# one-shot mode (single tick):
simug run --once
# or with absolute path:
/path/to/simug/bin/simug run- Drive execution through PR comments using
/agent ...commands from authorized users. - Let
simugkeep running and monitoring PR events.
When a run fails, get a one-command diagnosis:
simug explain-last-failureA PR is managed only when:
- it is open,
- it is authored by the authenticated GitHub user,
- its head branch matches the managed pattern (default
agent/<timestamp>-<slug>).
If more than one authored open PR exists, worker exits with a clear error to prevent desync.
For simug-on-simug development, use the wrapper script:
scripts/self-host-loop.sh --iterations 5For restart-boundary self-host canary validation:
scripts/self-host-canary.sh --repo . --iterations 4For stop/restart chaos validation:
scripts/chaos-stop-restart.sh --repo . --sleep-seconds 2Prerequisites for chaos validation:
- repository checkout has an
originremote, gh auth statussucceeds,- working tree is clean.
Go/no-go criteria for enabling self-host default are documented in docs/runbooks/SELF_HOST_GO_NO_GO.md.
To validate protocol behavior against a real Codex runtime (not shell fixtures):
scripts/canary-real-codex-protocol.sh --cmd "codex exec" --out .simug/canary/real-codexThis runs TestRealCodexProtocolConformanceCanary with real runtime prompts and archives per-scenario artifacts (prompt.txt, raw_output.txt, result.json) under the chosen output directory.
When --cmd is omitted, the script auto-detects and prefers codex exec.
For Codex commands, scripts run a lightweight preflight (--help) and fail fast with actionable diagnostics for auth/path-permission blockers.
To validate repair/restart boundaries with real Codex runtime:
scripts/canary-real-codex-recovery.sh --cmd "codex exec" --out .simug/canary/real-codexTo run the combined real-Codex validation gate (protocol + recovery):
scripts/canary-real-codex-gate.sh --cmd "codex exec" --out .simug/canary/real-codex --retain-days 14To verify live sandbox dry-run evidence (issue-driven + planning-driven PRs):
scripts/sandbox-dry-run.sh --repo <owner/name> --issue-pr <n> --planning-pr <n> --issue <n>
# or from local checkout path:
scripts/sandbox-dry-run.sh --repo . --issue-pr <n> --planning-pr <n> --issue <n>sandbox-dry-run is an evidence verifier, not a smoke test: PR numbers must already exist and be merged.
What it does per iteration:
- rebuilds
bin/simug, - runs
./bin/simug run --once, - captures stdout/stderr and state snapshots under
.simug/selfhost/<timestamp>/.
The script exits immediately on the first non-zero simug exit code so supervisor behavior stays deterministic.
simug writes:
.simug/state.json(persistent cursors and active PR state).simug/lock(single-process guard).simug/events.log(JSONL event/audit log).simug/archive/agent/...(per-attempt Codex prompt/output archival artifacts)
events.log includes high-fidelity trace entries (command_trace, invariant_decision, tick_start, tick_end) with run/tick correlation IDs for post-failure reconstruction.
Codex must emit machine-readable lines:
SIMUG_MANAGER: <human-friendly manager message>
SIMUG: {"action":"comment","body":"..."}
SIMUG: {"action":"reply","comment_id":123,"body":"..."}
SIMUG: {"action":"issue_update","issue_number":123,"relation":"fixes","comment":"..."}
SIMUG: {"action":"done","summary":"...","changes":true}
SIMUG: {"action":"idle","reason":"..."}
Rules:
- exactly one terminal action (
doneoridle), - malformed protocol is treated as failure,
- manager-facing human text must use
SIMUG_MANAGER:prefix, - unprefixed non-empty output lines are quarantined by the orchestrator (not treated as protocol),
- issue-related GitHub mutations stay orchestrator-owned (
issue_updateis intent, not direct mutation), - Codex must not push or create PR directly.
- Start
simugin this repository. - Use GitHub comments (
/agent ...) to steer work. simuginvokes Codex, validates output, pushes, and posts replies/comments.- Repeat until PR merge, then it can bootstrap the next task.
multiple open PRs authored by ...- close/merge extra PRs so only one managed lane remains.
checkout mismatch for PR ...- checkout correct branch and sync local/remote/PR head.
working tree is dirty- commit/stash/clean before running.
agent failed validation after ... attempts- inspect
.simug/events.logand last Codex output contract.
- inspect
- need a fast failure summary
- run
simug explain-last-failureto get the last failed tick reason, invariant context, and suggested next action.
- run
gh ... failed- verify
gh auth status, repo permissions, and network access.
- verify
gofmt -w $(find . -name '*.go')
go test ./...
GOCACHE=/tmp/go-build GOEXPERIMENT=nocoverageredesign go test ./... -coverprofile=coverage.out
GOCACHE=/tmp/go-build go tool cover -func=coverage.out