Author an agent — or a team of agents — in YAML or Python.
Get the production stack wired for you: tools, memory, tracing, streaming, and a served API.
Your agent works in a notebook. Shipping it means a REST API, session storage, tracing that reports real token costs, streaming with its error cases, and packaging. That is a couple of thousand lines of infrastructure with nothing to do with what your agent does — and you rebuild it for the next one.
The usual answer is a framework that owns everything. Then you are inside it, and the day you need something it lacks, you are rewriting.
AgentShip integrates best-of-breed libraries behind small, stable seams. LangGraph runs the graph. LiteLLM talks to models. MCP supplies tools. OpenTelemetry carries traces. We reimplement none of them — we wire them together and add the plumbing none of them ship.
pip install "agentship-sdk[starter,observability]"One agent, one tool:
# calc.yaml
name: calculator-agent
engine: langgraph
model: openai/gpt-4o-mini
prompt: Use the calculator for arithmetic. Answer with just the number.
tools: [calculator]agentship run calc.yaml --input "What is 17 times 23?"
# 391A team, with a coordinator that routes on each member's description:
# team.yaml
name: research-team
engine: langgraph
model: openai/gpt-4o-mini
members:
- name: analyst
description: arithmetic, comparisons, and calculations over known numbers
model: openai/gpt-4o-mini
prompt: Answer with the number and one short sentence.
- name: writer
description: explanations, summaries, and anything needing prose
model: anthropic/claude-sonnet-4-6
prompt: Answer in two clear sentences.A member can be inline like this, a ref: to its own YAML file, or a networked agent
reached over A2A. Each runs as its own turn, nested inside the coordinator's trace.
agentship serve --agents-dir . # /v1 REST + SSE + WebSocket, and Studio at /studioNo API key? The echo engine runs offline, so the transports, auth, error model and
Studio are all explorable for free:
name: hello
engine: echo
prompt: A stand-in agent that needs no provider.One YAML spec is compiled by an engine adapter into somebody else's graph, and run through a kernel that imports no vendor library. Everything below is in the tree today — dashed boxes are seams with a contract and one implementation, not roadmap.
flowchart TB
classDef spec fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#7c2d12
classDef system fill:#ccfbf1,stroke:#0f766e,stroke-width:2.5px,color:#134e4a
classDef adapter fill:#dcfce7,stroke:#15803d,stroke-width:1.5px,color:#14532d
classDef ext fill:#f1f5f9,stroke:#64748b,stroke-width:1.5px,color:#334155
classDef obs fill:#dbeafe,stroke:#1e40af,stroke-width:1.5px,color:#1e3a8a
SPEC["<b>agent.yaml</b><br/><i>[AgentSpec]</i><br/>name · engine · prompt<br/>tools · members"]:::spec
CLI["<b>agentship-cli</b><br/><i>[Entry point]</i><br/>run · serve · doctor · verify"]:::spec
SVC["<b>agentship-service</b><br/><i>[FastAPI]</i><br/>:invoke :resume :stream<br/>WS /live · /a2a · Studio"]:::spec
subgraph CORE["agentship-core — imports no vendor library"]
RT["<b>RunnableAgent</b><br/><i>[Runtime]</i><br/>one turn: run / stream / resume"]:::system
SEAM["<b>Seams</b><br/><i>[Contracts]</i><br/>auth · tenancy · tools<br/>observability · A2A"]:::system
CONF["<b>Conformance matrix</b><br/><i>[Build gate]</i><br/>fails on a capability<br/>declared but not held"]:::system
end
subgraph ENG["engine adapters — the only code that names a vendor"]
ECHO["<b>echo</b><br/><i>[Engine]</i><br/>no provider, no network"]:::adapter
LG["<b>langgraph</b><br/><i>[Engine]</i><br/>single · graph · autonomous"]:::adapter
end
subgraph EXT["consumed, never reimplemented"]
X1["<b>LangGraph</b><br/><i>[External]</i><br/>StateGraph · checkpointer"]:::ext
X2["<b>LiteLLM</b><br/><i>[External]</i><br/>every model provider"]:::ext
X3["<b>MCP adapters</b><br/><i>[External]</i><br/>stdio · http · OAuth"]:::ext
end
OBS["<b>agentship-observability</b><br/><i>[OTel exporter]</i><br/>Phoenix / Langfuse / Opik"]:::obs
SPEC -->|compiled by| CLI
SPEC -->|served by| SVC
CLI --> CORE
SVC --> CORE
CORE -->|delegates the turn to| ENG
CONF -.->|verifies| ENG
LG --> X1
LG --> X2
LG --> X3
CORE -->|emits spans| OBS
Read it in one line: your spec never names a vendor, the kernel never imports one, and the adapter is the single place that does — so replacing LangGraph is one package, not a rewrite.
echo is the proof rather than a toy: it is a second engine with no provider, no network and
no key, which is why the conformance matrix can tell a capability an engine declares from one
it actually has.
Not in this picture, because it is not built yet: voice, long-term memory, guardrails/PII, sandboxing, evals, and the ADK / Pydantic AI adapters. See Status.
Multi-agent. A coordinator classifies the request against each member's description,
dispatches, and merges the result. Members nest properly in the trace — a sub-agent's model
and tool calls appear beneath it, not in a separate trace.
Tools and MCP. Built-in tools (calculator, web_search, scrape_url), your own
Python functions, and any MCP server — stdio or streamable HTTP — through
langchain-mcp-adapters. An MCP tool and a native one are indistinguishable to the graph.
Memory and durability. Short-term conversation memory by default; PostgreSQL
checkpoints when a run needs to survive a restart. A run that pauses for a human returns a
resume token, and POST /v1/agents/{name}:resume continues it.
Observability that shows the money. One OpenTelemetry span tree per turn:
agent triage
node.classify
chat openai/gpt-4o-mini in=43 out=1 $0.000007
agent billing_specialist
chat openai/gpt-4o-mini in=43 out=54 $0.000039
Spans are named after the thing that ran — agent <name>, chat <model> — rather than
agent and model, so a backend's list is readable. Turns carry thread_id, so a
conversation groups into one thread instead of scattering into unrelated traces. Exports to
Opik, LangFuse, LangSmith or Phoenix: set AGENTSHIP_OTEL_EXPORTERS and the credentials,
and nothing in your spec changes.
Reasoning models. reasoning_effort: minimal | low | medium | high — one knob, mapped
by LiteLLM onto whichever scale the provider uses. Thinking arrives on its own reasoning
stream frame, never mixed into the answer, and reasoning tokens are recorded separately so
a turn that cost 5× shows why.
Serving. /v1 REST, SSE streaming, WebSocket, RFC-9457 problem documents, API-key or
JWT auth, per-tenant isolation, and validated structured output when a spec declares an
output_schema.
Studio, built in. A chat and trace UI at /studio, served by the same process — one
self-contained HTML file, no build step and no CDN. It shows what the agent is doing while
it works, rather than a spinner:
✓ Thinking…
✓ Calling web_search…
✓ Reading web_search result…
the answer
Six distributions, released together, one version. Install only what you need.
| Package | What it is |
|---|---|
agentship-sdk |
The batteries-included meta-package |
agentship-core |
The vendor-free kernel: spec, runtime, registry, middleware, echo engine |
agentship-langgraph |
The reference engine — compiles a spec into a LangGraph StateGraph |
agentship-service |
The FastAPI app behind /v1, plus Studio |
agentship-observability |
The OpenTelemetry pipeline and its exporters |
agentship-cli |
agentship run, serve, verify, doctor, init |
agentship-core imports no vendor library. That is what keeps the seams honest: the engine
can be replaced without touching the kernel, and a conformance matrix fails the build if an
engine declares a capability it does not actually have.
pip install "agentship-sdk[starter,observability]" # the usual stack
pip install "agentship-sdk[all]" # everything
pip install "agentship-langgraph[mcp]" # MCP tools
pip install "agentship-core[postgres]" # durable checkpointsagentship init my-project # scaffold a project
agentship new-agent support # scaffold one agent from a template
agentship run agent.yaml # one turn, printed
agentship serve --agents-dir agents # the /v1 API + Studio
agentship doctor # validate every spec against its engine
agentship verify # prove engines honour what they declare
agentship db upgrade # apply checkpoint migrations (gated)doctor and verify exist because a capability an engine declares and one it actually
has are different things. verify fails the build when they diverge.
| Capability guides | docs/capabilities/ — multi-agent · tools & MCP · observability · service & security · checkpointing & HITL · durable resume |
| Architecture decisions | docs/decisions/ — why we integrate rather than reimplement |
| Runnable examples | examples/ |
| Releasing and versioning | docs/RELEASING.md |
| Deploying | deploy/RAILWAY.md |
| API collection | postman/ |
| Contributing | CONTRIBUTING.md |
| Changelog | docs/CHANGELOG.md |
Early — 0.x, so the API can change between minor versions. Pin exactly if that matters
to you (agentship-sdk==0.0.2).
0.0.1is yanked. It reserved the six names on PyPI but could not run an agent — tracing was on by default and the adapter is not in[starter], so every run failed withobservability provider 'otel' is not installed. Fixed in 0.0.2; every resolver skips0.0.1, so a plainpip installgets the working one.
What is built is the diagram above: the spec, the kernel and its seams, two engines, the
/v1 service, the CLI, and OpenTelemetry tracing. What is not built yet: voice, long-term
memory, guardrails/PII, sandboxing, evals, and the ADK / Pydantic AI adapters. The JOSS
figures in figures/ show the full intended system, not today's tree.
Rebuilt foundation-first: one thin working slice per phase, with tests and a runnable demo before anything is called done. Test first, one task per commit, CI green — see CONTRIBUTING.

