Metadata-Version: 2.5
Name: splay-router
Version: 0.17.0
Summary: Evidence-led local execution control plane for coding agents
Project-URL: Homepage, https://github.com/delvera-ai/splay
Project-URL: Documentation, https://github.com/delvera-ai/splay/tree/main/docs
Project-URL: Issues, https://github.com/delvera-ai/splay/issues
Project-URL: Changelog, https://github.com/delvera-ai/splay/blob/main/CHANGELOG.md
Author: Splay maintainers
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: coding-agents,execution,mcp,routing,splay
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: platformdirs>=4.2
Requires-Dist: pydantic>=2.7
Requires-Dist: rich>=13.7
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: hatchling>=1.25; extra == 'dev'
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pip-audit>=2.7; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.2; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == 'mcp'
Description-Content-Type: text/markdown

# Splay

Splay runs bounded coding tasks through an eligible local coding agent, isolates its changes, verifies the result, and retains the evidence.

## Install and connect

Install Codex and sign in with an eligible personal subscription, then:

```bash
pip install splay-router
splay setup --qualify
```

For this checkout, use `uv sync` followed by `uv run splay setup --qualify`.

Setup can register the MCP service in Codex, Cursor, or Claude Code, installs host-owned skill or instruction blocks, and checks the Splay MCP connection. `--qualify` authorizes one small, bounded included-subscription task with an independent verifier for the selected worker family (`codex`, `cursor`, or `claude`). Setup reports ready only when a selected worker has a verified qualification. Changed account, installation, version, or model bindings require qualification again. Credentials stay with the worker. Host activation and worker execution are independent: installing Splay into Cursor or Claude Code does not make that host the execution worker.

```bash
splay setup
  --host auto|codex|claude|cursor|agy|none
  --worker auto|all|codex|claude|cursor|agy|acp
  --qualify
  --json
  --human
  --quiet
```

`--host` defaults to `auto` and installs detected host integrations for Codex, Cursor, and Claude. `--host codex`, `--host cursor`, and `--host claude` still prepare that integration before the matching CLI is installed. `--host agy` is inventoried only; there is no Antigravity installer yet. `--host none` does not write host files. `--worker` defaults to `auto` and opens a qualified family when a matching fingerprint exists. If more than one family is qualified, Codex is preferred. A Cursor or Claude fingerprint is used when it is the only qualified family. `--worker all` inventories every candidate and may qualify Codex first. `--worker cursor` and `--worker claude` are qualification-capable and still require `--qualify`. `--worker agy` and `--worker acp` stop before installation or qualification. Key and token channels are never treated as included. `--ensure/--no-ensure`, `--home`, and `--state-dir` keep their previous meanings.

A terminal shows the readable summary. Redirected stdout stays JSON so scripts keep one parseable object. `--json` and `--human` override that detection and cannot be combined. Progress is printed on stderr; `--quiet` omits it and still prints the result. Invalid selectors and conflicting format flags exit 2 before setup writes files. `ready` means a selected execution profile is usable. Exit 0 is `ready` or `ready_with_skips`. Exit 1 is `partial` or `not_ready`.

This is the readable summary for a verified `--host codex` qualification when Claude and Cursor CLIs plus a configured ACP command are also present. `--host auto` also prints Cursor and Claude host-install and activation lines when those CLIs are detected:

```text
Splay setup

✓ Codex detected
✓ Claude detected
✓ Cursor detected
– Antigravity CLI (agy) was not found
· ACP command configured — diagnostics only, not a qualified route
✓ Codex host integration installed
✓ MCP connection checked — 6 required tools available
✓ Test file independently verified
✓ Qualified profile saved
✓ Codex worker eligible
✓ Worker closed

Setup complete — Codex ready
Model: gpt-test
Qualification duration: 24 seconds
Additional spend reported: $0.00

Restart existing Codex sessions to activate the integration.
Use /skills → Splay (or $splay).
```

While qualification is running, stderr shows `→ Running one verified qualification task.` before the task finishes. A failed verification stays partial, does not say the test file was verified, and leaves spend unknown when the worker did not report it. The `--host codex` integration and task handle remain:

```text
Splay setup

✓ Codex detected
✓ Claude detected
✓ Cursor detected
– Antigravity CLI (agy) was not found
· ACP command configured — diagnostics only, not a qualified route
✓ Codex host integration installed
✗ Qualification failed — Codex qualification did not finish with passed verification.

Setup incomplete
Model: gpt-test
Qualification duration: 3 seconds
Additional spend reported: unknown
Task handle: task-test

Codex qualification did not finish with passed verification.

Restart existing Codex sessions to activate the integration.
Use /skills → Splay (or $splay).
```

JSON output uses `setup_schema_version` 1. That version is the setup document, not the nested control-plane `schema_version`. Every object includes `setup_schema_version`, `state_dir`, `outcome`, `ready`, `inventory`, `steps`, `qualification_summary`, and `next_actions`. Existing keys remain, with the same value types, when they apply: `host`, `mcp`, `qualification`, `profile`, and `next_action`. `qualification_summary` records whether qualification was requested, performed, or reused, plus the verifier result, final profile state, duration, reported spend, model, and task handle. A historical bootstrap value of `unqualified-bootstrap` does not replace a passed verification. Unknown spend is `null`, not zero. `state_dir` is left usable. Display copies redact account emails, credential fields, secret-shaped tokens, and secret-bearing ACP arguments. That is structured sanitization, not a claim that arbitrary prose is perfectly redacted. Stored execution evidence is not rewritten, and normal human output does not dump worker transcripts.

Upgrade an installed copy in place:

```bash
splay update
```

The command updates `splay-router` in the Python environment that owns the running `splay` command. It supports normal pip installs, pipx environments with pip, uv tool installs, and other uv-managed environments. For uv tools, it retains the owning tool and executable directories and replaces an old version pin; for other uv environments, it targets the exact running interpreter. Editable installs and source checkouts are refused so a development tree is never replaced unexpectedly. Updating leaves Splay configuration, task history, workspaces, and Codex integration files in place. Installer errors are shown and their nonzero status is returned. Restart active Codex sessions after an update.

Restart existing Codex sessions after setup. Ordinary bounded implementation, fix, and review requests should use Splay automatically. You can also choose **Splay through `/skills`**, or type **`$splay`**. You do not need to remember MCP tool names. Activation is mediated by the host; it is not a guarantee that every model response invokes Splay. Live workers are qualified Codex, Cursor ACP (`cursor-agent acp`), and Claude print (`claude -p`). Cursor host MCP is not the Cursor worker. Agy stays detected-only.

The installer enables automatic calls only for the six bounded task tools: delegate, review, status, explain, cancel, and apply. Other tools retain prompt approval. No tool can enable paid fallback, raise server ceilings, or bootstrap qualification. Normal implementation requests authorize the host to apply a verified result through the apply tool, which checks the original repository and exact candidate; reviews never promote.

## Use from the terminal

From a clean Git repository:

```bash
splay run "Fix the failing parser test" --repo . --verify "python -m pytest tests/test_parser.py"
splay explain task-...
splay apply task-...
```

Use your project's actual verification command. Worker completion alone is not success. A passing candidate stays in its worktree until applied; promotion checks the exact verified tree and refuses a changed or dirty canonical repository. It never runs blanket `git reset --hard` or `git clean`.

```bash
splay status
splay profiles
splay doctor
splay policy
splay configure --help
splay update
splay task cancel task-...
splay uninstall --yes
```

Uninstall disconnects the owned host integration and preserves history. `--purge` is a separate operation that refuses active work, active workspaces, a running daemon, or unowned files. Modified user configuration is preserved. `--home` and `--state-dir` support isolated setup testing.

## Supported execution and current limits

The supported live path is **SINGLE execution** through a qualified included personal subscription on Codex, Cursor ACP, or Claude print, with bounded resources, isolated worktrees, independent verification, durable results, and explicit safe promotion. Codex and Cursor ACP support cancellation and owned-process restart. Claude print is one-shot and does not expose process identity. `auto` uses the only qualified family, or Codex when more than one is qualified. Unknown or paid channels block by default. MCP starts a local daemon on demand; work survives the submitting MCP client's exit.

Splay currently provides local, terms-aware verified execution control for
bounded coding-agent work. Dynamic selection among execution profiles is a
strategic hypothesis (H-R), not a qualified claim. The production route is
still hard FILTER, then the existing deterministic fallback, then SINGLE
execution. No learned or adaptive router is enabled.

The qualified behavior baseline remains
[Splay Technical Specification v0.3](Splay_Technical_Specification_v0.3.md)
at accepted implementation `11f580a5`. The
[v0.4-draft-review2 pack](docs/spec/Splay_Specification_Pack_v0.4-draft-review2/00_README.md)
is a proposed specification. It is not a release authorization. The first
implementation tranche is recorded in
[docs/review2/IMPLEMENTATION_LOG.md](docs/review2/IMPLEMENTATION_LOG.md).

The [v0.2 draft PDF](Splay_Technical_Specification_v0.2-draft.pdf) is historical.
Remaining gaps include quality-calibrated multi-model routing, automatic
production handoff, project-specific policy overlays, a first-party Agy
worker, and the draft's newer MCP Tasks extension. Live `auto` already
persists a `RouteDecision`. One-stage ESCALATE and canonical ContextPack
handoff are experimental explicit surfaces, not defaults. Generic `--worker acp` remains diagnostic. Hard no-network
verification requests block when no qualified isolation backend can enforce
them. Portable verification commands run locally with a filtered environment;
they are not an OS sandbox for hostile repositories. A same-user worker may
still have OS authority outside Splay unless a stronger sandbox exists.

MCP uses supported revision negotiation and durable Splay task handles rather than claiming Tasks-extension certification. Synthetic evaluations and one small live qualification do not establish general coding quality or optimal routing. See the [original audit](docs/audits/2026-09-21-spec-review.md) and [remediation evidence](docs/audits/2026-09-21-remediation.md). The v0.3 alignment remediation is complete at `11f580a5`. Next work is the [qualification and empirical roadmap](docs/plans/qualification_and_empirical_roadmap.md), not another remediation cycle. Historical phase documents describe component milestones and are not current product certification. The `0.17.0` package version is an unpublished candidate.

## Development and acceptance

Build release artifacts with `make build`, publish them using `UV_PUBLISH_TOKEN`
from `.env` with `make publish`, or do both with `make release`. See
[build and publish instructions](CONTRIBUTING.md#build-and-publish).

```bash
uv sync
uv run pytest
uv run ruff check src tests scripts
uv run ruff format --check src tests scripts
uv run mypy
```

An opt-in live acceptance test creates a disposable repository, delegates through MCP, verifies, promotes, restarts the daemon, and checks durable results:

```bash
uv run python scripts/live_acceptance.py --live --state-dir /path/to/qualified/state
uv run python scripts/host_acceptance.py --live --state-dir /path/to/qualified/state
```

Research commands are explicitly diagnostic: `splay route plan --diagnostic --prompt "..."`, `splay profile probe` (stub by default), `splay eval routing`, and `splay experiment`. `splay experiment review run --live` produces immutable review evidence. `splay experiment review qualify` is the only path that can persist `READ_ONLY_REVIEW` QUALIFIED, and only from control-plane-stamped live evidence. No live profile has earned it yet. `splay experiment corpus run --live` can record isolated task×profile cells without changing production routing. They do not change production routing from offline scores.

Apache-2.0 — see [LICENSE](LICENSE).
