tau-sub
Sub-taus: small, named specialists of your tau. A workout coach (/coach), a landing-page
writer (/landing), a helper for the robot arm: each is tuned to one job, used on its own or
asked by the main tau. A sub-tau is not a second hub or a second identity; it shares your
tau's hub, spine and address (ADR 0012).
It is its own distribution (tau-sub, import tau_sub), uses only the public API of
tau-core and plugs in through three entry points:
| group | name | what |
|---|---|---|
tau.commands |
sub |
tau sub … |
tau.tools |
sub |
ask_sub (tier 0), create_sub (tier 2) |
tau.subs |
sub |
the public sub-taus, for tau-net (see "Public sub-taus" below) |
What a sub-tau is
Each sub-tau has:
- a name, a slug matching
^[a-z][a-z0-9-]{1,30}$, shown as/name;net,app,api,auth,claimandhubare reserved, because a tau's host serves those paths itself (ADR 0013); - a persona: its character and its task instructions;
- an about line, at most 200 characters;
- a model role:
brain(default),fastorlocal; - a tool allowlist: names from the tool catalog (
tau components), empty by default; - a
publicflag, false by default: a public sub-tau answers your contacts over the tau network and is listed in the universe (see "Public sub-taus" below); - a page for a public sub-tau, off by default: with
web = trueanonymous visitors can talk to it on its universe page, at mostweb_dailyvisitor turns per UTC day, andstartersare the suggested first messages there (see "Web pages" below); - its own sessions, on the channel
sub:<name>.
The definition file
persona/subs/<name>.md under TAU_HOME (gitignored in the tau repository, like
persona/user.md): TOML front matter between two +++ lines, then the persona text.
+++
about = "A strict but kind workout coach who plans three short sessions a week."
role = "brain" # brain | fast | local
tools = ["current_time"] # names from the tool catalog
public = false # true: contacts reach it as <address>/coach
# public_note = "coach.public.md" # optional: a file next to the definition
# web = false # true: visitors talk to it on its universe page
# web_daily = 50 # visitor turns per UTC day, 1 to 1000
# starters = ["Plan my week"] # up to 4 suggested first messages, 1 to 80 characters
+++
You plan the owner's workouts: three sessions of 20 to 30 minutes a week, ...
- The front matter is parsed with
tomlliband never reaches the model. Unknown keys, wrong types, an unknown role, anaboutover 200 characters, an empty persona and every tool name that is not in the catalog are errors; an unknown tool is named in the error. ask_subandcreate_subare never allowed in an allowlist, so a sub-tau cannot call or create other sub-taus.- HTML comments in the persona are notes for you, like in
persona.md. - A
public_noteis a.mdfile inpersona/subs/whose name is not itself a sub-tau name (the convention is<name>.public.md). webis a boolean,web_dailya whole number from 1 to 1000 (default 50) andstartersa list of at most 4 texts of 1 to 80 characters (collapsed to one line, duplicates dropped).webonly takes effect withpublic = true;tau sub showsays so.- Files are written atomically with mode 0600 in a 0700 directory and never overwritten
without
--force.examples/coach.mdis a complete example with made-up content.
The prompt
The model reads:
You are /<name>, a specialist of your owner's tau: <about>. Stay within this task; say so
when a request is outside it.
<the persona text>
## User
<persona/user.md>
## Now
<the dynamic context: time, profile, host role, live nodes, budget>
tau-core's PersonaLoader reads a persona file and user.md and knows nothing of front
matter, so the first two parts are rendered into a derived file,
TAU_DATA_DIR/subs/<name>/persona.md (0600), rewritten only when the definition changes. The
loader keeps its hot reload: tau sub chat re-reads the definition before every turn, a new
persona applies from the next turn, and a new role or allowlist rebuilds the agent on the
same session.
Commands
tau sub new coach --describe "a strict but kind workout coach that plans three short sessions a week"
tau sub new landing --about "Writes landing-page copy." --tools current_time # a template to edit
tau sub new coach --public --web --web-daily 30 --starter "Plan my week" --starter "I missed a run"
tau sub list # name, role, tools, public, last session
tau sub show coach
tau sub edit coach # opens $EDITOR, then checks the file
tau sub ask coach "plan my week" # one turn
tau sub chat coach # a conversation; /tools /new /session /quit
tau sub chat coach --new # a fresh session
tau sub remove coach # the definition only; sessions are kept
new --describeasks thebrainrole for a draft ({about, persona, tools}), shows it and asks before writing (--yesskips the question). The drafter gets the tool catalog without tier-2 tools and never seesuser.md; proposed tools that are unknown, forbidden or tier 2 are left out and listed (--allow-tier2keeps tier-2 tools, which still ask for approval on every call).--about,--role,--tools,--publicand the page options win over the draft.new --webneeds--public;--web-daily N(1 to 1000) and--starter TEXT(repeatable, at most 4) are checked before anything is drafted or written.showprints the page settings;editchecks them like every other field.chatandaskcontinue the sub-tau's last session, remembered inTAU_DATA_DIR/subs/<name>/session;--newstarts a fresh one.
Tools for the main tau
ask_sub(name, question), tier 0: runs the sub-tau for one turn, on a new session of its own, and returns its answer. An empty name lists the sub-taus.create_sub(name, about, persona, tools), tier 2, effect "Creates a new sub-tau of your tau that can use the listed tools.": validates liketau sub newand never overwrites.
Safety rules
- The tier gate stays the only way a tool runs. A sub-tau's agent comes from
tau_core.build_agentwith exactly its allowlist; a tool outside it is refused as unknown. - A tier-2 tool asks for approval on every call:
- in
tau sub chat, on the terminal; - in
tau sub ask, on the terminal when stdin is one, and refused otherwise; - through
ask_sub, with the approver of the turn that called it, so the owner answers on the channel the conversation came from (terminal, TUI, Telegram), and the approval names the sub-tau. The tool finds that approver through its Strands tool context (the calling agent's tier hook). When there is none, every tier-2 call of the sub-tau is refused and the answer says that tier-2 tools needtau sub chat.
- in
- Nothing approves on the owner's behalf, in the code or in the tests (
ScriptedApprover). create_subis tier 2: a new sub-tau is a new agent configuration that may use tools.- A sub-tau cannot call
ask_suborcreate_sub, so delegation is one level deep. - A remembered session that belongs to another channel is ignored: a sub-tau never continues the main tau's history.
Public sub-taus
public = true lets your contacts on the tau network reach a sub-tau directly, as
<address>/<name> (tau net send alice.example.com/coach "…"); the sealed message carries
"sub": "coach" (protocol reference, docs/reference/tau-network.md §3 and §6.4):
- A public sub-tau answers with the same narrow network turn as the main tau: its persona (the
header and persona text above) and, as the
## Usersection, itspublic_note, or your tau's public note (persona/net.md) when it names none. Neverpersona/user.md, never the tools of its allowlist, no approvals, and the samemax_hopsand hourly cap per contact. - Each contact gets its own session with it, titled
tau network · <name> · /coach, on the model role of the definition. Its answer carries/coach, and a reply to it goes back to/coach, so the thread stays with it. - A message for a private, unknown or invalid sub-tau is dropped and logged, like one from a stranger, and never answered. Making a sub-tau private takes effect with the next message.
- While your tau is in the universe, each report lists your public sub-taus (
{name, about}, at most 20) and the page draws them inside your hull. Private sub-taus never leave the hub.
tau-net does not import tau-sub. It finds the sub-taus through the tau.subs entry point:
tau_sub.network:public_subs(config) returns a PublicSubs directory whose public(name)
and public_subs() give plain PublicSub records (name, about, role, persona_file,
public_note_file, web, web_daily, starters). Without tau-sub installed, a hub has no
public sub-taus.
Web pages
A public sub-tau with web = true gets a chat page on the universe (ADR 0013 §5), for
anonymous visitors, who have no key and no card:
- The universe relays a visitor's message to your hub as a signed
visitenvelope under its own network identity. Your hub accepts it only from the universe it joined (its key pinned at the first visit), only for a sub-tau withpublicandweb, and only while the sub-tau has visitor turns left today (web_daily, counted per UTC day on the hub). - The sub-tau answers with the same narrow network turn as for a contact (its persona, its
public note, no
user.md, no tools, no approvals), framed as a message from an anonymous visitor of its public page. A visit creates no contact and counts toward no universe link. - Each report lists
webandstarterswith every public sub-tau, so the page can show the chat box and the starter chips. - Visitor turns cost your model budget, which is why the page is a separate flag with a daily cap. Visitor chats are not end-to-end private: the universe sees them to relay them.
Development
uv run pytest packages/tau-sub -q
uv build --package tau-sub
Metadata
Release files for tau-sub 0.1.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 | |
|---|---|---|---|
| tau_sub-0.1.0.tar.gz | 48.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tau_sub-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 87.7 kB
Release files / tau_sub-0.1.0.tar.gz
| Download URL | tau_sub-0.1.0.tar.gz |
|---|---|
| Size | 48.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
43d8ea868a6d61be0d8369938615f8acd15fd4d31602c41ac7bf76645942f419
|
|
BLAKE2b-256 checksum How to use checksums |
9d25c0d5f84974cd9bb196fea1bd62e95458c549addfc985ab2063c005fdce8f
|
| 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 Sep 30, 2026.
Transparency logRelease files / tau_sub-0.1.0-py3-none-any.whl
| Download URL | tau_sub-0.1.0-py3-none-any.whl |
|---|---|
| Size | 39.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5aa9bb5a80974afc2cc6e8caa64c6604fdfe869add30db3935acdd6a88a2b833
|
|
BLAKE2b-256 checksum How to use checksums |
286d574c30281616fe40fd704b4654cb4265ff45ac26ad008f985d7b69bacdde
|
| 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 Sep 30, 2026.
Transparency log