Autonomous work stays understandable because every piece of work has a durable thread, an explicit owner, a precise wait state, and links back to the work that started it.
Where a thread lives
Every piece of work is a thread, and each thread sits in one of the three tabs (see Desktop app):
- Conversations — you and a companion, talking. These are yours to drive.
- Activity — the companion working on its own: peer companions, scheduled runs, Slack and email handled in the background. It behaves like an inbox — read threads hide by default.
- Thoughts — retained introspection, analyses, and dream narrations that the companion chose to carry forward after reflection — not raw hidden reasoning.
The rule of thumb: Conversations need you, Activity does not — until it does.
A graph of work, not a stack of chats
Threads can form a directed graph instead of becoming disconnected tasks:
spawned_fromrecords provenance when a thread creates a separate piece of work. An exploration can spawn an implementation thread; an implementation can spawn a peer review or a focused companion consultation. The child remains linked to the thread that caused it.blocked_byrecords a real dependency. A thread can wait on one or several specific threads and only resumes after every open blocker has reached a terminal state.
Parent and child links remain visible and navigable in the context panel even after either thread resolves. The originating companion can also recover a compact summary of the parent when a child resumes, so delegation keeps the reason for the work as well as its result.
In the sidebar, each tab shows its own collapsible projection of that family. The rows stay flat rather than becoming an indented tree, and a visible child can lead the group when the original parent is hidden or belongs to another tab. Each member still follows its own lifecycle: one child can surface in Conversations for a human decision while its parent and siblings remain in Activity or Thoughts.
This means tamag0 retains what started the work, which thread owns the next step, what is still blocking it, and what eventually landed — not only the final answer from an opaque task launch.
Every wait names what owns the next move
The app uses plain labels in the interface, while the durable lifecycle distinguishes the following states:
| State | What owns the next move | How work resumes |
|---|---|---|
active |
The companion | Work is live: the companion is running or ready to take the next step. |
awaiting_human |
A human | A reply, approval, or judgment is required. An agent-created thread surfaces in Conversations so it cannot wait unnoticed. |
awaiting_agent |
The owner companion | The companion needs to resume — for example after a peer reply, a completed child, or a watchdog wake. The dispatcher wakes the owner. |
awaiting_thread |
One or more named threads | When every open blocked_by thread becomes terminal, the parent moves to awaiting_agent and its owner is woken. |
awaiting_external |
A registered external event | CI, a pull-request state, deployment, webhook, or timer is monitored without keeping a companion process busy. When the event fires, the owner is woken; if its deadline expires, the wait is surfaced for human attention. |
resolved |
Nobody | The outcome was delivered. The thread is terminal but its history and links remain available. |
closed |
Nobody | The thread was deliberately hard-closed and no further processing is expected. |
abandoned |
Nobody for now | Work stopped without a conclusion after becoming stale or repeatedly failing to resume. It is set aside rather than left pretending to be active, and can be revived when work restarts. |
The important distinction is not technical vocabulary but accountability: human reply, companion action, thread dependency, and external event are four different waits. A thread never has to say only “pending” and leave everyone guessing who should act.
When a thread needs your attention
A companion working autonomously in Activity will sometimes reach a decision that belongs to you — an approval, a direction, or a judgment call it should not make alone. It moves to awaiting_human and surfaces in Conversations, in front of you rather than hidden in background activity.
The reverse also holds. A thread that no longer needs you can wait on its companion, a linked thread, or a registered external signal in Activity. It returns only when there is a real human decision to make.
This is the signal to trust: anything that needs a decision from you comes to Conversations. You do not need to inspect every autonomous thread just to find out whether one needs a reply.
How linked work resumes
Thread dependencies are event-driven:
- A parent records the child threads that block it and enters
awaiting_thread. - Each child continues independently and can exchange several messages before finishing.
- Whenever a child reaches
resolved,closed, orabandoned, tamag0 checks the parent's remaining open blockers. - Only when none remain does the parent move to
awaiting_agentand wake its owner companion. - The companion resumes in the original thread, with the linked children still available for inspection.
A defensive watchdog also detects an inconsistent awaiting_thread with no open blocker and returns it to its owner instead of leaving a zombie wait. See Scheduled tasks & watchdog.
When a thread resolves
A thread resolves when its work actually lands — a pull request opened, a message sent, a document produced and handed to you, or a requested decision delivered — not merely because the companion declared itself finished. Delivery, not self-assessment, is the useful meaning of “resolved.”
In Conversations and Activity, resolved, closed, abandoned, and archived threads are hidden by default to keep the sidebar clean, except when they are unread: unread terminal threads remain visible so an outcome cannot be missed. Show resolved adds terminal threads to the current view with their messages and links; Hide read and other active filters still apply.
Desktop builds that support resolved-thread cleanup can reclaim workspace storage by removing cloned Git repositories from a resolved thread's working folder only when they verify that the repository is clean and reconstructible. Repositories with uncommitted work, local Git data, or an unverifiable state are kept intact by this resolution-time cleanup.
This is separate from workspace retention: stale thread folders may be removed after 30 days regardless of their Git contents. Keep any work you need outside a thread's working folder before that retention period expires.
Staying oriented
The sidebar and context panel are built for triage across many threads at once:
- Unread counters per tab tell you where new activity is.
- Collapsed family dots show that a descendant has unread activity even when its row is hidden inside the group.
- Hide read keeps Activity behaving like an inbox — only unread, running, and escalated work stays in view.
- Filters and search work by companion, domain, and full text.
- Awaiting indicators distinguish a human or external wait; internal companion and thread waits stay visually quiet because they require no human action.
- Linked threads preserve provenance and let you move between parent and child work, including completed threads.
Subtree deletion is guarded by a fresh impact count. If a child appears after the confirmation opens, tamag0 cancels that attempt, shows the updated count, and waits for a second explicit confirmation instead of deleting a larger family silently.
The result: you do not monitor companions. Conversations shows what needs you, Activity carries what does not, and every autonomous wait has an explicit resolver.