Catalog PyPI
Back to packageRELEASE DETAILS

6.0.6

PyPI

agentdeck-sdk

Agentic software should feel like software. Build agents, tools and workflows as normal software, and get one execution model you can observe, control and extend.

Published14 Sept 2026
Direct dependencies25
Transitive dependenciesNot calculated

README

Version 6.0.6 documentation
AgentDeck

AgentDeck SDK

Agentic software should feel like software.

Build agents, tools and workflows as normal software. AgentDeck gives them one execution model you can observe, control and extend.

CI Release Python License Docs

You write the agents, tools and workflows. AgentDeck writes what surrounds them: a run that suspends on a human and resumes days later on another machine, a cancel that lands on a run in another process, one conversation that survives turns, surfaces and restarts, and one event log that the HTTP wire, the terminal and AG-UI all read the same way.

None of that is your application, and all of it is work. It is done once here instead of again in every project that needs it, and needing the next piece of it costs one call, not a redesign.

pip install agentdeck-sdk

Built to stay out of your way

Agent systems accumulate infrastructure quickly, and decisions that look small early are the hardest to change later.

Execution, control, state, observability, reporting, interaction, and integration already have their place in AgentDeck, and they were designed to work together: less machinery to build today, and nothing to retrofit around your application when you need the next one.

Simple code. Serious capabilities.

Your code stays about the behavior and structure of your application:

  • Tools do work: A plain Python function for a context-free tool, @tool for one that declares ToolCtx[T] to receive strongly typed application data without exposing internal state to the model prompt.
  • Agents make decisions: Declarations configuring model instructions, tools, skills, and handoffs.
  • Workflows manage process: Ordinary async Python functions decorated with @workflow. Use WorkflowCtx to invoke targets (ctx.invoke), branch in parallel (ctx.parallel), or park for human input (ctx.ask).
  • Decks assemble applications: Deck is the single composition root. It validates dependencies, schemas, and catalogs at startup before the first turn.
from agentdeck import Agent, Deck, ToolCtx, WorkflowCtx, tool, workflow

class AppContext:
    def search(self, query: str) -> str:
        return "Internal records found."

@tool
def lookup_records(query: str, ctx: ToolCtx[AppContext]) -> str:
    """Look up internal records."""
    return ctx.data.search(query)

agent = Agent(
    name="SupportBot",
    instructions="Help users resolve inquiries using internal tools.",
    tools=[lookup_records],
)

@workflow
async def handle_request(ctx: WorkflowCtx, ticket: dict) -> str:
    """Coordinate support tasks with human approval for sensitive changes."""
    response = await ctx.invoke(agent, ticket["query"])
    if ticket.get("urgent"):
        approved = await ctx.ask(f"Approve urgent response for ticket {ticket['id']}?", options=[True, False])
        if not approved:
            return "Escalated to human supervisor."
    return response

deck = Deck(agents=[agent], workflows=[handle_request], context=AppContext)

You build the behavior. AgentDeck manages the machinery.

Run
├── executions     nested invocations, each addressable
├── events         one ordered log per run
├── reports        progress and status from inside the work
├── state          sessions that outlive a single call
├── interaction    branches that wait for external input
└── control        pause, resume, cancel
You ownAgentDeck owns
agents, tools, workflowsEvents. One ordered stream of what happened.
what progress meansReporting. Progress and status, sent from inside the work.
when work should stopControl. Execution paused, resumed or cancelled at safe points.
when a person decidesInteraction. Branches that wait for external input.
business stateState. Sessions that outlive a single call.
your UI and integrationsBindings. Native HTTP/SSE, the terminal, AG-UI clients such as Assistant UI, and any binding you write read the same run.

The complexity is still there. It just lives in the layer built for it.

Reachable through bindings

One Deck, served over its own HTTP wire, the AG-UI protocol, and the terminal at once. Add a binding by adding a line; the runtime never learns which one is talking.

from agentdeck import Deck
from agentdeck.bindings import AGUI, Native, Terminal

deck = Deck.from_project()
deck.serve(Native.http("/api"), AGUI.http("/agui"), Terminal.stdio(), port=8000)

See what changed in 6.0.

Streaming and event logs

Every managed execution produces an immutable, ordered stream of events:

async with deck:
    async for event in deck.stream("handle_request", {"id": "T-100", "query": "status update"}):
        print(event.kind)  # run.started, tool.call.started, text.delta, run.completed

Execution you can steer

A Run is first-class and addressable. Steering methods belong to the handle:

run = await deck.runs.start("handle_request", {"id": "T-100", "query": "status update", "urgent": True})

if run.can.pause:
    await run.pause()
    await run.resume()

# Answer an execution waiting on human approval:
await run.answer(True)
result = await run

deck.runs.get(id) rehydrates the handle in another process, so a run parked on input or paused by a web request can be resumed by an asynchronous worker.


Where your definitions live

Everything you define can live in a .agentdeck/ directory next to where you run. The path is the registration:

.agentdeck/
├── agents/support_bot/agent.py        # an Agent(...)
├── workflows/handle_ticket/workflow.py # a @workflow function
└── skills/troubleshooting/            # SKILL.md + prompt resources
async with Deck.from_project() as deck:
    result = await deck.run("handle_ticket", {"id": "T-101", "query": "help"})

Deck.from_project() discovers and validates all definitions at startup, catching missing skills, invalid types, or broken references at build() time.


Who it is for

You want this if you are putting agents somewhere they have to keep working: several agents and workflows in one project, a chat surface and a batch path over the same definitions, runs you need to inspect afterwards, approvals that outlive the process that asked for them.

You do not want this if you are writing one script that calls one model. Use the Agents SDK directly, and come back when the wiring around it has become the work. You also do not want it if you have already built your own harness: AgentDeck is opinionated about project layout and configuration, and those opinions are the product.

What it deliberately does not do

  • No DSL. Definitions are Python. There is no YAML agent format, and there will not be one.
  • No agent loop of its own. Bugs in the agent loop belong upstream, and improvements there arrive without agentdeck doing anything.
  • No sandbox. Tools, skills and workflows are ordinary Python in your process, and a model-chosen tool call is trusted by design. See SECURITY.md before you give an agent something destructive.
  • No auth, no multi-tenancy, no hosted control plane, no marketplace. namespace labels a run; it does not authenticate anyone. Put a real gateway in front of the HTTP surface.
  • No evaluation framework or prompt management. Model prefixes select configured providers; AgentDeck does not add a dynamic routing service.

Install

pip install agentdeck-sdk
export OPENAI_MODEL=gpt-4.1-mini OPENAI_API_KEY=sk-...

The distribution is agentdeck-sdk; the import stays agentdeck. Agents may declare openai/..., anthropic/..., gemini/..., ollama/..., or openrouter/...; see model configuration. OPENAI_BASE_URL also supports any OpenAI-compatible endpoint. Extras: the serve extra for Native.http(), AgentDeck's own HTTP/SSE binding; agentdeck-sdk[agui] for AGUI.http(), the AG-UI protocol binding Assistant UI and CopilotKit speak; postgres for the Postgres event log; redis for Redis-backed sessions or event log; observability for Langfuse tracing.

Contributing to agentdeck itself is a different setup: see CONTRIBUTING.md.


Documentation

The full documentation and live assistant demo are at agentdecksdk.com:

If AgentDeck is useful to you, a star helps other developers find it.


Project

Contributors

Contributors

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 28

Native requirements
25 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
httpx
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
httpx>=0.27runtime
openai-agents
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
openai-agents==0.17.0runtime
openai
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
openai==2.32.0runtime
pydantic-settings
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pydantic-settings>=2.4runtime
pydantic
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pydantic>=2.7runtime
python-dotenv
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
python-dotenv>=1.0runtime
pyyaml
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pyyaml>=6.0runtime
ag-ui-protocol
Environment
{
  "extras": "",
  "marker": "extra == \"agui\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
ag-ui-protocol<0.2,>=0.1.22; extra == "agui"runtime
starlette
Environment
{
  "extras": "",
  "marker": "extra == \"agui\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
starlette>=0.40; extra == "agui"runtime
ag-ui-protocol
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
ag-ui-protocol<0.2,>=0.1.22; extra == "dev"runtime
fastapi
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
fastapi>=0.115; extra == "dev"runtime
griffe
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
griffe>=2.3.0; extra == "dev"runtime
import-linter
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
import-linter==2.15; extra == "dev"runtime
pre-commit
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pre-commit>=4.0; extra == "dev"runtime
pytest-asyncio
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pytest-asyncio>=0.23; extra == "dev"runtime
pytest-cov
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pytest-cov>=5.0; extra == "dev"runtime
pytest-timeout
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pytest-timeout>=2.3; extra == "dev"runtime
pytest
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
pytest>=8.0; extra == "dev"runtime
redis
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
redis>=5.0; extra == "dev"runtime
ruff
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
ruff>=0.16.7; extra == "dev"runtime
ty
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
ty>=0.0.80; extra == "dev"runtime
langfuse
Environment
{
  "extras": "",
  "marker": "extra == \"observability\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
langfuse>=4.15.2; extra == "observability"runtime
openinference-instrumentation-openai-agents
Environment
{
  "extras": "",
  "marker": "extra == \"observability\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
openinference-instrumentation-openai-agents>=2.4.1; extra == "observability"runtime
opentelemetry-sdk
Environment
{
  "extras": "",
  "marker": "extra == \"observability\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
opentelemetry-sdk>=1.27; extra == "observability"runtime
psycopg
Environment
{
  "extras": "binary",
  "marker": "extra == \"postgres\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
psycopg[binary]>=3.2; extra == "postgres"runtime
redis
Environment
{
  "extras": "",
  "marker": "extra == \"redis\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
redis>=5.0; extra == "redis"runtime
starlette
Environment
{
  "extras": "",
  "marker": "extra == \"serve\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
starlette>=0.40; extra == "serve"runtime
uvicorn
Environment
{
  "extras": "",
  "marker": "extra == \"serve\"",
  "requires_python": ">=3.12",
  "evaluation": "NOT_EVALUATED"
}
uvicorn>=0.30; extra == "serve"runtime

Distribution files

2 collected
agentdeck_sdk-6.0.6-py3-none-any.whl

bdist_wheel · 291.35 KB · Python py3

Source file
agentdeck_sdk-6.0.6.tar.gz

sdist · 1,534.78 KB · Python source

Source file

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:47 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:12eb21b7dbbdd7af10d019aec54590891994b42cf9da0c1d99bdbe3e1e8070f2

Other collected versions

View all collected versions →