Board
One project’s task board, opened as a takeover at
/board/{org}/{project}: a slim bar, the rows waiting on the reader, the
project’s cards in lanes by state, and the line that cuts a new row. The
fleet stays the glance; this is the world. Nothing of any other project
appears here. The drawing it is held against is
web-board.html, beside this page.
It is reached from two doors: open board on the project’s row on the
home, and the tasks strip in a session’s chat, which carries
open board first in its list. Both open the same page. back and done
return the reader where they came from, and a deep link with nothing to go
back to lands on the home.
The page draws from the board subject: a project’s rows, schedules and
connector sets ride in that subject’s entry, and it hears the updates that
move them. The seat chips and the fleet’s waiting on you count come from
the home snapshot beside it; the row and running counts are the board’s own.
So a seat that claims a row, a row that is cut, or a move made in another view
arrives as an update, and the page re-reads without the reader doing
anything. While it is mounted it also re-reads on a slow 30 s beat:
a row’s age, its worked time and the marks read off them move with the clock,
and no update announces that.
What it draws
| Region | Shows | Read from |
|---|---|---|
| Top bar | back, the project’s name with its own read (N waiting on you, N rows, N running), done | the route and the snapshot |
| Seats | one chip per seat this project holds, linking to its session page; a card dropped on one assigns it | agents filtered to the project |
| Waiting on you | the rows whose wait is a decision, each card leading with the wait’s ask: the verify gate (approve, a words box, send back) on a row minted verify: user, or a worker’s question (an answer box), with the row’s links and a look’s artifact beside it. A root whose children are not all done draws the count and the send-back instead of approve, because a row closes only when its children do | waiting_on with kind: decision (a verification park only where the row’s own verify is user), the wait’s detail, the row’s links, and the row’s rollup |
| Lanes | every card, in its state’s lane, with the grown groups folded - the finished ones to their five most recent, Backlog to its ten | the board’s projects[].rows |
| Create | a subject box, an epic picker and + add, which files the row at the queue’s end | task_create |
The lanes
Six lanes, always drawn in this order, because a missing lane would read as
a missing state: Backlog (pending), Waiting, In progress,
Completed, Failed, Canceled. The pool of everything not yet
started leads, then the lane that wants the reader, then the work. Backlog is
the pending status: work kept to look at later, not by itself an assignment
and not a promise to start. Its ready, unowned cards are the dispatch queue,
not a promise to run. A lane is a name, its count and a rule, with its cards
under it - no box around the column - and the lanes wrap to a second row
rather than scroll sideways.
The grown groups fold. A finished row accumulates for the life of the
project and a queue accumulates for the life of the work, so Completed,
Failed, Canceled and Backlog are the lanes that grow without bound. The three
finished groups draw their five most recently finished rows - by when they
last moved, whatever their place in the lane - and the Backlog draws its top
ten, larger than the finished groups’ five because the queue’s order is the
lead’s dispatch order and the head of it is what stays in view. The rest of
each group waits behind a show all (N) control under the last card. N is
the lane’s true count, which the head carries whether or not the group is
open; pressing the control draws every row and it reads show less, and a
group at or under its limit draws whole with no control. A card the reader is
dropping into a folded group stays drawn while the core’s answer is in
flight, and a jump aimed at a folded row - an epic pill, a row page’s task
list - opens the fold and lands on it. In progress and Waiting never fold: they
are the live work.
A card
Three lines, top to bottom:
- the mark, then the subject. A row in progress displays its
active_formwhere it has one, with the subject under it, because that is what the reader wants to know - subjects are what a row is, active forms are what it is doing. A completed row’s subject is struck through. - the owner (their initial in a disc, linking to their session page, or
unclaimed), the epic it belongs under where it has one, its links, and its chips - with adone/totalrollup beside them on a parent. - worked time against the estimate with the measure under it, and how long
since the row last moved (
wrote 12s ago, breathing while the row is running and recently wrote).
The tree reads in two marks. A parent’s card wears an epic pill and a
solid left spine; each child wears the epic’s name in a pill with a return
arrow and a dimmer spine, so a tree reads across lanes at a glance and the
board still works without colour. The child’s card pill is a door: it brings
the epic’s own card into view and flashes it. On the row’s page the same pill
is a label, and the doors there are the tasks it lists - what a parent’s
tasks are, and how to reach one, lives on that page.
The mark carries shape as well as colour, so the board reads without colour:
| Status | Mark | The state |
|---|---|---|
| Pending | a ring | queued, not started |
| In progress | a filled accent dot | a seat is on it |
| Waiting | a warning square | a wait, a question or the verify gate |
| Completed | a tick | done |
| Failed | a cross | it ended in failure |
| Canceled | a dim bar | withdrawn, kept for the record |
The chips are the server’s derived marks, named in words:
| Chip | Tone | Means |
|---|---|---|
waiting on you | warn | a decision wait, or a look park on a row minted verify: user |
on <row> | warn | waiting on another row’s completion |
waiting on a resource | warn | waiting on something outside the board |
waiting | warn | a verification wait whose row carries no own gate: an inherited park, left behind by the old rule |
waiting <3h> | bad | the wait has outlived the threshold |
overdue | bad | worked time has crossed the estimate |
no movement <5h> | dim | untouched, and nothing is waiting |
owner gone | bad | its owner is no longer a live seat |
in review | blue | completed with the verify gate up |
lead attested | blue | the lead completed the look, citing the user’s own approval |
to close | blue | a root whose children are all done, waiting for its close |
reserved for you | dim | the user reserved this pick: the sweep leaves it, it never reads ready, and no claim takes it |
attempt N | dim | sent back with words N times |
The look has two doors, and the row page draws both. The user’s own
approve sits on the waiting strip; a lead who watched the user approve in
chat completes the row through tasks__approve, which requires the approval
quoted and records it on the row. The completed card then wears
lead attested, and the row page draws the quote with a reopen button:
reopening strikes the attestation, re-mints the look gate and parks the row
on the user again. The page’s pick line is the other side of the sweep:
reserve for you marks the row so the sweep never dispatches it, and
release takes that back. A reserved row is not ready and no seat’s claim
takes it: the pick is the user’s alone. The line draws only while the row is
live - a completed, failed or canceled row has no pick left to reserve.
A wait leads with its ask. The waiting card and the row page both open
on the wait’s own detail where it states one, else the row’s detail - a
look parks with no wait detail, and its ask is the row’s own words - and a
wait with neither falls back to the state’s sentence (“A decision is waiting
on you”, “A look: this row is finished and waits on your approval”). That
fallback is a seeded or legacy wait, or a look minted with no ask, and a
blank detail counts as none. The row’s links follow the ask as references in the sheet’s own
link grammar - the app’s link colour with an underline set off the text, and
a fuller rule under the pointer; no bare anchor reaches the strip, so none
draws the browser’s purple. In a look the artifact is its own door,
look at <name>, wearing the same pill grammar as approve and send back
rather than sitting in the sentence as another link; when the artifact is
already one of the row’s references, the door is its only showing and the
links line keeps the others, so one reference appears once. A good ask says what
the question is, why it needs the user, and links the thing to look at; a
bare “waiting on you” is a card with no question on it.
The links come off the row’s own list: a URL follows in a new tab under its label, and a path or a branch draws as text rather than a dead anchor.
Moving a card
The drag is the board’s interaction, and what the card lands on decides the
command: another lane is a move carrying its place (task_move), a position
inside its own lane is a re-rank by drop position (task_rank), and a seat
chip is an assignment (task_assign). A lane’s whole column takes the drop,
an empty one included, and the place the drop chose is the priority the row
keeps on either path. A press that never passes six pixels is a click, which
opens the row’s own page. A dropped card lands where it was put at once and
the wire’s own snapshot reconciles it a moment later; it animates into place
unless the reader has asked for reduced motion, and the card under the
pointer tilts and lifts.
The keyboard has the same power without a row of buttons: the arrow keys on a focused card re-order it within its lane, and the owner picker on the card is a control like any other.
The row’s page
A click - or Enter or Space on a focused card - opens the row over the board: its
fields (state, owner, estimate, worked, both clocks, its parent, its pick
line and its links), Its tasks on a parent - each row a door that closes
the page and lands on that card - Waiting on you when the wait is a
decision, carrying the wait’s ask, its links and a look’s artifact, then the
waiting strip’s own controls (approve, the send-back box, the answer box),
while a dependency or resource wait draws the section without them, its
History - the row’s own transitions, which the core already records for
the worked time - and the way into the owner’s session. The read caps what a
row carries at its newest twenty, so a long trail reaches the page without
riding every board encode, and the section words what it withholds
(showing the last 20 of 43). The button, the scrim
and Escape all close it, and the card has the keyboard back when it goes; a
jump hands it to the card jumped to instead. The board stays behind it, so a
reader never loses the lane they were in.
Every control is one command on the socket, carrying this project on it.
task_move moves a row between lanes and lands it at the drop’s place,
task_rank re-orders it,
task_assign changes its owner, task_verdict approves or sends back a
verify row, task_answer answers a question, task_create files a row,
task_reopen strikes a lead’s attestation and parks the row on the user
again, and task_reserve reserves or releases the pick. A refused edit says
so on the service line rather than silently reverting, and every one of them
stamps the change as the user’s.
The states the page can be in
- A board, the ordinary case.
- Waiting on the reader: the strip draws only when at least one row’s wait is a decision. Its absence is not a state - an empty frame above the cards would read as a board with nothing for the reader, which is a different claim from the strip not being there.
- Empty: a project with no live rows draws one line naming its two moves
- cut a row in the create line, or tell the lead what is next - with the six lanes still drawn under it.
- Before the first frame: a route can be addressed before the snapshot lands. The page arrives with the connection rather than drawing a second loading state of its own, and a subscription the server turns down says so in its own words instead of reading forever.
- Unknown: a project the snapshot does not carry draws its name and one
line saying this forge does not hold it, with no lanes and no create line -
a row filed there would name a project
forge.tomlhas no entry for. - A set of seats: the seat chips draw only when the project holds one; a project with nothing running draws none.
The two widths
Checked at 1600 and at 430, against the drawing beside it. The lanes
are a grid of minmax(260px, 1fr) columns, so a wide window fits them side
by side, a phone stacks them, and neither scrolls sideways. Every control a
finger reaches takes a 44px target under @media (pointer: coarse), and the
drag is a pointer gesture, so it is the same one under a finger.