Build · execution ownership
SDK integrations
Keep your SDK's model loop in the app and ask for tool decisions, or move that loop into a Runkite runner and create managed Threads/Runs. Choose the boundary your caller needs. The frontend can remain in Next, Nuxt or another app.
Availability checked 2026-11-08. The latest published tag is
v0.6.1,
the first Apache-2.0 release. Published v0.6.0 artifacts retain BUSL-1.1.
The decision API shipped in v0.5.3. The managed AI SDK runner ships in
runkite-runner from v0.5.8 (optional peer ai@7.0.155).
Repository helper guards and Microsoft function middleware remain unpublished
as runkite-governance packages. See
CHANGELOG
before selecting a package version.
Published Python profiles: the v0.6.1
runkite-runner wheel includes managed Microsoft Agent Framework,
OpenAI Agents SDK, Pydantic AI and Google ADK adapters, installed through
optional extras with dedicated commands. The stock Python image keeps its
LangGraph default and does not install these optional SDK dependencies.
Jump to LangGraph / LangGraph.js, Vercel AI SDK, Microsoft Agent Framework, OpenAI Agents SDK, Pydantic AI, Google ADK, managed chat and reconnect or app-owned tool decisions.
Choose the execution boundary
| Caller | App keeps its loop | Runkite dispatches the loop |
|---|---|---|
| Entry point | POST /governance/decide | Agent Protocol thread/run routes |
| Who executes a tool? | Your app, after allow or later approval | The SDK inside a runner; actual connector gates govern connector calls |
| Admin Threads/Runs | No records for this caller | Real managed records |
| Run controls | No run kill switch, break-glass or spend cap | Existing admission, queueing, cancellation and reported-usage path |
| Pending continuation | App-owned saved operation | Framework-dependent; initial AI SDK runner has no native approval/resume |
v0.6.0 runner identity fixes: TypeScript status checks now include the assignment tenant, and both helpers encode custom run IDs as one URL component. Unicode/legacy header-unsafe identities use new base64url headers and require a plane-first upgrade. New run IDs reject controls and outer whitespace. Named LangGraph tenants must use HTTP proxy checkpoints; direct Postgres now rejects every non-default tenant before factory/state access because legacy history has no ownership attestation. Default cron threads need proxy mode too. Review the native boundary and explicit history resolution before continuing. Managed Python SDK profiles and AI SDK opaque history continue using the exact scoped HTTP checkpoint boundary.
App-owned tool governance
A normal AI SDK tool.execute or a Microsoft local function can
ask Runkite once before execution. Use a server-side key with the explicit
governance:decide permission; read/write and agent-run permissions
do not imply it. The key selects the tenant. Policy identities and the target
arguments must come from trusted server code.
- Submit agent, connector, tool and exact arguments to
/governance/decide. - Execute only after
allow. An allow is permission, not evidence that the tool executed. - For
pending, persist the action ID and original operation in the app, then return promptly. - On a later authenticated request, poll
GET /governance/actions/{action_id}and execute the saved operation only afterapproved. - Reject fresh replacement arguments and use an application transaction, downstream idempotency key or outbox to prevent duplicate effects.
run_id on this door is a stable application correlation value, not
a managed Runkite run or an execution-idempotency guarantee. Polling does not
consume approval. Rejected or consumed actions must not execute. Embedded
pending rows expire after 24 hours on SQL; expired rows cannot be approved.
Admin approval updates the pending row and does not execute or resume your app.
The v0.6.0 argument parser preserves the submitted JSON type. This door
still accepts any JSON argument value, but a string containing JSON remains
a string rather than being parsed again. Submit an object when your policy
predicates inspect its fields; ambiguous duplicate keys or invalid Unicode
receive HTTP 400.
v0.6.0 approval upgrade: pending or approved actions
created before the v2 argument binding now poll as rejected
with approval_binding_legacy, and Admin refuses to approve them.
Do not execute the saved operation from that result. Resubmit for a new
decision and fresh approval when required. There is no migration or automatic
replay; see approval upgrades.
The repository's TypeScript createGovernedExecute decides once and
never polls or retries. It supports ordinary single-result JSON tools inside
generateText and streamText; async-iterable tool outputs
are outside that helper. The optional Python Microsoft
GovernanceFunctionMiddleware uses the same door for local function
tools, tested with agent-framework-core==1.23.0. It is not a
Microsoft managed runner and creates no Admin run.
Managed LangGraph and LangGraph.js
The default Python and TypeScript runkite-runner commands
execute LangGraph and LangGraph.js in separate workers. Install with
pip install runkite-runner or
npm install -g runkite-runner, then load a graph from your
runner config. These profiles create managed Threads/Runs and support
their documented native interrupt/resume and checkpoint paths.
Start with the first-agent walkthrough,
agent registration and runner commands and
capability matrix.
Named tenants and default cron:<name> threads must use
HTTP proxy checkpoints.
Direct Postgres checkpoints are limited to guarded default-tenant IDs;
switching modes does not import old native history. The four older
CrewAI, LlamaIndex, AutoGen and plain LangChain adapters remain
checkout-only integrations.
Managed Vercel AI SDK runs
The new TypeScript backend executes public AI SDK ToolLoopAgent
code inside the runner. Your app creates a Runkite run and consumes its stream
instead of calling the model loop in its HTTP handler. Runkite owns operational
dispatch and records; the SDK still owns the model loop. No upstream fork,
second scheduler, policy engine or SDK runtime inside the Go binary is needed.
{
"runner_kind": "typescript-ai-sdk",
"graphs": { "managed_ai_sdk": "./agent.ts:createAgent" }
}
Each export is a per-run factory returning AiSdkAgentDefinition
settings. The runner constructs the native SDK agent using those settings.
This supported factory shape lets it supply trusted run context and check
allowed_tools before local execution. An arbitrary opaque agent
object is not automatically fully governable.
# From a v0.5.8+ checkout or installed runkite-runner; no provider key for this example cd typescript/runkite-runner npm ci npm run build cd ../../examples/managed_ai_sdk npm ci cd ../.. # Local development plane, separate terminal runkite dev --config examples/managed_ai_sdk/langgraph.json # Matching runner node typescript/runkite-runner/dist/cli.js --framework ai-sdk \ --config examples/managed_ai_sdk/langgraph.json \ --grpc-address localhost:50051 --http-address http://localhost:2026
ai@7.0.155 is the tested optional peer. The updated runner package
exposes runkite-runner/ai-sdk. The example keeps the existing
langgraph.json filename and graph mapping; the protocol does not
require the agent to use LangGraph. For production, use the normal
auth, runner-token, TLS and deployment profile.
Keep the AI SDK chat UI
AI SDK useChat reads its own UI message protocol. The example's
app-side bridge converts the runner's custom:ai_sdk events through
the SDK's public UI APIs and waits for durable Runkite completion before UI
finish. Your existing app authenticates the user, checks chat ownership, maps
chat IDs to server-owned threads, and keeps the Runkite key on the server.
Use managed-run read/write permissions for that route; a governance-only key
cannot create, read and cancel managed runs.
Only the new user text enters the runner. Browser history is presentation state and cannot replace its stored native model/tool history. A different attempt after rendering begins causes a delivery error rather than mixing two assistant replies. Automatic reconnect, regeneration and browser tool approvals are not part of this initial bridge.
v0.6.0 checkout bridge update: the app can explicitly
detach delivery, reattach its owned run through an authenticated GET, and
request run cancellation through a separate app POST. Create still cancels
on disconnect by default;
detach requires the app's persisted run ID. Reattach uses complete retained
replay from the same attempt without dispatching the model or tools again.
Persist the first assistant ID with onMessageStart before display
and pass it back as expectedMessageId, so a replacement attempt
cannot silently become a second assistant after reconnect. Missing history
fails explicitly. This is manual reattachment, not an automatic retry loop;
see the example's reconnect and Stop contract.
Durability and limits
- The v0.6.0 bridge applies
timeoutMs(30 seconds by default) to browser request-body intake as well as HTTP setup and durable-completion reads. A stalled intake is canceled before any run is created. This is not a duration limit on the running chat stream. - New thread/run IDs equal to
.or..are rejected with HTTP400before persistence. Other custom string IDs remain supported; encode them as individual URL components. The bridge already refuses dot-only IDs. - Native successful-turn history uses the existing run-bound opaque checkpoint API, with framework/agent validation, exact generation and tenant binding, strong ETags and CAS.
- State must commit before success. A committed current-run receipt replays after reclaim without repeating its model or tools. A crash before commit can still repeat external writes; downstream idempotency is required.
- Initial scope is text and local JSON-result tools. No native approval/resume, client/provider tools, async-iterable tool outputs, binary attachments, time travel, partial-turn restore or whole-run caching.
- Run lifecycle does not automatically govern every native tool body. Connector policy still requires the real connector path. Cancellation cannot undo an already completed effect.
- v0.6.0 connector helpers use one total operation deadline and refuse redirects. Pass the TypeScript run signal, or cancel the Python coroutine, to stop delivery. Only the plane's explicit pre-dispatch
connector_session_invalidresponse permits automatic renewal. Upgrade the plane first; an upstream401becomes502 connector_upstream_unauthorizedand is not retried. See connector recovery rules. - Successful turns report provider tokens. The plane can settle cancellation before trailing usage arrives, so complete canceled-run spend is not guaranteed.
- State is capped at 16 MiB, a turn's UI receipt at 8 MiB and final output at 3 MiB. The example bridge has its own documented request/frame limits.
make test-managed-ai-sdk exercises native SDK calls, the UI consumer
and a real Go plane. Set RUNKITE_TEST_POSTGRES_DSN and
RUNKITE_TEST_REDIS_URL together to select its Postgres + Redis
profile, including crash-after-commit receipt replay without duplicate tool
work or usage. This suite uses one plane process; it is not a multi-replica HA soak.
Source and runnable example: examples/managed_ai_sdk. Existing CrewAI, LlamaIndex, AutoGen and plain LangChain adapters remain checkout integrations, not published adapter packages. See the framework matrix and limitations before claiming feature parity.
Managed Python SDK profiles (v0.6.1)
Microsoft factories return a public agent_framework.Agent for
python-agent-framework. OpenAI factories return a public
agents.Agent for python-openai-agents. Both run the
native loop in a Python worker and create ordinary Runkite Threads/Runs.
The plane owns dispatch and durable records through existing protocols;
it does not embed an SDK runtime or use a hosted agent-session service.
Install the published v0.6.1 profiles with
pip install 'runkite-runner[agent-framework]' or
pip install 'runkite-runner[openai-agents]' in a clean environment.
Source installs from ./python remain available for contributors.
Run runkite-runner-agent-framework or
runkite-runner-openai-agents with the matching config. The SDKs
are pinned to agent-framework-core==1.23.0 and
openai-agents==0.24.0. Repository PYTHONPATH is not
needed after installation. The ordinary Python command and stock image
retain their LangGraph defaults; the image does not install these extras.
Initial support is successful text turns and ordinary local tools. Conditional opaque state and receipts preserve native history and avoid repeated model/tool work after a confirmed commit. Interrupted and failed turns retain prior committed history. External effects before commit still require idempotency. Native approval/resume is unsupported, and local tools need the actual connector path to receive connector grants and HITL. The OpenAI profile also rejects native handoffs, hosted/MCP tools and structured final outputs. Its native SDK trace exporter is disabled; Runkite OTLP run tracing remains available.
The managed Python profiles enforce dispatched allowed_tools
before local execution: omitted is unrestricted, [] denies all,
and a list permits those names. Microsoft uses native function middleware
and rejects a configured restriction before model execution if a custom
client lacks that invocation boundary. This cooperative check is not a
sandbox or a replacement for connector policy.
Microsoft Agent Framework
Select python-agent-framework in the plane config and run
runkite-runner-agent-framework. A per-run factory returns
agent_framework.Agent; the adapter preserves successful
native AgentSession history. Workflows, .NET, non-text input
and native approval/resume remain outside this profile. Follow the
managed Microsoft example and installed-runner tests.
OpenAI Agents SDK
Select python-openai-agents and run
runkite-runner-openai-agents. A per-run factory returns
agents.Agent; the adapter streams text and persists native
successful-turn history. Native approval/resume, handoffs, hosted/MCP
tools and structured final output are unsupported. Follow the
managed OpenAI Agents example and installed-runner tests.
Use the shared UI bridge
The application retains its UI authentication and presentation history. The v0.6.1 shared application bridge can translate these Python profiles' ordinary Agent Protocol text for the same AI SDK UI transport. Choose the profile on the server and use the Next/Nuxt route recipes. It validates the current turn and durable framework/generation before finishing; Pydantic final JSON remains a separate result part. Python profiles do not add native tool UI, reasoning display or approval resume. Attach expects a bridge-created single-user string turn with full retained replay and a persisted assistant identity. The tests use offline native models with a real plane on SQLite/in-process and Postgres/Redis, not an external model provider or a multi-replica HA soak.
Managed Pydantic AI (v0.6.1)
Native pydantic_ai.Agent factories run as
python-pydantic-ai through the existing generic worker.
Text can stream, while typed final results are validated by the SDK
and stored as JSON in output.result. Only completed
execution commits success; partial JSON is not a durable result.
Install with pip install 'runkite-runner[pydantic-ai]' and
run runkite-runner-pydantic-ai. Published PyPI v0.6.1 includes
this adapter. The optional extra pins pydantic-ai-slim==2.63.0;
install your chosen provider separately. Source installs from
./python[pydantic-ai] remain available. The stock image does
not install this SDK, and the default CLI remains LangGraph.
Native conversations retain metadata and successful history through opaque CAS state. Per-run usage excludes earlier conversation turns; a committed receipt replays without repeating the factory, model or tools. Local tool allowlisting is separate from synthetic output-schema calls. Connector policy requires the existing connector path. Native deferred approvals, output functions, multimodal input and additional workflow engines are outside this profile.
The app keeps UI authentication and presentation history. Use the ordinary Agent Protocol result stream, then read the durable result. See the offline example and adapter contract and tests.
Managed Google ADK (v0.6.1)
A fresh ordinary LlmAgent runs as python-google-adk
through the Python worker. The public ADK runner keeps the model loop;
Runkite owns Threads/Runs, dispatch, cancel, received usage and durable records.
No hosted Agent Engine or additional session database is required.
Install with pip install 'runkite-runner[google-adk]', then run
runkite-runner-google-adk with the same config loaded in the plane.
Published PyPI v0.6.1 includes this adapter; the optional extra pins
google-adk==2.13.0. Source installs from
./python[google-adk] remain available. The default CLI and stock
image keep their LangGraph defaults, and the image does not install this SDK.
Send exactly one new user text message per run. Native events, tool results and session-local state persist through opaque CAS writes and successful receipts. Partial text is reconciled with the final aggregate, and a final response marker alone does not prove success. Reclaim after commit replays without another model/tool cycle. The app owns UI authentication and presentation history and consumes ordinary Agent Protocol events.
Shared app:/user: state is rejected rather than
silently made thread-local. Temporary state lasts for the invocation.
Workflows, delegation, native confirmation/resume, long-running tools,
memory/artifacts, structured output and live audio are outside the first
slice. Local tools need the existing connector path for connector grants,
secret injection and HITL. Native confirmation blocks the local body,
although its model proposal can already have consumed tokens.
See the offline example and adapter contract and tests for session scope, token accounting, telemetry privacy and installed-package checks.