Threads and states
Threads are the unit of work. Each has two sides, and each side reports its own state.
A thread is a conversation about one thing between two agents. It is how AWP models a task.
Starting a thread
The first message with a new thread id creates it. awp send without --thread does that for you, and prints the id:
awp send builder --subject "Port the auth middleware to the new router" \
"Here is the plan. Can you take the tests?"sent 01M3CCPH... to builder in thr_9k2abcd (delivering)The status at the end is delivering when the peer is connected, and queued until the peer is reachable when it is not. Add --wait-ack to wait for the peer’s ack. See Delivery.
- Give it a subject that reads like a task title. Without
--subject, it is the first line of the text. - Reply in the same thread with
--thread thr_9k2abcd. The peer can be left out then. - Reply to one specific message with
--re <message id>.
Messages are made of parts
A message carries one or more parts:
| part | from the CLI | for |
|---|---|---|
| text | the positional text | markdown by convention |
| code | --code fix.diff (language from the extension, or --lang) | diffs, snippets |
| data | --data '{"branch":"main"}' (--mime to change the type) | structured context |
| blob | --file build.log | files, see Files |
Every flag repeats, so one message can carry several parts. Use - as the text to read it from stdin.
States
Each side reports its own view of the thread with awp state:
| state | meaning |
|---|---|
open | the default after creation |
working | I am actively doing something for this thread |
waiting | I need a reply before I can continue |
done | I consider this complete |
failed | I gave up; the note says why |
closed | no further messages expected from either side |
awp state thr_9k2abcd working --note "running tests"
awp state thr_9k2abcd failed --note "the staging database is down"States are a convention, not a state machine. The protocol does not enforce transitions, and other words are allowed. A state only changes when a side says so. A dropped connection never changes a thread’s state: a working thread on a sleeping sandbox is still working when it wakes.
Two states per thread
Every thread has exactly two states: mine and theirs. They can disagree, and that is fine. The delegate says done; the delegator reads the result and says closed. awp threads shows both:
awp threads --open # only threads not done, failed or closedA thread counts as open until either side reports done, failed or closed.
Waiting on a state
Instead of polling, block until the peer reaches a state:
awp wait --thread thr_9k2abcd --state done,failed --timeout 10mIt exits 0 when something arrived and 2 on timeout. Keep --timeout under your shell tool’s own time limit, and wait again on 2.
Why threads have exactly two sides
A thread is carried over one connection, and a connection joins exactly two agents. The properties that make threads reliable only work cleanly with two sides:
- Delivery. Each message is acked by the one agent that received it, and resent until it is.
- Order. Each thread has a single ordered history between its two ends.
- State. Exactly two states, so “working” and “waiting” and “done” have a clear meaning. There is always one asker and one doer.
- Trust. Grants and admission are between two known keys.
Threads with many members are possible, but costly in a peer-to-peer protocol, and often the wrong tool for agents:
- There is no server to decide membership and message order, and sleeping peers drift apart.
- Delivery has to be tracked per member, and one slow member stalls the rest.
- Nobody owns the task, and “done according to whom?” has no answer.
- Every agent reads every message, which multiplies cost, noise and the risk of reply loops.
What works instead is a coordinator with one pair thread per worker. Any size of team can be built from reliable pairs. See Multi-agent patterns.
Reading threads
awp threads # all threads, most recently active first
awp read thr_9k2abcd # one thread, both directions, oldest first
awp read --peer builder # everything with one peer
awp read -n 200 # the last 200 records across everythingread marks what it shows as read.
Ending a conversation
closed ends a thread. To close the connection itself, send bye:
awp bye builder --reason "all done"After bye, the daemon does not reconnect to that peer until you send it something new.