Skip to main content

dharta-runtime

The Dharta 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 @dharta/cli (npm install -g @dharta/cli). This package is dharta-runtime - the internal engine that CLI bootstraps for dharta 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 Dharta

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.

Dharta 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.

Dharta 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          │  Dharta                      │
│                            │                              │
│  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 Dharta 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 Dharta instances communicate via gateway HTTP POST
Multi-tenancy Workspace-per-user isolation with DhartaHub 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 dharta-runtime dev/dev-serve/serve - streaming terminal REPL and the local/self-host serve planes (the public CLI is @dharta/cli)
Typed streaming Structured events: text, tool_use, reasoning, step_start, step_finish, error, input_required

Install

pip install dharta-runtime

With optional backends:

pip install dharta-runtime[postgres]   # PostgreSQL sessions
pip install dharta-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 dharta import Dharta

app = Dharta()
response = app.send_sync("Hello!")
print(response.text)

Dharta auto-detects your harness from the project directory (.claude/ → Claude Code, .opencode/ → OpenCode).

Multi-turn sessions

from dharta import Dharta

app = Dharta()

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 dharta import Dharta

app = Dharta()

# 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 dharta import Dharta, HumanAgent

app = Dharta()
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 dharta import Dharta

async def main():
    app = Dharta()
    async for event in app.stream("Explain quicksort"):
        if event.type == "text":
            print(event.text, end="", flush=True)

asyncio.run(main())

HTTP API

from dharta import Dharta
from dharta.server import create_fastapi_app
import uvicorn

app = Dharta()
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 dharta import DhartaHub

hub = DhartaHub("/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 = Dharta()

@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 @dharta/cli; this package's verbs are internal (local platform dev, self-host):

dharta-runtime dev <path>         # Hot-reload REPL against a folder
dharta-runtime dev-serve <path>   # Serve a folder behind the consumer session API
                                 # (what the unified CLI's `dharta dev` spawns)
dharta-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 @dharta/cli). It was dropped rather than shimmed: dharta-python never shipped to PyPI, so there is no installed base to point anywhere.

Architecture

                 External Clients / Other Dharta Instances
                              │
                    ┌─────────▼──────────┐
                    │     Gateway         │  event ingestion, fan-out delivery
                    │  Local · HTTP       │  cross-instance messaging
                    └─────────┬──────────┘
                              │
                    ┌─────────▼──────────┐
                    │   Client Layer      │  HTTP API · CLI · Python SDK
                    └─────────┬──────────┘
                              │
                    ┌─────────▼──────────┐
                    │   Multi-Tenancy     │  DhartaHub → WorkspaceManager
                    └─────────┬──────────┘
                              │
                    ┌─────────▼──────────┐
                    │    Dharta 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 Dharta

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

Dharta uses your harness's native agent definitions as the source of truth. Optional Dharta-specific settings go in dharta.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/:

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/dharta/

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

dharta_runtime-0.6.77.tar.gz (2.4 MB view details)

Uploaded Source

Built Distribution

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

dharta_runtime-0.6.77-py3-none-any.whl (2.6 MB view details)

Uploaded Python 3

File details

Details for the file dharta_runtime-0.6.77.tar.gz.

File metadata

  • Download URL: dharta_runtime-0.6.77.tar.gz
  • Upload date:
  • Size: 2.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dharta_runtime-0.6.77.tar.gz
Algorithm Hash digest
SHA256 8afc5740e46eefa3e3d8cf0fc5159cc51b335f4d65ee765aced4248c481de5bd
MD5 7cd2946a3d7c215817b2a953ab608599
BLAKE2b-256 48114f6ae2b29657297b739635dce91d78c429ba4a8aabc8fc3fd44025772f4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for dharta_runtime-0.6.77.tar.gz:

Publisher: publish.yml on dharta-ai/dharta

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

File details

Details for the file dharta_runtime-0.6.77-py3-none-any.whl.

File metadata

File hashes

Hashes for dharta_runtime-0.6.77-py3-none-any.whl
Algorithm Hash digest
SHA256 c7c233fe6973ce7097fd9f452c1b40faff89c5699a451b89690e092fb4705168
MD5 20db2906555fc2cbfbc708ec160bf460
BLAKE2b-256 2a7d87fb81c72901567cdb75f32ceb32b7efb58ad175feb452d1b11e27c16db5

See more details on using hashes here.

Provenance

The following attestation bundles were made for dharta_runtime-0.6.77-py3-none-any.whl:

Publisher: publish.yml on dharta-ai/dharta

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

Release history Release notifications | RSS feed

0.6.78

2 files

This release

0.6.77 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page