tantra
The agent turn loop as a library. Install name tantra-harness, import name tantra.
What it is
- The harness owns the loop — sampling, tool dispatch, permissions, approval/suspend-resume, subagents, compaction, persistence. You supply an
Agent(a declarative class of values and function references) and run turns against it. - Tools, hooks and skills plug in. An
Agentdeclarestools; aHarnesstakeshooksand aSkillssource. - Agents hold no live I/O. A resume can run in another process and look the agent up by name from the persisted session header.
- Configuration is explicit construction: tools are built by factories (
web_search(api_key=...)) in your own module, so keys are per-agent and a misconfiguration fails at construction, not mid-turn. The library never reads the environment. - Shipped tools live under
tantra.extratools.*and their dependencies are extras, so the base install stays light —pydantic,httpx,openaionly. The shell tools are stdlib and need no extra.
Install
| Command | Adds |
|---|---|
pip install tantra-harness |
core + tantra.extratools.shell (bash, ShellGuard) |
pip install "tantra-harness[web]" |
web_search (Brave) + web_fetch |
pip install "tantra-harness[doc]" |
read_doc for PDF / docx |
pip install "tantra-harness[postgres]" |
the psycopg driver that PostgresStore needs at use time; the class itself imports without it |
pip install "tantra-harness[telemetry]" |
tantra.telemetry.Telemetry — OpenTelemetry tracing for Harness(telemetry=...) |
pip install "tantra-harness[web,doc]" |
combine freely |
Import-name collision. The unrelated PyPI project tantra also installs an import tantra. Installing both into one environment clobbers the import silently. Do not co-install them.
Basic usage
import asyncio
from tantra import Agent, Harness, OpenAICompatible, SQLiteStore
from tantra.extratools.doc import read_doc
from tantra.extratools.shell import ShellGuard, bash
from tantra.extratools.web import web_fetch, web_search
from tantra.providers.base import TextDelta
class Researcher(Agent):
model = "gpt-5"
prompt = "You answer questions using the web, local documents and the shell."
tools = [bash(), web_search(api_key=BRAVE_API_KEY), web_fetch(), read_doc()]
permissions = {"bash": "allow"}
async def main() -> None:
store = SQLiteStore("sessions.db")
await store.setup()
harness = Harness(
OpenAICompatible("https://api.openai.com/v1", OPENAI_API_KEY),
store,
[Researcher],
hooks=[ShellGuard()],
)
session = await harness.create_session(Researcher)
async for emitted in harness.run(session.id, "What changed in Python 3.13?"):
if isinstance(emitted.event, TextDelta):
print(emitted.event.text, end="", flush=True)
asyncio.run(main())
Notes on the snippet:
harness.run(...)is an async iterator ofEmitted. The turn only advances while the stream is consumed;tantra.collectdrains it into a list.bashdeclarespermission="ask", so a headless run must override it — hencepermissions = {"bash": "allow"}. Globs work ("web_*": "allow").ShellGuard()denies destructive commands with a reason the model sees.ShellGuard(on_trip="ask")escalates to the human approval flow instead. It is a guardrail, not a sandbox.
Docs
Reference apps
apps/sarthiin apps/sarathi — a fully usable Perplexity clone with multi tanancy, memoery, parallel agents, web search built inapps/agniin apps/agni — a terminal coding agent built on this library: REPL, permission prompts, skills, memory, compaction.
License
Apache-2.0
Metadata
Release files for tantra-harness 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tantra_harness-0.4.0.tar.gz | 177.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tantra_harness-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 261.9 kB
Release files / tantra_harness-0.4.0.tar.gz
| Download URL | tantra_harness-0.4.0.tar.gz |
|---|---|
| Size | 177.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88b0ddc4d2fa548ee9ddfc3227aad13cb4ba47b445a9a8daba2f10e1b386a1fe
|
|
BLAKE2b-256 checksum How to use checksums |
c72af02831331f5373a7e01ce24915799601ce31f6dccd0fefbe849e208743d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.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 Aug 22, 2026.
Transparency logRelease files / tantra_harness-0.4.0-py3-none-any.whl
| Download URL | tantra_harness-0.4.0-py3-none-any.whl |
|---|---|
| Size | 84.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fcbe1f509509bb51d9089c816d6ebe3b36165c190bdeee50b86c3c55d393460c
|
|
BLAKE2b-256 checksum How to use checksums |
6d815fe0c367a2e82e4d057bff656aaf6f05d4691fb6d21013518ceaba784603
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.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 Aug 22, 2026.
Transparency log