Skip to main content

ffwf-tau-agent-core

The runtime of Tau, a programmable coding agent harness. tau_agent_core is the loop that drives a conversation: it calls the model, executes tools, appends entries to a session, dispatches extension hooks, and compacts context when it grows too large.

It is headless. No Textual, no stdout assumptions, and tau_agent_core never imports tau_coding_agent. Embed it in your own program, drive it as a subprocess over RPC, or run it under Tau's TUI.

Tau began as a Python port of the TypeScript project pi-mono, which is still read as the reference implementation when porting or debugging; it now diverges from pi deliberately in several places.

What is in it

  • AgentSession — the object you hold. The one door: every input source — TUI keystrokes, tau -p, the SDK, an extension, an RPC client — funnels through AgentSession.submit(). prompt() is a thin wrapper that builds a Submission and calls submit(), not a second door. Concurrent submissions have a stated policy (multitask_strategy: reject, enqueue, steer, rollback, fork) rather than an answer improvised per caller.
  • create_agent_session() — the SDK factory. Resolves a model name, built-in tool names, and extension callables into a working session.
  • Built-in toolsread, write, edit, bash, ls, grep, find.
  • Sessions are a tree, not a chat log. Entries are append-only; ConversationTree walks parent_id chains to build model input for the active leaf. Fork, branch, rollback, and running a second agent from an earlier point in the conversation all fall out of that structure instead of being bolted on.
  • Storage is a seam. SessionLog and SessionCatalog are protocols. An in-memory log ships here, a file store ships with ffwf-tau-coding-agent, and a JMFTS-backed store ships with ffwf-tau-jmfts.
  • Extensions are plain Python modulesimportlib, no compile step, no manifest language. They register tools and commands, subscribe to lifecycle events, mutate what the loop is about to do, carry per-extension config, and can veto a tool call.
  • Compaction is LLM-backed with no fabricated-summary fallback. A compaction error raises rather than silently truncating the conversation.
  • RPC — a versioned JSON-RPC 2.0 command surface, so τ can be driven as a process rather than imported.
  • Export — a session to Markdown or HTML.

Why it is a separate package

The runtime and the terminal interface are different concerns with different dependency footprints. Keeping them apart is what lets a server, a bot, or a test harness run the same agent without a UI toolkit in sight.

Install

pip install ffwf-tau-agent-core

Python 3.11 or newer. Pulls in ffwf-tau-llm.

Two extras, both off by default:

Extra Adds Needed for
ffwf-tau-agent-core[bus] nats-py the built-in nats_bus extension, which publishes to NATS subjects
ffwf-tau-agent-core[testing] pytest importing tau_agent_core.testing, the store contract suites

A plain install stays pytest-free and NATS-free.

Example

import asyncio
from tau_agent_core import create_agent_session


async def main():
    session = create_agent_session(
        model="gpt-4o",
        tools=["read", "grep", "bash"],
    )
    session.subscribe(lambda event: print(event.type))

    messages = await session.prompt("What files are in this directory?")
    for message in messages:
        print(message.get("role"), message.get("content"))


asyncio.run(main())

prompt() returns the messages produced by this turn, not the whole conversation. The full history lives in the session's SessionLog.

tools= takes built-in name strings only, and raises on a name it does not recognise. A custom AgentTool goes through the AgentSession constructor directly, or is registered by an extension.

Writing an extension

An extension is a module with a register callable that receives an ExtensionAPI. This one refuses a destructive shell command before it runs:

def permission_gate_tool_call(event, ctx):
    command = (event.get("input") or {}).get("command", "")
    if event["tool_name"] == "bash" and "rm -rf /" in command:
        return {"block": True, "reason": "destructive command refused"}
    return None


def register(api):
    api.on("tool_call", permission_gate_tool_call)

tool_call is a mutating hook, not a notification. Its return value is honoured, and a block becomes an error tool result the model can react to. Notify-only events such as tool_execution_start have their return value discarded and cannot stop anything — a gate written against one prints a warning and then lets the command run.

A module written this way loads from a path: tau -e permission_gate.py. The repository's examples/ directory holds around thirty working extensions.

Testing your own store

tau_agent_core.testing ships the conformance suites for the two storage seams, so a store written elsewhere can be held to the same contract. The contract is the code, not a document.

from tau_agent_core.testing import SessionCatalogContractTests, SessionLogContractTests


class TestMyLog(SessionLogContractTests):
    def make_log(self):
        return MyStore(...)


class TestMyCatalog(SessionCatalogContractTests):
    def make_catalog(self):
        return MyCatalog(...)

Install ffwf-tau-agent-core[testing] to import that module.

Docs

  • docs/tau-agent-core.md — design notes for this package.
  • docs/SUBMISSION-LIFECYCLE.mdsubmit() and the concurrency strategies.
  • docs/NODE-ADDRESSABLE-AGENTS.md — the session-tree invariants.
  • docs/extensions.md, docs/EXTENSIONS-WALKTHROUGH.md — the extension API.
  • docs/REMOTE-CONTROL.md, docs/RPC-PROTOCOL.md — driving τ as a subprocess.

Repository: https://github.com/jmccardle/tau

The rest of Tau

Distribution Imports as What it is
ffwf-tau-llm tau_llm the provider and streaming layer this sits on
ffwf-tau-coding-agent tau_coding_agent the tau command and the Textual TUI
ffwf-tau-jmfts tau_jmfts a JMFTS-backed session store

MIT © Fight Fire with Fire Robotics, LLC

Download files

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

Source Distribution

ffwf_tau_agent_core-0.9.2.tar.gz (846.0 kB view details)

Uploaded Source

Built Distribution

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

ffwf_tau_agent_core-0.9.2-py3-none-any.whl (441.3 kB view details)

Uploaded Python 3

File details

Details for the file ffwf_tau_agent_core-0.9.2.tar.gz.

File metadata

  • Download URL: ffwf_tau_agent_core-0.9.2.tar.gz
  • Upload date:
  • Size: 846.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.2

File hashes

Hashes for ffwf_tau_agent_core-0.9.2.tar.gz
Algorithm Hash digest
SHA256 b4b2d3f4ab7611fb1391e55276956832350004689d0ab3b6d967d2d11909bc9a
MD5 c3e236dab061491b0ee08ab0537802fc
BLAKE2b-256 77f8400ed81880b4d0b64b110ec2905aea48f84087684126168bb4f9648337a5

See more details on using hashes here.

File details

Details for the file ffwf_tau_agent_core-0.9.2-py3-none-any.whl.

File metadata

File hashes

Hashes for ffwf_tau_agent_core-0.9.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f9f86cc971987a1f7e19b92689d9a0e9a6032d844cdb4cb8fc8789f6a16cadea
MD5 2ea455fae59f8efdda37dbadd9afa1f1
BLAKE2b-256 40f090ac39f6c78dc49e74c417ee8b7514deb3d5c649ef2c00fd1b015de20e49

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.9.2 This release

2 files

Supported by

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