karta-runtime
The Karta runtime: harness adapters, sessions, and the consumer session API on agent harnesses like Claude Code and OpenCode
Looking for the
kartacommand? The public CLI is@karta.sh/cli(npm install -g @karta.sh/cli). This package iskarta-runtime- the internal engine that CLI bootstraps forkarta dev, and the data plane the platform serves (RFC 0013, docs/rfcs/0013-unified-cli.md). Its own CLI verbs are internal (see CLI); use it directly as a Python SDK/library, exactly as documented below.
Why Karta
Agent frameworks like LangGraph, CrewAI, AutoGen, and the OpenAI Agents SDK build agents from scratch — defining their own tool systems, context management, memory, and execution loops.
Karta takes the opposite approach. Agent harnesses like Claude Code and OpenCode already solved the hard problems — tools, MCP servers, context management, memory, skills, and agentic execution. They're battle-tested, deeply integrated with real development workflows, and improving fast.
Karta builds on top of these harnesses in two tiers: a thin core that delegates all agent execution and conversation persistence to the harness, plus a platform layer that adds the multi-tenant SaaS machinery production applications need. Together they provide multi-user sessions, multi-agent routing, participant-aware messaging, cross-instance communication, HTTP deployment, multi-tenancy with durable tenant isolation, BYOK key management, usage metering, policy enforcement, and lifecycle hooks — without reinventing agent capabilities from scratch.
┌──────────────────────────────────────────────────────────┐
│ Other frameworks │ Karta │
│ │ │
│ Build agents from scratch │ Build ON existing harnesses │
│ Own tool system │ Harness tools (MCP, etc.) │
│ Own memory/context │ Harness memory/context │
│ Own execution loop │ Harness execution loop │
│ + Multi-agent orchestr. │ + Multi-user sessions │
│ │ + Multi-agent routing │
│ │ + Gateway & fan-out │
│ │ + Multi-tenancy │
│ │ + HTTP API & CLI │
│ │ + Hooks & policies │
└──────────────────────────────────────────────────────────┘
What Karta provides
| Feature | Description |
|---|---|
| Multi-agent routing | Discover and route to specialist agents defined in your harness's native format |
| Multi-user sessions | Route conversations by metadata (customer ID, channel, etc.) with automatic persistence |
| Participant model | Multiple humans and AI agents in the same session with message attribution |
| Gateway & fan-out | Unified event ingestion with fan-out delivery to all session participants |
| Cross-instance messaging | Agents on different Karta instances communicate via gateway HTTP POST |
| Multi-tenancy | Workspace-per-user isolation with KartaHub orchestrator |
| Session persistence | SQLite (default), PostgreSQL, or S3 backends |
| Lifecycle hooks | Events on message.received, message.completed, agent.handoff, session.created |
| Policy enforcement | Validate messages against configurable policies (length limits, message counts, keyword gates) |
| HTTP API | Production-ready FastAPI server with REST endpoints and SSE streaming |
| Internal CLI | karta-runtime dev/dev-serve/serve - streaming terminal REPL and the local/self-host serve planes (the public CLI is @karta.sh/cli) |
| Typed streaming | Structured events: text, tool_use, reasoning, step_start, step_finish, error, input_required |
Install
pip install karta-runtime
With optional backends:
pip install karta-runtime[postgres] # PostgreSQL sessions
pip install karta-runtime[s3] # S3 sessions
You also need a coding agent harness installed:
- Claude Code:
npm install -g @anthropic-ai/claude-code(docs) - OpenCode:
curl -fsSL https://opencode.ai/install | bash(docs)
Quickstart
Zero-config hello world
from karta import Karta
app = Karta()
response = app.send_sync("Hello!")
print(response.text)
Karta auto-detects your harness from the project directory (.claude/ → Claude Code, .opencode/ → OpenCode).
Multi-turn sessions
from karta import Karta
app = Karta()
session = app.session(metadata={"customer_id": "abc123"})
response = session.send_sync("I need help with my order")
response = session.send_sync("Order #12345")
# Resume later by looking up the session
session = app.session(metadata={"customer_id": "abc123"})
response = session.send_sync("Any updates?")
Multi-agent routing
Define specialist agents in your harness's native format (.claude/agents/*.md or .opencode/agents/*.md), then route:
from karta import Karta
app = Karta()
# Route to a specific agent
response = app.send_sync("Audit my billing", agent="billing-specialist")
# Agent handoff within a session
session = app.session(metadata={"customer_id": "abc123"})
session.send_sync("I need help with my order") # → default agent
session.current_agent = app.agents["billing"] # handoff
session.send_sync("Check invoice #789") # → billing agent
Multi-participant sessions
from karta import Karta, HumanAgent
app = Karta()
session = app.session()
alice = HumanAgent(name="alice", display_name="Alice Chen")
bob = HumanAgent(name="bob", display_name="Bob Park")
# Messages are attributed to the sending participant
session.send_sync("I need help with deployment", participant=alice)
session.send_sync("I can help — what's the error?", participant=bob)
Streaming
import asyncio
from karta import Karta
async def main():
app = Karta()
async for event in app.stream("Explain quicksort"):
if event.type == "text":
print(event.text, end="", flush=True)
asyncio.run(main())
HTTP API
from karta import Karta
from karta.server import create_fastapi_app
import uvicorn
app = Karta()
fastapi_app = create_fastapi_app(app)
uvicorn.run(fastapi_app, host="0.0.0.0", port=8000)
This exposes:
POST /v1/send— send a message, get a responsePOST /v1/stream— send a message, get SSE streamPOST /v1/sessions— create a sessionGET /v1/sessions— list/lookup sessionsPOST /v1/sessions/{id}/messages— send within a sessionPOST /v1/sessions/{id}/input/respond— respond to approval promptsPOST /v1/gateway/submit— submit a gateway eventPOST /v1/gateway/deliver— deliver to a local participantGET /healthz— health check
Multi-tenancy
from karta import KartaHub
hub = KartaHub("/path/to/karta-root")
# Each tenant/user gets an isolated workspace
session = hub.session("acme", "alice", metadata={"topic": "billing"})
response = session.send_sync("Help with invoice")
Lifecycle hooks
app = Karta()
@app.on("message.completed")
async def log_response(event):
print(f"Session {event.session.id}: {event.message.text}")
@app.on("agent.handoff")
async def track_handoff(event):
print(f"Handoff: {event.payload['from']} → {event.payload['to']}")
CLI (internal)
The customer-facing CLI is @karta.sh/cli; this package's verbs are internal
(local platform dev, self-host):
karta-runtime dev <path> # Hot-reload REPL against a folder
karta-runtime dev-serve <path> # Serve a folder behind the consumer session API
# (what the unified CLI's `karta dev` spawns)
karta-runtime serve # The platform serve plane (self-host / dev-infra)
This package installs no karta script at all - that name belongs to
the unified CLI (npm install -g @karta.sh/cli). It was dropped rather
than shimmed: karta-python never shipped to PyPI, so there is no
installed base to point anywhere.
Architecture
External Clients / Other Karta Instances
│
┌─────────▼──────────┐
│ Gateway │ event ingestion, fan-out delivery
│ Local · HTTP │ cross-instance messaging
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ Client Layer │ HTTP API · CLI · Python SDK
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ Multi-Tenancy │ KartaHub → WorkspaceManager
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ Karta Core │ sessions, agents, policies,
│ │ hooks, participants
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ Harness Layer │ Claude Code (SDK) or
│ │ OpenCode (CLI subprocess)
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ Coding Agent │ tools, MCP, context,
│ │ memory, skills
└──────────────────────┘
Design principles
- Convention over configuration — follows your harness's folder conventions
- Progressive disclosure — start with 3 lines, add features as you need them
- Harness-native — agents are defined in
.claude/agents/*.mdor.opencode/agents/*.md, not reinvented - Zero abstraction tax — examples from harness docs work as-is inside Karta
Progressive examples
The examples/ directory walks through increasing levels of complexity:
| Level | Directory | What it demonstrates |
|---|---|---|
| 0 | level-0-zero-config/ |
No config needed — just app.send() |
| 1 | level-1-project-context/ |
Project context with AGENTS.md / .opencode |
| 1 | level-1-project-context-claude-code/ |
Same, using Claude Code |
| 2 | level-2-custom-agent/ |
Single agent with a custom skill |
| 2 | level-2-custom-agent-claude-code/ |
Same, using Claude Code |
| 3 | level-3-multiple-agents/ |
Multi-agent routing |
| 4 | level-4-multi-turn-sessions/ |
Session persistence and metadata lookup |
| 5 | level-5-hooks-policies/ |
Lifecycle hooks and policy enforcement |
Configuration
Karta uses your harness's native agent definitions as the source of truth. Optional Karta-specific settings go in karta.jsonc:
{
"cli": {
"hidden_event_types": ["system"],
"input_required_policy": "prompt"
},
"harness": {
"claude": {
"idle_timeout_seconds": 600,
"permission_intercept": false
}
}
}
See examples/configurations/ for copy-ready templates.
Supported harnesses
| Harness | Adapter | Detection |
|---|---|---|
| Claude Code | ClaudeAdapter (via Claude SDK) |
.claude/ directory or CLAUDE.md |
| OpenCode | OpenCodeAdapter (via opencode run) |
.opencode/ directory |
| Deep Agents Code | DeepAgentsAdapter (via dcode -n) |
.deepagents/ directory |
| Goose | GooseAdapter (via goose run --output-format stream-json) |
.goose/ directory |
| Codex CLI | CodexCliAdapter (via codex exec --json) |
.codex/config.toml |
Adding a new harness means implementing one HarnessAdapter class.
Documentation
Design documents and implementation specs live in dev/:
- Architecture — system architecture reference
- Design document — architecture and design philosophy
- Implementation spec — detailed implementation reference
- CLI spec — CLI commands and options
- HTTP API spec — REST endpoint reference
- Gateway implementation plan — gateway system design
- Multi-tenancy architecture — workspace isolation deep dive
- Phase status — implementation progress tracking
Development
# Install dependencies
poetry install --all-extras
# Run tests
poetry run pytest
# Lint
poetry run ruff check src/ tests/
# Type check
poetry run mypy src/karta/
License
This project is licensed under the MIT License — see the LICENSE file for details.
Release files for karta-runtime 0.6.76
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| karta_runtime-0.6.76.tar.gz | 2.2 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| karta_runtime-0.6.76-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 4.7 MB
Release files / karta_runtime-0.6.76.tar.gz
| Download URL | karta_runtime-0.6.76.tar.gz |
|---|---|
| Size | 2.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7b8099c05c3f3b3c6104f899808d07b181aa398bac06c66c6c8d933b00af3d0d
|
|
BLAKE2b-256 checksum How to use checksums |
d9d73773f162082ddf04ab11441684e0f964b134795a9adb78a622e6b7f8c2fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.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 Jul 28, 2026.
Transparency logRelease files / karta_runtime-0.6.76-py3-none-any.whl
| Download URL | karta_runtime-0.6.76-py3-none-any.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c03a2e79701da3acdafec31730adcdbe6e64a02b44179c08e3d27b6edd2865e9
|
|
BLAKE2b-256 checksum How to use checksums |
ae0ac5facb1c53a71bec342ce292d4cedc1384a89c196a9b860645765e5aa742
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.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 Jul 28, 2026.
Transparency log