Skip to main content

poly-harness-dispatcher (PHD)

CI PyPI Python License

Spawn headless AI coding agents (Claude Code claude -p, Codex codex exec, OpenCode opencode run) from one harness-neutral spec, and get back one normalized result.

You describe the agent once as a stack (identity, skills, MCP servers, hooks in a config/ directory) and the run as a spec (harness, model, working directory, credentials, options). PHD builds an isolated config home per run, launches the CLI, parses its stream into events and a RunResult, and records everything under ~/.phd/runs/<run_id>/.

Status: layer 1 (the core spawner) is built. It runs agents on the host with no sandbox; sandboxing, an API and other components are planned (architecture).

Install

Python 3.12+; the harness CLIs you use must be on PATH.

pip install poly-harness-dispatcher    # import name: phd

From a clone (development, with uv):

uv sync --extra dev        # or: uv venv && uv pip install -e ".[dev]"
uv run pytest -q           # offline test suite

Quickstart

from phd import Credentials, Dispatcher, Inputs, Spec, Stack

spec = Spec(
    harness="claude",                          # or "codex", "opencode"
    model="haiku",
    stack=Stack.load("tests/fixtures/stack"),  # the bundled test stack
    cwd="path/to/repo",
    credentials=Credentials.from_host("claude"),
    secrets={"ECHO_PREFIX": "phd-echo"},       # fills ${env:ECHO_PREFIX} in the stack
)
d = Dispatcher(spec)
result = d.spawn(Inputs(msg="List the names of your skills."))
print(result.status, result.cost_usd, result.result_text)
followup = d.spawn(Inputs(msg="Which one has a scripts/ folder?"), session_id=result.session_id)

To compose a stack from several sources (a base stack plus extra skills, MCP servers or hooks, local or https://) and keep it in a local store, use phd.stacks:

import phd.stacks as stacks

stack = stacks.resolve(stacks.compose("reviewer", "1.0.0", base="tests/fixtures/stack",
                                      skills=["path/to/extra-skill"]))
spec = Spec(harness="claude", model="haiku", stack=stack, cwd="path/to/repo",
            credentials=Credentials.from_host("claude"))

In async code, d.run(...) ties the run to a block: leaving it cancels a run that has not finished, and a harness whose caller dies is killed too (Windows Job Object, POSIX reaper).

async with d.run(Inputs(msg="List the names of your skills.")) as handle:
    async for ev in handle.events():
        print(ev.type)                  # run.started, session.started, message, ..., run.finished
    result = await handle.wait()

session_id= continues that harness session (the home is re-materialized from the current spec). spawn() blocks; in Jupyter or async code use await d.start(inputs), then async for ev in handle.events() and await handle.wait() (see examples/quickstart.ipynb). A failed run does not raise: check result.status and result.error. Problems detectable before launch raise a PhdError.

On macOS the Claude login lives in the Keychain: use Credentials.claude_oauth_token(token) with a token from claude setup-token instead of from_host("claude").

Documentation

Build the docs site locally: uv sync --all-extras && uv run mkdocs serve.

Metadata

Release files for poly-harness-dispatcher 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for poly-harness-dispatcher 0.1.1
File Size Uploaded
poly_harness_dispatcher-0.1.1.tar.gz 354.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for poly-harness-dispatcher 0.1.1
File Interpreter ABI Platform
poly_harness_dispatcher-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 481.9 kB

Release files / poly_harness_dispatcher-0.1.1.tar.gz

Download URL poly_harness_dispatcher-0.1.1.tar.gz
Size 354.7 kB
Tags Source
SHA-256 checksum
How to use checksums
76b5f781bbda11023352b2315175c2337fb7324847dc67413fddb72ddab7b21f
BLAKE2b-256 checksum
How to use checksums
69486a6b7a5a3928dad6938a22ee6b07706c688b46a5843c172f2f6af2ac6415
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / poly_harness_dispatcher-0.1.1-py3-none-any.whl

Download URL poly_harness_dispatcher-0.1.1-py3-none-any.whl
Size 127.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
114663e47631464dbd3c45ef21196b01ff71877bc982718bf74b7d29b43529e7
BLAKE2b-256 checksum
How to use checksums
38fa4cd999bd1487ae900d45f0741b281a61f542d8670ba4652431d7db7dec58
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page