Skip to main content

A provider-neutral harness SDK for agent systems on Claude and Codex.

Project description

Yoke

yoke (yōk), n. A harness that joins two, that they may pull as one. [akin to Skr. yoga, union.]

Python 3.11+ Typed Claude harness Codex harness License: Apache-2.0

A Python SDK for building agents on Claude Code and Codex.

Claude Code and Codex have become general-purpose agents: give them instructions, skills, and subagents, and they can be shaped to any task. Yoke lets you reuse them from code — one Harness that drives both.

Quickstart · How it compares · Sessions · Skills · Subagents · Workflows · Goals · Surfaces · CLI

Quickstart

pip install almanac-yoke

Install a provider extra when you want Yoke to manage that SDK directly:

pip install 'almanac-yoke[claude]'  # or [codex], or [all]

Define an agent, pick a harness, run:

from pathlib import Path

from yoke import Agent, Goal, Harness

agent = Agent(
    instructions="You are a careful maintainer. Make small, safe changes.",
    goal=Goal("Finish the requested implementation safely."),
)
harness = Harness("codex", agent=agent, cwd=Path.cwd())

result = await harness.run("Implement the bundle loader.")
print(result.output)

Swap "codex" for "claude" and the same agent runs there. Your existing Claude Code or ChatGPT login is all it needs — no API keys.

Embedding applications can observe a one-shot run while it is happening:

from yoke import RunOptions

seen = []
result = await harness.run(
    "Implement the bundle loader.",
    RunOptions(on_event=seen.append),
)

assert tuple(seen) == result.events

on_event is a synchronous callback receiving each normalized Event once. It is runtime-only—it is excluded from serialized options and agent folders. Live callback delivery is supported by the Claude Python SDK and Codex app-server surfaces. Passing on_event selects one of those surfaces when the surface is automatic, and raises UnsupportedFeature when an explicitly selected surface cannot deliver callbacks. Use harness.stream(...) for a portable event iterator.

How it compares

The question that places Yoke: who runs the agent?

The agent runs in Yoke
Claude Agent SDK · Codex SDK the lab's harness — one provider each builds on them. They are the surfaces Yoke drives; one definition runs on both.
Pydantic AI · LangChain your process — a loop you assemble over model APIs starts from a different premise: the harness already is the agent, so there is no loop to assemble.
Eve Eve's own durable runtime, deployed on Vercel is closest in spirit — an agent is a directory — but compiles that directory onto Claude and Codex instead of shipping a runtime.

Sessions

session = await harness.start()

plan = await session.run("Draft the migration plan.")
step = await session.run("Apply step one.")

await session.close()

State lives with the provider; Yoke holds the handle. Sessions are native on every surface except the Codex CLI, where they work by resuming threads.

Skills

from yoke import Skill

agent = Agent(
    instructions="You are a careful maintainer.",
    skills=(Skill(path=Path("skills/source-grounding")),),
)

A skill is a folder with a SKILL.md. Claude loads skills natively, the Codex app-server mounts them as native skill roots, and other surfaces get them compiled to files.

Subagents

agent = Agent(
    instructions="You are a careful maintainer.",
    subagents={
        "reviewer": Agent(
            description="Find correctness and architecture risks.",
            instructions="Review concretely. Prefer file and line evidence.",
        ),
    },
)

A subagent is just another Agent. Claude runs declared subagents through its native Agent tool. Codex app-server compiles the declaration into explicit guidance to use native spawn_agent, including requested model overrides, and normalizes collaboration events when the parent follows that guidance. This is model-driven orchestration, not deterministic tool enforcement. Codex SDK/CLI surfaces use clearly labeled compiled instructions or provider files.

Workflows

from yoke import Step, Workflow, WorkflowOptions

workflow = Workflow(
    name="review",
    steps=(
        Step(name="draft", agent="main", prompt="Draft release notes."),
        Step(
            name="review",
            agent="reviewer",
            depends_on=("draft",),
            prompt="Review this draft: {draft}",
        ),
    ),
)

result = await harness.workflow(
    workflow,
    options=WorkflowOptions(timeout_seconds=120, step_timeout_seconds=60),
)

A workflow is a small dependency graph over the agent and its subagents; main is the reserved name for the root agent, and WorkflowOptions bounds the run. Neither provider has a native equivalent yet, so workflows are portable Yoke constructs — they run the same on every surface.

Goals

from yoke import Goal

session = await session.set_goal(Goal("Land the bundle loader.", token_budget=200_000))
print(await session.get_goal())

A goal is intent that outlives a single prompt. On the Codex app-server it is real thread state — readable, replaceable, clearable. Everywhere else it compiles into the provider loop, and explain() tells you which you got.

No pretending

Claude and Codex expose different primitives, and Yoke does not flatten them into a weak common denominator. The capability map is part of the API:

for row in harness.explain().reports:
    print(row.feature, row.support, row.lowering)  # native, compiled, emulated, unsupported
Feature Claude SDK Codex app-server Codex SDK Codex CLI
Sessions native native native resume-based
Streaming native native native transport JSONL/process
Skills native native skill roots compiled files/compiled
Subagents native compiled → native tool compiled files/compiled
Goals provider loop native state compiled context provider loop
Workflows portable Yoke portable Yoke portable Yoke portable/limited
Permissions/hooks native callbacks native request events sandbox/approval flags/config

Agents are folders

Everything defined in Python can be saved as files, edited by hand, and loaded back:

agent.save("agent")
agent = Agent.from_folder("agent")
agent/
  agent.yaml
  instructions.md
  skills/
    source-grounding/SKILL.md
  subagents/
    reviewer/
  workflows/
    ship/

Provider files like .claude/ and .codex/ are compiled from this source, only when you ask:

agent.bundle(provider="codex", surface="codex_cli").write(Path.cwd())

Surfaces

This is the deeper layer:

agent definition -> provider surface -> real harness

Each provider ships more than one way in. Harness("codex") picks the strongest one for you (the app-server); address a surface directly when you require an exact one:

Surface What it is
codex:app Codex app-server — sessions, native goals, skill roots
codex:sdk Codex Python SDK
codex:cli Codex CLI — codex exec, resumable threads
claude:sdk Claude Agent SDK for Python

discover reports what this machine already has — surfaces installed, logins ready, models available — and picks the first ready surface satisfying the requested features:

from yoke import Feature, discover

found = await discover("codex", Path.cwd(), agent)  # reuses your local login

for surface in found.surfaces:
    print(surface.surface, [model.id for model in surface.models])

harness = found.harness(Feature.STREAMING)

Claude also accepts runtime-only Credentials (redacted, never serialized); Codex logins persist provider state, so they go through an explicit await harness.login(...).

CLI

The same agents and folders, from the shell:

yoke run agents codealmanac "Review this repo"
yoke explain agents codealmanac
yoke status agents codealmanac
yoke install agents codealmanac --provider codex:cli
yoke runs

CLI runs leave inspectable snapshots under .yoke/runs/. SDK users can persist returned results explicitly with RunStore.at(".yoke/runs").record(result).

Status

Yoke is an early alpha. Everything shown above is built and smoke-tested against live providers. The API may still change before 1.0; durable workflow execution and typed coverage of every provider-specific option remain future work.

Apache-2.0. See LICENSE.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

almanac_yoke-0.1.5.tar.gz (113.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

almanac_yoke-0.1.5-py3-none-any.whl (132.5 kB view details)

Uploaded Python 3

File details

Details for the file almanac_yoke-0.1.5.tar.gz.

File metadata

  • Download URL: almanac_yoke-0.1.5.tar.gz
  • Upload date:
  • Size: 113.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for almanac_yoke-0.1.5.tar.gz
Algorithm Hash digest
SHA256 59c2850edc0e962fb10d009445c1373b270aac546deb88c6fddb984277f52d01
MD5 088cfc344a442e2d34d49790c85589d9
BLAKE2b-256 e601ee1cdfb120e4e9564a2dcc0b8d66e3ba95fd30590e9b448af8713e436246

See more details on using hashes here.

Provenance

The following attestation bundles were made for almanac_yoke-0.1.5.tar.gz:

Publisher: publish.yml on AlmanacCode/Yoke

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file almanac_yoke-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: almanac_yoke-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 132.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for almanac_yoke-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 3ce54759139fda01e1d899f196414cf42aa297d9a45f56f714356904233f0b61
MD5 8f64a99b190a02586b40d6d8daa3fc2c
BLAKE2b-256 c9f02a2189bfd2105c2bc3cb1fa3f7a71c54d5a7f67de8017a4ec316977b7090

See more details on using hashes here.

Provenance

The following attestation bundles were made for almanac_yoke-0.1.5-py3-none-any.whl:

Publisher: publish.yml on AlmanacCode/Yoke

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page