Skip to main content

karta-runtime

The Karta runtime: harness adapters, sessions, and the consumer session API on agent harnesses like Claude Code and OpenCode

GitHub License PyPI Version Python Version GitHub issues

Looking for the karta command? The public CLI is @karta.sh/cli (npm install -g @karta.sh/cli). This package is karta-runtime - the internal engine that CLI bootstraps for karta 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 response
  • POST /v1/stream — send a message, get SSE stream
  • POST /v1/sessions — create a session
  • GET /v1/sessions — list/lookup sessions
  • POST /v1/sessions/{id}/messages — send within a session
  • POST /v1/sessions/{id}/input/respond — respond to approval prompts
  • POST /v1/gateway/submit — submit a gateway event
  • POST /v1/gateway/deliver — deliver to a local participant
  • GET /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/*.md or .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

Adding a new harness means implementing one HarnessAdapter class.

Documentation

Design documents and implementation specs live in dev/:

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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

karta_runtime-0.6.29.tar.gz (515.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

karta_runtime-0.6.29-py3-none-any.whl (592.0 kB view details)

Uploaded Python 3

File details

Details for the file karta_runtime-0.6.29.tar.gz.

File metadata

  • Download URL: karta_runtime-0.6.29.tar.gz
  • Upload date:
  • Size: 515.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for karta_runtime-0.6.29.tar.gz
Algorithm Hash digest
SHA256 abbab29835b2f1c1575cdb3fd9afa9e86b898801d5d64135376cdfb5c68bf838
MD5 b931b8b0cda96923b43067d22cfaae59
BLAKE2b-256 3c9be181ed41e4f48463876da01bf33e3d48dd5cfe6a102c6669ee3698d507ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for karta_runtime-0.6.29.tar.gz:

Publisher: publish.yml on karta-sh/karta

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file karta_runtime-0.6.29-py3-none-any.whl.

File metadata

  • Download URL: karta_runtime-0.6.29-py3-none-any.whl
  • Upload date:
  • Size: 592.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for karta_runtime-0.6.29-py3-none-any.whl
Algorithm Hash digest
SHA256 5984d13588af97920d438d791f9c9ac65f4f6305391e301aa18760181919cc67
MD5 5b7c4fe5d56802de8b29a87fdf68586b
BLAKE2b-256 ee989856ff653266c89487d704aabb777b931279d100cfa71e93a818c19bd89d

See more details on using hashes here.

Provenance

The following attestation bundles were made for karta_runtime-0.6.29-py3-none-any.whl:

Publisher: publish.yml on karta-sh/karta

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page