pinbox pin.
Everything else in pinbox is built on the pin: the thread hanging off it, the event that
announces it, the delivery that carries it to an agent.
The shape
Here is a real pin, straight out ofpinbox pin --json:
id, schemaVersion, status, createdAt, and stamps env.branch and
env.commit from git. You supply the rest.
Every field under
target and env is optional. A pin created with pinbox pin has no
browser, so it has no viewport and no bounding rect — pinbox records absence rather than
inventing browser: "cli". Read them by presence (pin.target?.rect), never by sentinel.Status is two values
On the wire,status is open or resolved. Nothing else. It is a versioned contract,
and keeping it to two values is what lets any client — the CLI, the toolbar, an agent, a
script you write this afternoon — agree on what a pin is.
Anything richer is derived from the pin plus its thread. The toolbar, for example,
computes its badge like this:
Build your own labels the same way: read
status, then look at the thread. Do not expect
new status values to appear.
Pins are conversations
A pin is a thread, not a ticket that flips a bit. Each thread message is:role is human, agent, or mirror (a message that came in from a linked tracker;
origin records where, e.g. github:someuser).
Two rules matter:
Replying never resolves. pinbox reply appends a message and leaves status alone.
Resolving is a separate, deliberate act — pinbox resolve, or a Resolves: pin_x trailer
on a commit. An agent that answers a question has not fixed anything yet.
A reply reaches the same agent session the thread started in. The first time a pin is
routed, the hub writes the session it went to into pin.agentSession. Every later message
on that pin follows that binding, so a back-and-forth stays with the agent that already has
the context loaded, instead of landing cold in whichever session happens to be newest.
CLI reference
pinbox pin, list, show, reply, resolve — flags, output, and exit codes.