Karta agent runtime: harness adapters, dev serve, and the platform serve layer
Project description
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 |
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file karta_runtime-0.1.0.tar.gz.
File metadata
- Download URL: karta_runtime-0.1.0.tar.gz
- Upload date:
- Size: 196.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9dd66169c19bf407bdab90f6e8f81ad98d2050e9796ff4c2528da67b95122426
|
|
| MD5 |
7578a32d8e76056236cbb3f331187fe7
|
|
| BLAKE2b-256 |
59d46a6620caca6ebea1fe6db4e7ef651a4f86231a8568c9a48ef075f7e4ea51
|
Provenance
The following attestation bundles were made for karta_runtime-0.1.0.tar.gz:
Publisher:
publish.yml on karta-sh/karta
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
karta_runtime-0.1.0.tar.gz -
Subject digest:
9dd66169c19bf407bdab90f6e8f81ad98d2050e9796ff4c2528da67b95122426 - Sigstore transparency entry: 1785854411
- Sigstore integration time:
-
Permalink:
karta-sh/karta@d9f84c5d3c902ac45953f8e8f96791a3824db290 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/karta-sh
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d9f84c5d3c902ac45953f8e8f96791a3824db290 -
Trigger Event:
release
-
Statement type:
File details
Details for the file karta_runtime-0.1.0-py3-none-any.whl.
File metadata
- Download URL: karta_runtime-0.1.0-py3-none-any.whl
- Upload date:
- Size: 236.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8998666aa04aa8fb91d4000bfd56f1e93daa6683f6f3b1eead0e90fc1ce5b65
|
|
| MD5 |
d145a9250fda3c6437af887d4d4075bf
|
|
| BLAKE2b-256 |
9fa07c0b6feb0eabb2fd21c999b5f1a9bc42c4d6dba5b8c373cabffd6b8e8db2
|
Provenance
The following attestation bundles were made for karta_runtime-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on karta-sh/karta
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
karta_runtime-0.1.0-py3-none-any.whl -
Subject digest:
b8998666aa04aa8fb91d4000bfd56f1e93daa6683f6f3b1eead0e90fc1ce5b65 - Sigstore transparency entry: 1785854466
- Sigstore integration time:
-
Permalink:
karta-sh/karta@d9f84c5d3c902ac45953f8e8f96791a3824db290 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/karta-sh
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d9f84c5d3c902ac45953f8e8f96791a3824db290 -
Trigger Event:
release
-
Statement type: