cd /news/ai-agents/l3-simulator-agent-orchestrator-over… · home topics ai-agents article
[ARTICLE · art-62544] src=github.com ↗ pub= topic=ai-agents verified=true sentiment=· neutral

L3 Simulator: agent orchestrator over GH issues

L3 Simulator is an open-source tool that orchestrates AI coding agents over GitHub issues, allowing developers to label issues for automated planning, coding, and PR creation while retaining human review and merge control. The tool uses GitHub labels as its source of truth and supports multi-repo dependencies, plan approval workflows, and automated retries on failure.

read6 min views1 publishedJul 16, 2026
L3 Simulator: agent orchestrator over GH issues
Image: source

Have you ever wanted a tireless junior engineer who never sleeps or doom-scrolls? L3 Simulator orchestrates AI coding agents over your GitHub issues: label an issue ready

and your synthetic L3 claims it, optionally writes up a plan, dispatches a coding agent (Claude Code or Codex) in an isolated git worktree, opens a PR, and babysits it through CI failures, review comments, and merge conflicts. In the meantime you go do something befitting your seniority.

L3 Simulator never merges anything. You are still responsible for code review and merging. The gh

wrapper hard-rejects merge commands, agents are denied gh

and git push

, and CI greps for regressions. Your L3s can open all the PRs they like, but shipping is above their pay grade.

  • Node >= 22 authenticated (gh

gh auth login

)claude

(Claude Code) and/orcodex

CLI installed- A local clone of the repo you want to orchestrate

Install the CLI globally from npm:

npm install -g l3-simulator

This puts an l3-simulator

command on your PATH. Prefer not to install globally? npx l3-simulator <command>

works too. To build from source, see Development.

Then, inside each repo you want to orchestrate:

l3-simulator init

init

writes .l3-simulator.json

into the repo (gitignore it; it contains a local path) and creates the five workflow labels on GitHub. Any command run from inside that repo picks up its config, so multiple repos each get their own daemon, worktrees, state, and logs.

GitHub labels are the orchestrator's source of truth: the issues UI is the dashboard, and a crash or restart re-derives everything from labels + PRs. Your L3s have no memory of their own. You can interact either via the TUI or via the GitHub issues UI.

Label Meaning Who sets it
ready
Start working on this you
needs-plan
Plan first; reply #approve to start coding, anything else revises the plan
you
needs-plan-noreview
Plan first, then code immediately without waiting for approval you
in-progress
Claimed; an agent is (or will be) working orchestrator
blocked
Needs your input (plan approval, questions, failures) orchestrator
in-review
An agent PR is open. Review and merge it yourself orchestrator
failure
Added with blocked when an agent actually failed. Urgent, reply to retry
orchestrator

Lifecycle:

  • Create issue with ready

tag. Optionally addneeds-plan

orneeds-plan-noreview

  • L3 claims an issue (adds in-progress

tag) - (Optional) L3 plans work and posts a comment with the plan, waits for approval

  • Coding L3 starts in a worktree on l3/issue-<n>-<slug>

  • Submits a PR (tags in-review

) - (Optional) comment on the PR to request updates

  • You merge, and the labels are removed

Cross-repo prerequisites file themselves. When a coding agent concludes the work is blocked on changes in another repository, it describes the issue(s) to file there, the orchestrator creates them and the original issue automatically resumes once every prerequisite issue is closed. You can run another instance of L3 Simulator on that repo as well.

Plans are approved explicitly. When a plan is posted (needs-plan

), the issue blocks until you reply. A reply containing #approve

starts coding — anything else in that reply is passed to the coding agent as guidance. Any other reply is treated as plan feedback: the plan agent produces a revised plan and re-posts it for review, as many rounds as you like.

Everything else blocked resumes on a reply. Planning-agent questions, agent failures, and the fix-attempt cap all add blocked

plus an explanatory comment. Replying with any comment unblocks the issue and work resumes with your reply as context. Removing the blocked

label by hand also works. Human comments are passed to the coding agent and take precedence over the plan.

Multi-stage issues. When a coding agent reports its PR is a first slice (done: false

), the issue keeps in-progress

alongside in-review

, and the next stage starts only after you merge the current PR.

While a PR is open the orchestrator polls its health: failing checks, new review comments, or merge conflicts dispatch a fix agent into the same worktree (capped at maxFixIterationsPerPr

per PR; pushing your own commit to the branch resets the counter). Branches that fall behind the base are updated automatically, and merge conflicts are resolved even while an issue is blocked on something else.

Closed issues are tidied automatically: workflow labels are stripped (so the closed list looks clean) and worktrees whose PRs are merged or closed are removed once the issue is no longer active — worktrees with uncommitted changes are left for l3-simulator cleanup --force

.

l3-simulator start                 # TUI dashboard + daemon (q to quit)
l3-simulator start --headless      # plain log lines (cron, background)
l3-simulator start --dry-run       # log every mutation instead of doing it
l3-simulator run-once              # single tick (demos, cron)
l3-simulator status                # one-shot table derived from GitHub
l3-simulator cleanup               # prune worktrees for merged/closed PRs

start

opens a live TUI: every workflow issue with its phase (queued, planning, coding, fixing, plan review, blocked, in review, next stage), the running agent's role + elapsed time + live progress line (on the selected row), the open PR with a CI glyph (✓ ✗ ●), the worktree branch, and a "recently completed" section of closed issues the orchestrator shipped. A log pane shows recent events (--verbose

adds per-tool agent progress).

Keys: ↑↓

/j k

select · n

file a new issue (title, body, label choice — appears on the next tick) · r

force a poll now · o

open a new tmux pane cd'd into the selected issue's worktree ·

open the PR (or issue) in your browser · q

/ctrl-C graceful shutdown (kills agents, releases the lock).

Agent transcripts land in ~/.local/share/l3-simulator/logs/<owner--repo>/issue-<n>/

.

While a fix agent addresses PR feedback, the issue's in-review

label swaps to in-progress

(and back after the push) so GitHub also shows work is active.

~/.config/l3-simulator/config.json

(override with --config

or L3_SIMULATOR_CONFIG

):

{
  "repo": {"path": "/home/you/myrepo", "slug": "you/myrepo"},
  "maxConcurrentAgents": 2,
  "pollIntervalSeconds": 60,
  "maxFixIterationsPerPr": 3,
  "agents": {
    "plan": {"backend": "claude", "timeoutMinutes": 15},
    "code": {"backend": "claude", "timeoutMinutes": 60, "model": "opus"},
    "fix": {"backend": "codex", "timeoutMinutes": 30},
  },
}

Each role (plan

/code

/fix

) independently chooses claude

or codex

, plus optional model

, permissionMode

(Claude), and extraArgs

. Use init --global

for a single per-user config instead (~/.config/l3-simulator/config.json

). Resolution order:

--config

flagL3_SIMULATOR_CONFIG

  • nearest .l3-simulator.json

up the directory tree - user config dir.

No merging. The onlygh pr

subcommands in the codebase are create/list/view/checks/comment/update-branch; the singlegh

choke point (src/github/gh.ts

) rejectsmerge

argv outright.Agents don't touch GitHub. Claude runs withgh

andgit push

disallowed; Codex runs sandboxed. The orchestrator pushes branches and opens PRs itself, and only after verifying the agent actually committed.Claude code/fix agents run with inside their isolated worktree. HeadlessbypassPermissions

acceptEdits

aborts on any shell command, so autonomous work is impossible without it. Thegh

/git push

deny rules are enforced even in bypass mode; setagents.<role>.permissionMode

to tighten this if you prefer explicit allowlists.Anything the orchestrator can't handle is commented on the issue and handed to you. Your L3s know when to escalate to an adult.blocked

is inert.- Recommended: branch protection on your default branch (require review, no force pushes). One daemon per repo (enforced by a pidfile).

npm install              # install dependencies
npm run dev -- status    # run from source (tsx)
npm run demo             # render the sample dashboard (handy for screenshots)
npm test                 # vitest
npm run typecheck && npm run lint && npm run format:check

To use a source build as the global l3-simulator

command: npm run build && npm link

.

── more in #ai-agents 4 stories · sorted by recency
── more on @l3 simulator 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/l3-simulator-agent-o…] indexed:0 read:6min 2026-07-16 ·