Metadata-Version: 2.4
Name: litectrl
Version: 0.2.0
Summary: A small deterministic local controller for OpenAI Codex
License-Expression: Apache-2.0
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# LiteCtrl

LiteCtrl is a small deterministic local controller for OpenAI Codex.

> **Status:** community project. LiteCtrl is not an OpenAI product and is not
> affiliated with or endorsed by OpenAI.

Its design goal is deliberately narrow:

> Humans choose the work. Codex does the work. LiteCtrl controls the run.

LiteCtrl does not discover backlog tasks, run a manager model, create reviewer
chains, or let subagents orchestrate one another. A human supplies one bounded
TaskSpec. LiteCtrl creates an isolated Git worktree, starts one fresh Codex
thread, audits the resulting file scope, runs deterministic verification outside
the model loop, and returns `READY` or `STOPPED`.

## How to use

### 1. Install LiteCtrl

```bash
python3 -m pip install litectrl
```

You also need Git and an authenticated local `codex` CLI. LiteCtrl v0.2.0 was
tested with `codex-cli 0.154.0`. The v0.1.0 file-based CLI remains supported.

### 2. Create a managed task

From the Git repository you want Codex to work on, run:

```bash
litectrl task create
```

LiteCtrl prompts for the task ID, goal, write scope, context files,
verification commands, model, and reasoning effort. It automatically uses the
repository's current exact `HEAD` as `base_sha` unless you provide another exact
commit.

Managed TaskSpecs are stored outside the repository under
`~/.litectrl/tasks/`, grouped by repository. They do not add task files to your
project or Git status.

You can also create a task non-interactively:

```bash
litectrl task create readme-edit \
  --goal "Improve one unclear sentence in README.md without changing its meaning." \
  --write-path README.md \
  --context-path README.md \
  --verify-json '["git","diff","--check"]' \
  --model gpt-5.6-sol \
  --effort high \
  --token-budget 50000
```

### 3. Review and validate the task

```bash
litectrl task list
litectrl task show readme-edit
litectrl task validate readme-edit
litectrl task models
```

`task list` shows the base commit, model, token budget, and durable run status.
`task show` prints the full TaskSpec plus the last persisted run evidence when
available. `task validate` checks the TaskSpec, exact base commit, and bounded
context files without starting a model turn. Live model/effort availability is
still checked by Codex when the task is run. To check the live model/effort and
quota signals without starting a model turn, use:

```bash
litectrl task validate readme-edit --runtime
```

`task models` lists the current model IDs and supported reasoning efforts
reported by the local Codex runtime, so TaskSpecs do not need a hard-coded model
allowlist.

To edit a saved task with your configured editor:

```bash
export EDITOR=vim   # or your preferred editor
litectrl task edit readme-edit
```

### 4. Run the managed task

```bash
litectrl run readme-edit
```

LiteCtrl will:

1. create an isolated worktree at the exact `base_sha`;
2. check Codex quota before starting a model turn;
3. start one fresh Codex thread with the bounded task and context;
4. watch the token budget and audit changed paths; and
5. run the declared verification commands outside the model loop.

### 5. Check the result

The CLI prints a JSON result and exits with `0` for `READY` or non-zero for
`STOPPED`. An abridged successful result looks like this:

```json
{
  "state": "READY",
  "failure": null,
  "workspace": "/.../.litectrl/workspaces/readme-edit-01234567",
  "changed_paths": ["README.md"]
}
```

`READY` means the bounded change completed, stayed inside `write_paths`, and
passed deterministic verification. The changes remain in the isolated worktree
shown in `workspace`: LiteCtrl does **not** automatically commit, push, open a
pull request, merge, release, or deploy them.

`STOPPED` means LiteCtrl deliberately stopped the run. Inspect the `failure`,
`detail`, changed paths, token usage, and verification evidence in the JSON result
before deciding what to do next.

The original file-based interface is still available when direct JSON TaskSpecs
fit your workflow better:

```bash
litectrl --task /absolute/path/to/task.json --repo /absolute/path/to/repository
```

## How it works

```mermaid
flowchart TD
    H["Human chooses one bounded TaskSpec"] --> L["LiteCtrl controller"]
    L --> W["Prepare exact-SHA Git worktree"]
    L -.-> D["Durable SQLite state: checkpoint / resume"]
    W --> Q{"Codex quota below threshold?"}

    Q -- No --> QS["STOPPED: quota guard"]
    Q -- Yes --> C["Start one fresh ephemeral Codex thread"]
    C --> E["Codex edits the isolated workspace"]
    E --> B{"Token budget exceeded?"}

    B -- Yes --> I["Interrupt the turn"]
    I --> BA["Audit changed paths"]
    BA --> BS{"Inside write_paths?"}
    BS -- No --> SV["STOPPED: SCOPE_VIOLATION"]
    BS -- Yes --> BE["STOPPED: BUDGET_EXCEEDED"]

    B -- No --> CC["Codex turn completes"]
    CC --> A["Audit changed paths"]
    A --> S{"Inside write_paths?"}
    S -- No --> SV
    S -- Yes --> V["Run verify commands outside the model loop"]
    V --> P{"Verification passes?"}
    P -- No --> VF["STOPPED: verification failure"]
    P -- Yes --> R["READY"]

    QS --> O["Human decides what happens next"]
    SV --> O
    BE --> O
    VF --> O
    R --> O
```

The model is used only for the bounded Codex execution. LiteCtrl keeps the
control path outside the model loop:

- **Human authority:** a person chooses the task, exact base SHA, allowed write
  paths, verification commands, model, and limits.
- **One model run:** one TaskSpec starts one fresh ephemeral Codex thread; there
  is no manager/reviewer loop or subagent orchestration by default.
- **Deterministic gates:** quota admission, write-scope auditing, verification,
  and crash/resume decisions are handled by local Python, Git, and SQLite logic.
- **Explicit result:** LiteCtrl ends in `READY` or `STOPPED`; it does not merge,
  release, deploy, or choose the next task automatically.

## LiteCtrl vs. orchestration-heavy controllers

LiteCtrl deliberately moves control decisions out of the model loop. The table
below compares that approach with two common patterns. "Typical orchestration"
means a capable root model that may delegate bounded work; "high-autonomy
controller" means a broader system that may discover, route, repair, review, and
continue work with less human involvement. Exact implementations vary.

| Comparison axis | LiteCtrl | Typical orchestration | High-autonomy / traditional controller |
| --- | --- | --- | --- |
| **1. Who chooses the work?** | **Human.** One explicit TaskSpec defines the bounded task before Codex starts. | Usually **human + root model**. The human gives an outcome; the root may decompose it, choose files, and decide whether to delegate. | Often **goal + controller**. The controller may discover candidates, rank/admit work, and select the next executable task. |
| **2. Root / worker topology** | **No manager-model layer by default.** One fresh ephemeral Codex thread performs the implementation; local Python controls the run. | Usually a **root orchestrator** plus optional explorer, implementation worker, or reviewer. Small tasks may stay root-solo. | Often a **multi-stage control plane**: discovery/admission, provider routing, writer, reviewer, repair, PR/CI, and sometimes merge/next-task stages. |
| **3. Model round trips** | Designed for **one bounded implementation turn** per TaskSpec. No automatic reviewer, repair, discovery, or manager loop. | Can require **multiple model turns** for decomposition, delegation, worker handoff, integration, review, and repair when those routes are used. | Can require the **most model activity**, because discovery, retries, repairs, reviews, provider fallbacks, and continuation may each add model work. |
| **4. Where is verification decided and run?** | **Outside the model loop.** LiteCtrl runs declared argv-based verification locally and deterministically audits scope and verification-time mutations. | Verification is commonly **owned by the root agent**, often using deterministic test scripts but with the model deciding what to run, interpreting evidence, and choosing follow-up actions. | Verification may be deterministic, but it is usually embedded in a **larger autonomous state machine** that can trigger repair, re-review, PR/CI handling, or further execution. |
| **5. Failure amplification** | **Fail closed and stop.** Quota, token-budget, scope, uncertain-run, or verification failures produce `STOPPED`; LiteCtrl does not silently start another model turn. | **Moderate and policy-dependent.** A worker failure or review finding may cause another root/worker/reviewer turn, but bounded orchestration can keep this limited. | **Highest potential amplification.** Discovery, provider, permission, repair, review, branch/CI, merge, and continuation failures can cascade across more controller states and retries. |

The trade-off is intentional: LiteCtrl gives up autonomy in exchange for a
smaller control plane, fewer model round trips, fewer failure points, and easier
post-run verification. If the task itself still needs product, architecture, or
high-level reasoning, that reasoning should happen before the TaskSpec is handed
to LiteCtrl.

## Features and roadmap

### Available now

- [x] **Managed TaskSpec CLI** — create, list, show, edit,
  validate, inspect live models, and run repository-scoped tasks without keeping
  TaskSpec files in the target repository.
- [x] **TaskSpec v1** — one explicit JSON task defines the goal, exact base SHA,
  write scope, context, verification commands, model, effort, and limits.
- [x] **Exact-SHA isolated worktrees** — work runs outside the source checkout
  without silently moving the requested base revision.
- [x] **Single-agent Codex execution** — one TaskSpec starts one fresh ephemeral
  Codex App Server thread with multi-agent delegation disabled.
- [x] **Runtime model and effort discovery** — supported choices come from the
  live Codex `model/list` response instead of a hard-coded model allowlist.
- [x] **Bounded `context_paths` injection** — a small set of relevant files can
  be supplied up front to reduce exploratory read/model round trips.
- [x] **Quota admission** — LiteCtrl checks the primary Codex usage signal before
  starting the model turn and can stop before consuming more quota.
- [x] **Mid-turn token guard** — cumulative token-usage events can interrupt a
  turn after the configured `token_budget` is exceeded.
- [x] **Post-run write-scope audit** — changes outside `write_paths` stop the run
  as a scope violation.
- [x] **Deterministic external verification** — argv-based verification runs
  outside the model loop, with verification-time repository mutation detection.
- [x] **Durable crash/resume state** — SQLite checkpoints let safe phases resume
  without repeating a possibly already-running model turn.
- [x] **Machine-readable results** — the CLI emits the final `READY` / `STOPPED`
  result and evidence as JSON.
- [x] **Durable task status** — `task list` and `task show` surface persisted run
  state and evidence without rerunning Codex.
- [x] **PyPI package and CI** — `pip install litectrl`, Python 3.11-3.14 CI, and
  OIDC Trusted Publishing are live for v0.1.0.

### Planned next
- [ ] **TaskSpec schema command** — expose a machine-readable schema/template so
  editors and other tools can generate and validate TaskSpec v1 more reliably.
- [ ] **Controlled token benchmark harness** — run repeatable same-task A/B
  measurements so token/time savings can be reported with comparable evidence
  instead of cross-task anecdotes.
- [ ] **PEP 639 license metadata** — replace the legacy setuptools license-file
  declaration in the next package release without rewriting the v0.1.0 tag.

The roadmap intentionally does **not** include autonomous backlog discovery,
manager/reviewer model loops, subagent orchestration, or automatic merge/release/
deployment as default behavior. Adding those would reintroduce the token and
failure amplification that LiteCtrl is designed to remove.

## Token efficiency

LiteCtrl is designed to reduce **orchestration overhead** around Codex. It does
not make the underlying model intrinsically cheaper for the same implementation
work. The savings come from avoiding repeated model turns, manager/reviewer
loops, model-driven polling, and unnecessary context rediscovery.

### Measured v0.1.0 release canary

One disposable clean-clone canary using Sol High completed successfully with:

| Metric | Measured value |
| --- | ---: |
| Total tokens | **20,486** |
| Input tokens | 20,360 |
| Cached input tokens | 18,816 |
| Output tokens | 126 |
| Reasoning output tokens | 0 |
| Codex turns | **1** |
| Model-side command executions | **0** |
| File changes | 1 |
| Codex elapsed time | ~17 s |
| Full controller elapsed time | ~18 s |

For historical context, an earlier BEFTR Sol development session observed before
LiteCtrl consumed **830,880 total tokens**. The LiteCtrl release canary is
numerically about **97.5% lower** in total-token usage, or about **40.6x smaller**.

> **This is not an apples-to-apples benchmark.** The two runs performed different
> tasks, so LiteCtrl does **not** claim a general 97.5% token reduction. A valid
> percentage requires running the same task, model, effort, repository state, and
> acceptance criteria through both controllers.

The expected savings depend on the baseline workflow:

- Against a workflow with manager, reviewer, retry, polling, or discovery model
  turns, LiteCtrl can remove most of that repeated orchestration context.
- Against an already-direct single Codex turn with little surrounding automation,
  token savings may be modest because there is less orchestration overhead to
  remove.
- `context_paths` can reduce exploratory reads by supplying a small bounded set
  of relevant files up front, while deterministic verification avoids spending
  model tokens on test-running and pass/fail decisions.
- `token_budget` and quota admission bound failure amplification: LiteCtrl stops
  rather than silently starting additional model turns to repair, review, or
  continue the task.

The project will only promote a general percentage reduction after a controlled
same-task A/B benchmark is available.

## Requirements

- Python 3.11+
- Git
- a local `codex` CLI with stable App Server v2 support
- an authenticated Codex account/session usable by that CLI

The current implementation uses only the Python standard library. It does not
depend on a Python SDK, an external orchestrator, MCP, or another coding agent.

### Codex compatibility for v0.2.0

`codex-cli 0.154.0` is the tested baseline for LiteCtrl v0.2.0. Older Codex CLI
versions are not supported by this release. Newer versions are expected to work
when they retain the stable App Server v2 protocol used by LiteCtrl, but they are
best-effort until explicitly tested.

LiteCtrl uses the stable App Server surface only and does not opt in to
`experimentalApi`. The current integration depends on stable initialization,
runtime model discovery, account rate-limit reads, ephemeral thread/turn
lifecycle, token-usage notifications, and turn interruption. LiteCtrl discovers
the live model catalog at runtime rather than keeping its own model allowlist.

## CLI details

The quick start above uses the console entrypoint:

```bash
litectrl \
  --task /absolute/path/to/task.json \
  --repo /absolute/path/to/repository \
  --workspace-root ~/.litectrl/workspaces
```

or the equivalent module entrypoint:

```bash
python3 -m litectrl \
  --task /absolute/path/to/task.json \
  --repo /absolute/path/to/repository \
  --workspace-root ~/.litectrl/workspaces
```

By default durable state is stored at `~/.litectrl/state.sqlite`. Override it
with `--state-path` when desired.

To install the current repository checkout instead of the PyPI release, run
`python3 -m pip install .`.

The default quota admission ceiling is 90% of the primary Codex usage window:

```bash
python3 -m litectrl \
  --task task.json \
  --max-quota-used-percent 80
```

## TaskSpec v1

TaskSpec is JSON and intentionally contains no automatic task discovery or
authority interpretation.

```json
{
  "version": 1,
  "task_id": "feed-pagination",
  "goal": "Add cursor pagination to the existing feed read path.",
  "base_sha": "0123456789abcdef0123456789abcdef01234567",
  "write_paths": [
    "lib/features/feed/**",
    "test/features/feed/**"
  ],
  "context_paths": [
    "lib/features/feed/feed_repository.dart",
    "test/features/feed/feed_repository_test.dart"
  ],
  "verify": [
    ["flutter", "test", "test/features/feed/feed_repository_test.dart"],
    ["flutter", "analyze"]
  ],
  "model": {
    "id": "gpt-5.6-sol",
    "effort": "high"
  },
  "limits": {
    "max_turns": 1,
    "max_runtime_minutes": 30,
    "max_repairs": 0,
    "token_budget": 50000
  }
}
```

### Important field semantics

`base_sha` must be one exact lowercase 40-character Git commit SHA already
available in the local repository. LiteCtrl does not fetch implicitly.

`write_paths` accepts exact repository-relative paths or a recursive prefix that
ends in `/**`. It is an audited change boundary: after Codex runs, any change
outside the declared paths stops the run. It is not presented as a read sandbox.

`context_paths` is optional. It accepts at most eight concrete UTF-8 files,
bounded to 32 KiB per file and 64 KiB total. Their content is supplied in the
initial prompt to avoid exploratory file-read turns. This is an efficiency hint,
not a security boundary restricting what Codex can read.

`verify` is an array of argv arrays, never shell command strings. LiteCtrl runs
these commands directly after Codex finishes. The model is explicitly told not
to run the verification commands itself.

Model IDs and reasoning effort strings are validated against the live Codex
`model/list` response at runtime.

## Execution model

For each new exact TaskSpec, LiteCtrl:

1. creates an exact-SHA Git worktree outside the source checkout;
2. verifies the source checkout was not changed by worktree creation;
3. checks the account rate-limit signal before starting a model turn;
4. starts a fresh ephemeral Codex App Server thread;
5. disables multi-agent delegation and unrelated plugin/browser/computer/MCP
   surfaces for the worker process;
6. watches cumulative token-usage notifications while the turn is active;
7. interrupts the turn when a usage update exceeds `token_budget`;
8. audits changed paths against `write_paths`;
9. runs deterministic verification outside Codex;
10. rejects verification that mutates repository content; and
11. persists terminal evidence as `READY` or `STOPPED`.

No commit, push, pull request, merge, release, or deployment is performed.

## Durable resume

SQLite stores a small run record and append-only event history. The durable
states are:

```text
CREATED
→ PREPARED
→ CODEX_RUNNING
→ CODEX_COMPLETE
→ VERIFY_RUNNING
→ READY / STOPPED
```

Resume behavior is intentionally conservative:

- `CREATED`: recover the deterministic worktree if it already exists.
- `PREPARED`: continue only if the workspace is still clean.
- `CODEX_RUNNING`: stop as `RUN_UNCERTAIN`; LiteCtrl will not risk a duplicate
  model turn after a controller/process crash.
- `CODEX_COMPLETE`: continue from scope audit and external verification without
  another model call.
- `VERIFY_RUNNING`: rerun verification only if the workspace fingerprint still
  matches the pre-verification fingerprint.
- terminal `READY` / `STOPPED`: return the stored result idempotently.

To deliberately start fresh work, use a materially new TaskSpec/task id rather
than silently reusing a terminal run.

## Token controls

LiteCtrl has three separate controls:

- **smaller prompt/tool surface** — unrelated Codex surfaces are disabled for
  the worker process;
- **bounded initial context** — selected files can be supplied up front to avoid
  read/tool/model round trips;
- **runtime guards** — account quota is checked before the turn, and cumulative
  token usage can interrupt an active turn.

The token budget is event-driven, not an exact meter. Codex can only be
interrupted after the next `thread/tokenUsage/updated` event arrives, so actual
usage can exceed the configured budget by one model/tool interval.

In one small local Sol High canary, the measured total went from 57,623 tokens in
the initial broad worker path to 30,839 after narrowing the worker surface, then
to 20,543 after supplying the two required context files up front. These are
single-task observations, not general performance guarantees.

## Approval boundary

The current worker starts with:

```text
approvalPolicy = never
approvalsReviewer = user
sandbox = workspace-write
```

This intentionally avoids the model-based auto-review path. LiteCtrl currently
does not implement a dynamic controller approval service; operations requiring
an unavailable escalation should fail rather than silently expand privileges.

## Non-goals for the current core

- autonomous backlog discovery or ranking;
- manager/reviewer model loops;
- subagent orchestration;
- automatic repair after an uncertain/interrupted model turn;
- automatic commit, push, PR, merge, release, or deployment;
- pretending `context_paths` is a physical read-security boundary.

Those exclusions are part of the lightweight design, not missing default
behavior.

## Security

Please do not report suspected vulnerabilities in a public issue. See
[`SECURITY.md`](SECURITY.md) for the private reporting path and supported-version
policy.

## License

Apache License 2.0. See [`LICENSE`](LICENSE).
