Skip to main content

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

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

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.

Project 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.1.0.tar.gz (196.8 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.1.0-py3-none-any.whl (236.1 kB view details)

Uploaded Python 3

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

Hashes for karta_runtime-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9dd66169c19bf407bdab90f6e8f81ad98d2050e9796ff4c2528da67b95122426
MD5 7578a32d8e76056236cbb3f331187fe7
BLAKE2b-256 59d46a6620caca6ebea1fe6db4e7ef651a4f86231a8568c9a48ef075f7e4ea51

See more details on using hashes here.

Provenance

The following attestation bundles were made for karta_runtime-0.1.0.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.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

Hashes for karta_runtime-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b8998666aa04aa8fb91d4000bfd56f1e93daa6683f6f3b1eead0e90fc1ce5b65
MD5 d145a9250fda3c6437af887d4d4075bf
BLAKE2b-256 9fa07c0b6feb0eabb2fd21c999b5f1a9bc42c4d6dba5b8c373cabffd6b8e8db2

See more details on using hashes here.

Provenance

The following attestation bundles were made for karta_runtime-0.1.0-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.

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