Metadata-Version: 2.4
Name: codex-planner
Version: 0.2.0
Summary: Local orchestration tooling for planner and worker Codex sessions.
Author: Codex Orchestrator maintainers
License-Expression: MIT
Project-URL: Homepage, https://github.com/peremarc/codex-orchestrator
Project-URL: Repository, https://github.com/peremarc/codex-orchestrator
Project-URL: Issues, https://github.com/peremarc/codex-orchestrator/issues
Keywords: codex,cli,orchestration,tmux,git-worktree
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Terminals
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.27.0
Requires-Dist: PyYAML>=6.0
Provides-Extra: dev
Requires-Dist: build>=1.2.2; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: twine>=6.1.0; extra == "dev"
Dynamic: license-file

# Codex Orchestrator

Codex Orchestrator is an installable CLI tool for coordinating one `planner` Codex session plus multiple `worker` sessions against the same repository.

The design goal is explicit orchestration:

- one global command: `codex-planner`
- one machine-level installation
- one repo-local state directory: `.codex/`
- visible session prompts and traceable runtime actions
- isolated worker worktrees via `git worktree`

The intended operator workflow is planner-first: you launch `codex-planner`, talk only to the `planner`, and let the planner create tasks, spawn workers, collect worker escalations, and come back to you only when a real decision is needed.

## Current Sprint 1 Scope

This repository currently ships the first technical MVP:

- installable Python package with console entrypoint
- one-command launch flow: `codex-planner`
- guided usage command: `codex-planner quickstart`
- repo dashboard command: `codex-planner dashboard`
- repo bootstrap command: `codex-planner init`
- readiness diagnostics: `codex-planner doctor`
- session attach command: `codex-planner attach`
- board inspection commands: `codex-planner list-tasks`, `list-sessions`, `show-handoff`, `show-prompt`
- resource inspection commands: `codex-planner resources`, `list-leases`
- task creation command: `codex-planner create-task`
- task update commands: `codex-planner update-task`, `request-review`, `request-input`, `resume-task`
- planner startup flow: `codex-planner start-planner`
- worker launch flow: `codex-planner spawn-worker`
- heavy-work lease flow: `codex-planner acquire-lease`, `release-lease`
- repo suspend flow: `codex-planner suspend`
- generic session closure: `codex-planner close-session`
- worker closure flow: `codex-planner close-worker`
- repo-local MCP/plugin layer backed by `codex-planner serve-mcp`
- YAML-backed board under `.codex/board/`
- real `git worktree` manager for future workers
- terminal backend abstraction with `auto`, `desktop`, and `tmux` modes

Worker orchestration now exists as explicit CLI-driven flows plus a structured MCP/plugin layer. The default `codex-planner` launch path now prepares that direct MCP wiring automatically when possible.

## Installation

### `pipx`

Install the published package globally:

```bash
pipx install codex-planner
```

### `uv tool`

Install the published package globally:

```bash
uv tool install codex-planner
```

### Local checkout

From a local checkout:

```bash
pipx install .
```

or:

```bash
uv tool install .
```

Every installation path exposes the same global command:

```bash
codex-planner --help
```

## Publishing to PyPI

The package is published on PyPI as `codex-planner`.

The distribution package name is `codex-planner`. This keeps the PyPI install name aligned with the CLI command and avoids a collision with an existing `codex-orchestrator` project on PyPI.

For operators, the public install path is now:

```bash
pipx install codex-planner
```

or:

```bash
pip install codex-planner
```

This repository also includes `.github/workflows/publish.yml` for Trusted Publishing via GitHub Actions releases. For future versions, the release flow is:

1. Bump the version in `pyproject.toml`.
2. Validate the distributions locally.
3. Create or publish a GitHub Release.
4. Let the workflow build `sdist` and `wheel` and publish them to PyPI.

To validate distributions locally before a release:

```bash
python3 -m pip install --upgrade build twine
python3 -m build
python3 -m twine check dist/*
```

If you need a manual fallback instead of GitHub Actions:

```bash
python3 -m pip install --upgrade build twine
python3 -m build
python3 -m twine upload dist/*
```

## Fastest Path

Inside a Git repository, the simplest operator path is now:

```bash
codex-planner
```

You can run that from the main repo root, any subdirectory inside the repo, or a same-repo Git worktree. The CLI now canonicalizes those entrypoints back to the primary repository root so planner resume, `.codex/`, and dashboard/session identity stay tied to one project context.

In one step, that command:

1. checks that the machine is ready enough to launch the planner
2. initializes `.codex/` if needed
3. ensures the direct Codex MCP server registration for `codex-orchestrator-local`
4. reconciles stale planner or worker sessions whose terminal backends no longer exist
5. starts a planner session if one is not already running for the repo
6. if no planner terminal is currently running, resumes the latest Codex planner session recorded for this repo context when available
7. otherwise reuses the running planner session
8. ensures a repo dashboard session exists when the active backend supports dashboards
9. attaches you to that dashboard or planner session immediately when the command is run interactively

If you run it from a non-interactive context, it still performs the setup and prints the relevant attach or visibility command instead of blocking.

If you want a clean planner context instead of resuming the last one:

```bash
codex-planner --new-session
```

If you want the tool to explain the operator flow with concrete commands for the current repository:

```bash
codex-planner quickstart
```

That command prints:

- the active terminal backend
- whether the repo is already initialized
- the recommended planner-first workflow
- the planner-only operator boundary, where workers escalate through the planner instead of talking directly to the user
- the structured handoff flow that workers receive
- example manual commands for creating a task and launching a worker
- the live planner and worker session names, when they already exist

## Global vs Repo-Local State

The tool is intentionally split into two layers:

### Global installation and config

- installed once per machine
- configuration lives outside repos
- default config path:
  `~/.config/codex-orchestrator/config.toml`

### Repo-local runtime state

- created per repository with `codex-planner init`
- stored only under `.codex/`
- contains board files, prompts, logs, and rendered prompt artifacts

`Codex Orchestrator` does not store repo runtime state in a global cache.

## Global Configuration

Default config file:

```toml
[defaults]
terminal_backend = "auto"
codex_executable = "codex"
git_executable = "git"

# Optional
# worktrees_base_dir = "~/codex-worktrees"
# planner_model = "gpt-5.4"
# worker_model = "gpt-5.4-mini"
# max_heavy_leases = 3
# max_loadavg_1 = 3.2
# min_mem_available_gb = 6.0
# worker_spawn_max_loadavg_1 = 2.4
# worker_spawn_min_mem_available_gb = 8.0
# lease_ttl_seconds = 1800
```

Supported terminal backend values:

- `auto`: prefer a desktop terminal window when a graphical session is available and a supported emulator exists; otherwise fall back to `tmux`
- `desktop`: force a native terminal window per planner or worker session; currently supports `gnome-terminal` and `xterm`
- `tmux`: force the tmux-backed dashboard and attach flow

Supported environment overrides:

- `CODEX_ORCHESTRATOR_CONFIG`
- `CODEX_ORCHESTRATOR_TERMINAL_BACKEND`
- `CODEX_ORCHESTRATOR_CODEX_EXECUTABLE`
- `CODEX_ORCHESTRATOR_GIT_EXECUTABLE`
- `CODEX_ORCHESTRATOR_WORKTREES_BASE_DIR`
- `CODEX_ORCHESTRATOR_PLANNER_MODEL`
- `CODEX_ORCHESTRATOR_WORKER_MODEL`
- `CODEX_ORCHESTRATOR_MAX_HEAVY_LEASES`
- `CODEX_ORCHESTRATOR_MAX_LOADAVG_1`
- `CODEX_ORCHESTRATOR_MIN_MEM_AVAILABLE_GB`
- `CODEX_ORCHESTRATOR_WORKER_SPAWN_MAX_LOADAVG_1`
- `CODEX_ORCHESTRATOR_WORKER_SPAWN_MIN_MEM_AVAILABLE_GB`
- `CODEX_ORCHESTRATOR_LEASE_TTL_SECONDS`

Environment variables override file-based settings.

Heavy-work concurrency defaults to automatic mode when `max_heavy_leases` is omitted. In that mode the effective limit is:

```text
max(1, floor(cpu_count / 2))
```

This limit applies to the host-global heavy-work lease budget shared across repositories on the machine.

Set `max_heavy_leases` to a positive integer only when you want a manual override.

Worker-launch admission uses the heavy-work CPU and memory thresholds by default. If you want `spawn-worker` to be more conservative than heavy-command admission, set `worker_spawn_max_loadavg_1` and/or `worker_spawn_min_mem_available_gb` explicitly. When those keys are omitted, `spawn-worker` inherits `max_loadavg_1` and `min_mem_available_gb`.

## Doctor

Run this before using the tool on a machine:

```bash
codex-planner doctor
```

`doctor` currently checks:

- global config loading
- `codex` availability
- `git` availability
- `git worktree` usability
- configured terminal backend readiness

Backend-specific readiness:

- `auto` resolves to `desktop` when `DISPLAY` or `WAYLAND_DISPLAY` is set and a supported terminal emulator is available; otherwise it resolves to `tmux`
- `desktop` requires a graphical session plus either `gnome-terminal` or `xterm`
- `tmux` requires `tmux` on `PATH`

## Repository Bootstrap

Inside a Git repository:

```bash
codex-planner init
```

This creates the repo-local control plane:

```text
.codex/
  board/
    tasks.yaml
    sessions.yaml
    decisions.md
    risks.md
    backlog.md
  handoffs/
  prompts/
    planner.md
    worker.md
    reviewer.md
  logs/
    orchestrator.jsonl
  state/
    rendered_prompts/
```

The YAML files are the shared source of truth for tasks and active sessions.

Heavy-work leases are persisted separately in a host-global registry under:

```text
$XDG_STATE_HOME/codex-orchestrator/leases.yaml
```

or, when `XDG_STATE_HOME` is unset:

```text
~/.local/state/codex-orchestrator/leases.yaml
```

## Start the Planner

After `init`:

```bash
codex-planner start-planner
```

For normal day-to-day use, prefer `codex-planner` without subcommands. `start-planner` remains available when you want an explicit low-level entrypoint.

What this does today:

1. validates the repo is initialized
2. resumes the latest Codex planner session recorded for this repo when one exists
3. otherwise renders a persisted planner prompt into `.codex/state/rendered_prompts/`
4. prepares the corresponding interactive Codex CLI command, including per-session Codex config overrides when needed
5. launches the configured terminal backend
6. registers the planner session in `.codex/board/sessions.yaml`
7. appends a trace event to `.codex/logs/orchestrator.jsonl`

Planner and worker sessions now launch Codex with `--yolo` by default, so they start without the normal sandbox or approval prompts. In the current Codex CLI on this VPS, that is the convenience flag for bypassing sandboxing and approvals entirely.

To force a clean planner conversation from this lower-level entrypoint:

```bash
codex-planner start-planner --new-session
```

For tmux-backed interactive sessions, the launcher also detects Codex's initial per-repo trust prompt and confirms it automatically when it appears.

If Codex already has an orchestrator MCP server configured under `codex-orchestrator-local` or `codex-orchestrator`, `start-planner` also injects a per-session override that sets `default_tools_approval_mode="approve"` for that server. This keeps the planner's own orchestration tool calls from stopping on a repeated approval menu while avoiding invalid overrides for MCP servers that are not actually installed in the local Codex config.

The default `codex-planner` launch path goes one step further and ensures the direct `codex-orchestrator-local` MCP registration exists before planner startup, so a fresh machine does not require a separate manual `codex mcp add` just to reach a usable planner.

Sprint 1 decision:

- the `planner` runs in the main repository worktree
- extra worktrees are reserved for future worker sessions
- the default portable launcher path is `terminal_backend = "auto"`, which uses separate native terminal windows on graphical machines and falls back to a repo-scoped tmux dashboard on headless or terminal-only machines

## Planner Tool Layer

The repository now includes a repo-local plugin scaffold under `plugins/codex-orchestrator-tools/` plus a marketplace file at `.agents/plugins/marketplace.json`.

The plugin does not depend on local source paths. It launches the globally installed CLI entrypoint:

```bash
codex-planner serve-mcp
```

Activate the repo-local marketplace from the repository root:

```bash
codex marketplace add .
```

If you prefer a direct machine-level MCP registration instead of the repo-local marketplace:

```bash
codex mcp add codex-orchestrator -- codex-planner serve-mcp
```

Live validation in this repository confirmed that a planner started after direct MCP registration can call the orchestrator tools through Codex without per-tool approval prompts, as long as the configured server name matches one of the supported orchestrator registrations above.

The structured tool layer currently exposes:

- `doctor`
- `init_repo`
- `list_tasks`
- `create_task`
- `update_task`
- `request_review`
- `list_sessions`
- `resources`
- `list_leases`
- `acquire_lease`
- `release_lease`
- `spawn_worker`
- `close_session`
- `close_worker`
- `show_handoff`
- `show_prompt`

When invoking these tools from a planner session, pass `repo_path` explicitly when you need deterministic repo targeting.

## Watching Sessions

When a worker is spawned, it gets its own terminal backend session and the spawn result includes an attach command. Today, with the `tmux` backend, the operator model is:

- one repo dashboard `tmux` session
- one dashboard window for the planner
- one dashboard window per active worker
- explicit attach commands if you want to jump straight to an individual planner or worker backend session

With the `desktop` backend, the operator model is:

- one native terminal window for the planner
- one native terminal window per active worker
- no repo dashboard session
- no interactive reattach support; the command output tells you which terminal process was launched

The simplest way back into the operator view is:

```bash
codex-planner
codex-planner dashboard
codex-planner attach
```

You can still jump into any running session directly:

```bash
codex-planner attach planner
codex-planner attach worker-task-003
```

If `attach` is called without a session name, it prefers the repo dashboard and falls back to the active planner session only if no dashboard exists.

With the `desktop` backend, `attach` prints the visibility hint for the existing native terminal window instead of trying to reattach.

## Task and Worker Lifecycle

Create a task explicitly in the shared board:

```bash
codex-planner create-task "Implement worker launcher" \
  --write-scope src/codex_orchestrator/orchestrator.py \
  --read-scope src/codex_orchestrator/board.py \
  --acceptance "Worker prompt is persisted"
```

Each task now gets a structured handoff file under `.codex/handoffs/`. If you do not provide a handoff path in `write_scope`, the tool creates one automatically and records it on the task as `handoff_file`.

Inspect the structured handoff that a worker will receive:

```bash
codex-planner show-handoff TASK-001
```

Or only print the resolved handoff file path:

```bash
codex-planner show-handoff TASK-001 --path-only
```

Inspect board state:

```bash
codex-planner list-tasks
codex-planner list-sessions --active-only
```

For machine-readable output:

```bash
codex-planner list-tasks --format yaml
codex-planner list-sessions --format json
```

Update a task when planning changes:

```bash
codex-planner update-task TASK-001 \
  --status blocked \
  --clear-owner \
  --acceptance "Waiting on design decision"
```

Mark a task ready for review:

```bash
codex-planner request-review TASK-001
```

If a worker needs a decision, clarification, or replanning instead of finishing immediately, mark the task as `needs_input` and append the question to the task handoff:

```bash
codex-planner request-input \
  --session-name worker-task-001 \
  --summary "Need direction on the migration strategy" \
  --detail "Option A preserves backward compatibility" \
  --detail "Option B is simpler but breaking" \
  --recommended-next-step "Ask the operator whether backward compatibility is required." \
  --close-session
```

That flow keeps the planner as the single user-facing session:

1. the worker records its blocker in `.codex/handoffs/<task>.md`
2. the task moves to `needs_input`
3. the planner can inspect `codex-planner list-tasks --status needs_input`
4. the planner reads `codex-planner show-handoff <TASK-ID>`
5. the planner decides whether it can answer from repo context or needs to ask the operator
6. after the answer, the planner usually runs `codex-planner resume-task <TASK-ID> --note "<resolution>"` to relaunch the worker, or explicitly cancels, splits, or re-scopes the work instead

When the same task should continue after the operator answers, use the explicit resume helper instead of a manual `update-task` plus `spawn-worker` sequence:

```bash
codex-planner resume-task TASK-001 \
  --note "Backward compatibility is required." \
  --note "Keep the old CLI spelling as an alias."
```

By default, `resume-task` reuses the most recent worker session name recorded for that task when one exists, so the planner can continue the same worker thread after `needs_input`.

Spawn a worker for a task:

```bash
codex-planner spawn-worker TASK-001
```

This flow:

1. validates the task exists
2. checks the current host resource snapshot and defers worker launch if CPU or memory pressure is already at the configured worker-launch limit
3. creates or reuses an isolated worktree
4. ensures the task has a structured handoff file and injects its content into the worker prompt
5. launches a terminal session through the configured backend
6. marks the task `in_progress`
7. registers the worker in `.codex/board/sessions.yaml`

When worker launch is blocked, `codex-planner spawn-worker ...` fails fast instead of opening the worker anyway. Use `codex-planner resources` to inspect both the heavy-work thresholds and the worker-launch thresholds, then wait until `Worker launch: allowed` returns before retrying.

Workers should not talk directly to the operator. If a worker gets blocked on a decision, it should use `request-input` and the handoff file so the planner can triage the question and stay as the only session that asks the user for guidance.

Before a worker starts an expensive command such as a large test suite, build, dependency install, or long-running linter, acquire a temporary heavy-work lease from the host-global machine budget:

```bash
codex-planner acquire-lease --session-name worker-task-001 --purpose pytest
```

If the lease is granted, the worker can run the expensive command. If the lease is denied, the worker is now placed into a host-global FIFO wait queue for heavy work and the command reports `queue_position` plus `retry_after_seconds`. The worker should continue with light work when possible and retry later instead of running the heavy command anyway.

Inspect the current admission state, queue depth, and active heavy-work leases across the machine:

```bash
codex-planner resources
codex-planner list-leases
```

Release the lease after the expensive command completes:

```bash
codex-planner release-lease HEAVY-1234abcd
```

Close a worker in the board when it finishes or hands off:

```bash
codex-planner close-worker worker-task-001
```

If you need to mark the worker closed but intentionally leave its terminal backend session alive:

```bash
codex-planner close-worker worker-task-001 --keep-terminal-running
```

`spawn-worker` and the default close flow both depend on the configured terminal backend being available. With the default backend, that means either a supported desktop terminal environment or `tmux`.

Close any session generically, including `planner`:

```bash
codex-planner close-session planner
```

For worker sessions, `close-session` can also carry a task transition. If needed, `--keep-terminal-running` is available here too:

```bash
codex-planner close-session worker-task-001 --task-status review_ready
```

If you want to close every active planner and worker session for the repository in one step, and tear down the dashboard too:

```bash
codex-planner shutdown
```

If you want to stop the whole orchestration but keep it resumable later:

```bash
codex-planner suspend
```

`Ctrl+C` now triggers that suspend flow from the dashboard, the planner, or any worker window. The next `codex-planner` run will try to resume the suspended planner first and then any suspended workers.

Inside an attached planner or worker terminal, typing `exit` closes only that session cleanly. If you are attached to the tmux dashboard and only want to leave the view while keeping sessions running, use `Ctrl-b d`.

Inspect the persisted prompt sent to a session:

```bash
codex-planner show-prompt worker-task-001
```

Or only print the prompt file path:

```bash
codex-planner show-prompt worker-task-001 --path-only
```

## Worktree Strategy

Worker worktrees are managed by the package, not by ad hoc shell snippets.

Default layout:

- main repo stays where it is
- worker worktrees default to a sibling directory named `<repo>-worktrees/`

This can be overridden globally with `worktrees_base_dir`.

## Development

Install editable mode with dev dependencies:

```bash
python3 -m pip install -e '.[dev]'
```

Run tests:

```bash
python3 -m pytest
```

Current automated coverage includes:

- board bootstrap and YAML persistence
- global config loading and env overrides
- orchestration flows for task creation, worker spawn, and worker close
- orchestration flows for task listing, update, review handoff, session listing, and prompt inspection
- planner tool wrapper flows and MCP server tool registration
- resource snapshot plus heavy-work lease acquisition/release flows
- host-global heavy-work lease registry behavior across repositories
- real `git worktree` creation

## Constraints of the Current MVP

- `desktop` currently supports `gnome-terminal` and `xterm` only
- the `desktop` backend opens real windows but does not support dashboard mode or interactive reattach
- planner-driven automatic plugin adoption is not implemented yet
- prompt inspection only works after a session has been created and persisted in the board
- no web UI or SDK-heavy orchestration has been added
