The screens

Once your request is in, your job is to watch. This chapter walks the screens in that order. It starts at the board, which shows the whole queue, goes into a single ticket, and from there down to what the session holding that ticket is doing right now.

Inside a project the header carries five screens. Board · Squads · Protocols · Ontology · Workers. Squads is also where you edit personas, so it gets two chapters (Personas · Squads). Group view, at the top of the left-hand list, splits those two jobs. Turn it on and squads are the axis; turn it off and the persona list comes up on its own. It ships on. The other two have their own chapters as well (Protocols · Archiving and the ontology). Here we look at the board, the workers, and the things hanging off either end of the header.

Press Esc on a ticket detail or the epic screen and you come out to the board. Pasting the address straight into a new tab makes no difference. There is no history to walk back, and the destination is the board either way. If a dialog or the switcher is up over the screen, that closes first and the screen underneath stays where it was.

Anywhere else, pressing it does nothing. That is true of the board, Squads, Protocols, Ontology, Workers and the project home, and of a file you opened in the ontology, a persona you picked in Squads, the sort and filter you set on the board, and the surface and tabs you have open on the home. Nothing is broken. The two screens above are the only ones with a destination set. And while you are typing in the interject box or a ticket editor, pressing it moves nothing. What you were writing should not go away on one Esc.

The board

The dira board. Ticket cards sit in three lanes: Open, In progress, Done.

Three columns divide the screen vertically. One column is a lane, and from the left they are Open · In progress · Done. One card is one ticket file.

A lane is a drawing of the filename suffix. When the suffix changes, the card moves to the next lane by itself (see The states a ticket passes through). The engine decides state.

Dragging a card onto another lane calls an engine action. Pick up an open card and the In progress lane header reads Drop to start now. Drop it there and an idle worker is pointed at that ticket; with no idle worker, you are asked whether to stop one running session and start. Pick up an in-progress card and the Open lane header reads Drop to unassign. Dropping it there is the same as Unassign on the ticket detail. Either way, the card moves only after the engine has renamed the file. Each case is spelled out in The states a ticket passes through.

  • A blocked ticket sits in the Open lane with the rest. The only difference is the orange deps tag on its card, and the Blocked badge beside it. Being blocked is a matter internal to that lane, so it clears itself once the prerequisite finishes. Nobody has to touch it.
  • An in-progress card tells you three more things. A dot in the persona's color moves, the worker mark (w6) for whoever is holding the ticket right now sits at the end of the meta line, and the bottom of the card carries one line saying what that session just did. A done card has none of the three. The owner on a finished ticket is a record, not the worker holding it.
  • A ticket waiting on an outside condition sits in the Open lane too. Its card carries a Polling badge with the time left, and one line under it saying what it is waiting for. Past the deadline the badge turns into Deadline passed (see The states a ticket passes through).
  • A done card with an archive ticket on it says how far archiving has got, in that same spot. There are three: Archiving — queued · Archiving · Archiving — awaiting answer (see Archiving and the ontology).
  • The Done lane draws 20 at a time. Scroll to the bottom and 20 more attach. It is not hiding anything, just drawing in batches. To take it all in at once, there is the table view (?view=table) and the filters.

The ticket page

A running ticket's page. Top left is the lock notice with an Unassign button; below it the progress record with four plan steps and the box for talking to the running session; below that the body's Goal and Done when checklist. The right column holds the frontmatter table, relations and the requirement.

Press a card and the page for that one ticket opens. The left side is what you read and write, the right side is what you glance at.

  • The left holds the markdown body someone wrote and the ## Done when checklist. The progress record shows up here too.
  • At the top of the right, one line says how many times this ticket came back, like Reassigned: 3. That is the number of times a worker could not finish it, it went back to the queue, and it got handed to someone again. A ticket that finished on the first pass, or that nobody has claimed yet, has no such line.
  • Below that come the frontmatter table and the relations. frontmatter is the block of settings written between two --- lines at the top of the ticket file. For relations, the top line draws [prerequisite] this ticket [dependent]. Under it, one more line each shows up only when there is something to show: which request this ticket came from (source, req:), and the archive ticket that moved this one into the record.

Reassigned is a different number from attempts in the frontmatter table. Two numbers on one screen are easy to confuse. They count different events. Reassigned counts every time the ticket was handed to a worker, without exception: the session ended in an error, a more urgent ticket pushed it aside, a person unassigned it — all of them. attempts counts one of those, the case where the engine found a session dead and reclaimed the ticket automatically. Of the 3,104 times a ticket went back in this queue, attempts went up 149 times, or 4.6%. The ticket that came back the most was reassigned 273 times, and its attempts line is empty. An empty or 0 attempts does not mean the ticket had an easy run.

The session ticks the Done when boxes as it works. They are not boxes for you to press. The only one who knows whether an item is finished is the session doing it. So each time it finishes an item, the session changes - [ ] to - [x] in the ticket file. This is where you look to see how far a running ticket has got.

This page keeps up without a refresh. When the session adds a line to the body, the line appears; when - [ ] becomes - [x], the box ticks. It is not just this one ticket. What triggers a redraw is the single fact that the queue moved, so the badges on the prerequisite and dependent tickets in the relations, and other people's hashes written in the body, change along with it. If the prerequisite that was blocking you just finished, its badge turns to done. It works the same for a ticket in any of the three lanes. Leave an open ticket on screen and you see the moment a worker takes it; the body of a done ticket has nothing left to change, but the states of other tickets written in it keep up.

A running ticket is read-only. The session is holding the file. Press Unassign in the lock card and the file goes back to the queue. Only then can you edit it by hand.

The Working in browser section on a ticket holding one

While a worker is driving a browser, that ticket gets one more section in the right-hand column. It comes right under the frontmatter table and above Polling, and it is called Working in browser. The screen the worker is on lies open directly beneath the heading.

There is nothing to press and no arrow to unfold. The picture is there from the moment the section appears, and it is live: turn the page on the worker's side and the picture turns with it. The browser runs without a window, so this section is where all of it shows. The picture fills the width of the column and takes its height from the shape of the worker's screen. For the short moment before the first frame lands, the heading stands alone.

A ticket not holding a browser has no such section. No heading, no dimmed line, no empty box. Open the ticket again once the worker has finished and handed the browser back, and the section is gone.

You cannot touch it here. Press on the picture and the worker's page does not budge. This is a place for watching. It is shut off so that an idle click of yours never shakes a screen the worker is measuring.

When you do need to touch it, press Open in home tab at the right-hand end of the heading row. You land on the Browser surface at home with that ticket's tab picked. One approval there and your mouse and keyboard go through (see Terminal, files, and source control).

The heading row carries no owner name and no dot. Here the owner is always this ticket, so there is nothing worth writing twice. Those two markers stand on the Browser surface at home, where every browser a project has opened gathers in one list, and that chapter reads them for you.

Narrow the window until the two columns fold into one and this section keeps its place in the order.

The Polling section on a waiting ticket

Only a ticket waiting on an outside condition gets one more section in the right-hand column. It comes right under the frontmatter table, and it carries the same name as the badge on the card: Polling. There are five rows.

RowValue
ReasonThe one line that showed under the badge on the card. It is the first line of the last ## 결과 (the result section) in the ticket body, and with no such section there is no row
ScriptThe name of the file that decides the condition. It lives under polls/ in the queue root
IntervalHow often it gets run (300s). With nothing written in the script header, Every tick
DeadlineHow long the wait runs and how much is left. Past it, Deadline passed takes that spot
Last polledWhen it last ran. Never run yet reads Not run yet

Under the rows, the Script body and the Last output open up whole. Why it will not clear is usually written in that output. If the file is gone you get Script file not found; if it has never run, No output yet.

Two handles at the bottom of the section break the wait before the deadline. Dispatch now puts the ticket back in the candidate pool regardless of the condition. It wakes a worker on the spot instead of waiting for the next tick. Extend deadline writes the time in the field beside it as the new deadline; the field comes pre-filled with the deadline you have, so you only push it as far as you need. There is no confirmation dialog. What it undoes is one worker command, so it is not a destructive operation.

Neither one makes an answer file. Nobody asked a question, so there is no answer to write. There is exactly one place an answer file is born — after the deadline passes and the ticket locks as Awaiting answer — and that screen looks like any other question (see The states a ticket passes through).

An address written into a ticket body, a deploy URL printed in the progress record, an http://localhost:3000 your terminal just spat out. Press a link like that inside the app window and the built-in browser opens it. Your default browser stays shut.

The press lands you on the Browser surface at home with a tab named Link already picked. It does this wherever you pressed. Even when you are already home, pressing a link in the home chat or the home terminal leaves the surface you were on and moves to that tab. A row by the same name stands in the list on the left, alongside the rows workers and the home chat hold, and the hash beside it reads c0ffee00.

Every link after the first reuses that tab. Press a hundred links and there is still one browser. That keeps links from eating the slots a worker needs to borrow.

In the terminal, only text starting http:// or https:// becomes a link. Hover and it picks up an underline; press it then. A full stop or closing bracket riding on the end of the address is trimmed off.

Links on the landing page and in this manual go to your default browser. Those two screens open in a web browser with no app at all, so they sit outside the product and skip the built-in browser. Links to screens inside the app, and anchors within a page, behave exactly as before. What gets caught is outside addresses.

Opening straight in your default browser

To skip the built-in browser and open a link in the browser you normally use, hold a modifier key as you press it: Cmd+click on a Mac, Ctrl+click on Windows. This works for links in the app window and in the terminal alike. No Link tab appears, its address stays put, and the screen stays where it is. On a Mac, Ctrl+click brings up the right-click menu, so use Cmd.

The address bar

One line carrying the current address stands in the head row of a browser tab, right under the owner's name. Every browser tab has it. Turn the page on the worker's side and the value follows. The Working in browser section on a ticket has no such line; that place is for watching.

Link is the only tab where you can edit the address. There the line is a field: clear it, type another address, press enter, and the browser goes there. Type example.com with no scheme and https:// gets put on the front for you.

On every other tab the same line is read-only text. What decides it is who opened that browser. The screen opens exactly one browser, Link, and that is the only one the screen may drive. The browsers workers and the home chat hold belong to a session at work, and an address you swap out from here would throw off what that run is measuring.

Nothing outside http: and https: is accepted. Put in a value starting javascript:, press enter, and the browser stays where it is.

Handing back a browser you are done with

Release sits at the right-hand end of the address bar on the Link tab. Press it and that browser goes away on the spot, and its row leaves the list on the left. The next link you press opens a fresh one.

No other tab carries this button. There is still no way for you to take back a browser a worker is holding (see Terminal, files, and source control). The screen only takes back what the screen opened.

Sending a page out to the default browser

Press Open in default browser beside the address and the current address opens in your Mac's default browser. Every browser tab has this button. On a tab with no address yet it does nothing.

The built-in browser has no back button and no bookmarks, and it inherits none of the logins from the browser you use every day. A screen you have to sign into with a Google account, or one that needs an extension to work, is what this button is for.

Pointing at the page to file a request on the spot

When you see something to fix on the page you are looking at, you can point at it and file a request right there. Press Comment at the right-hand end of the address bar. Every browser tab has it. Once it is on, the button stays pressed and the cursor over the page turns into a crosshair.

Now press any point on the page. A small dot lands there, and a speech bubble opens with its tail pointing at the dot. Its title is Screen comment, with the current address on one line below. At the top sits a small copy of the page as it was the moment you pressed, with the spot marked. Below that is the same form as the board's New request dialog. Write the body, then press New request or hit ⌘↵. When it goes through, a confirmation line and a See the request you submitted link appear inside the bubble.

What you filed is one kind: request ticket addressed to pm. Under the body you wrote, a ## Screen comment section is added with three lines.

  • URL - the address in the address bar when you pressed
  • Screenshot - the path to the image that was on screen at that moment (attachments/comment-<date-time>.jpg)
  • Click - the pixel position you pressed inside that screenshot, and the screenshot's size

So pm can tell what the request points at without opening the page again. You do not attach the screenshot yourself, and you cannot remove it from the bubble. Other files still go in through the attachment field.

While Comment is on, the page takes no clicks. Press a link and nothing navigates; scrolling and keys do not reach the page either. On a browser a worker is using, the prompt asking whether to unlock input does not appear. Pressing the black bands around the picture, or a tab with no picture yet, does nothing.

Comment stays on after you file. Press another spot and a fresh, empty bubble opens. A bubble closes with Esc, a click outside it, or Close. If you were in the middle of writing, you get the same confirmation the dialog asks for. To work the page again, press Comment once more to turn it off. The setting is not saved, so after a reload it is off.

When the slots are full

Six browsers run at a time. With the Link browser already up, the limit does not come into it. All that runs then is one move to a new address, so no new slot gets borrowed.

With no Link browser and all six slots taken, pressing a link raises one line of toast.

Browser slots are full (6/6) — can't open the link.

The screen stays where it is. The app will not take back a worker's browser to make room either. Wait for a worker to finish and free a slot.

Hashes and P numbers in the writing

Open a ticket body and you find other tickets' hashes all over it. A session writes things like "the back half goes to 8b7c1021". Press those eight characters and that ticket opens. You never have to copy one into the address bar. We will call text that works this way a marker.

Two kinds of value become markers. The eight-character hash of a ticket in the queue, and an epic number (P273). A small circle sits in front of a ticket hash to say its state. An empty circle is open, a circle with a triangle in it is in progress, and a circle with a check in it is done (the same three you saw in The states a ticket passes through). Epic numbers get no circle. An epic has no state to show. Both are underlined, so you can see which text you can press.

That circle points at the queue as it is now. Not as it was when the line was written. Open a ticket that finished long ago and the hashes in its progress record still carry today's state. It can even change while you watch. If the hash of a ticket you just handed off is on screen, you will see the triangle turn into a check right there.

The text itself does not change. A hash shows as its eight characters with no title trailing it. Tickets where a single ## 결과 (the result section) fixes more than ten hashes are common here. Drag a title into every marker and that paragraph grows several times over. If you want the title, rest on the marker for a moment.

Hashes wrapped in backticks work too. This queue writes them as `8b7c1021` more often than not. The gray pill keeps its shape, and only the circle goes outside the pill.

Where they work

Everywhere someone wrote for people to read. Ticket bodies, the session's words running through the progress record, the back-and-forth thread in the answer form, epic READMEs, persona memory, the conversation on the project home.

Ticket titles work as well. Titles on board cards and table rows, the title at the top of a ticket page, and the ticket lines the warning box at the top of the squad screen draws in a row. In a title like 아카이브 - 73f89584, the eight characters at the end become a marker. So one board card has two destinations. Press the hash in the title and that hash's ticket opens; press anywhere else on the card and you get that card's ticket, as before.

The editor you use to change a body has no markers. That is where your cursor goes while you are editing, so we left them out on purpose.

Rest on one and a card appears

Put the pointer on a marker and wait 0.6 seconds and a card appears. Passing over it does nothing. Writing with more than ten markers in a paragraph is normal in this queue, and if cards fired one after another just from a pointer going by, that is not a feature, it is noise.

A ticket card holds four things. The state badge and the hash, the full title, the first three lines of the body, and the persona in charge. The title is not truncated. The body preview skips heading lines like ## Goal and starts from the first line of prose. An epic card holds four as well. The P number, the first line of the README, the body preview after it, and the counts for open, in progress, and done.

There is nothing to press inside a card. One marker, one destination.

You do not need a mouse. Tab to a marker and the same card appears.

Eight characters that do nothing

Not every eight-character hex string works. A marker appears only when that ticket is actually in the queue.

The commit hashes written in a ## 결과 section have exactly that shape. 3f05446e, say. They are not values in the queue, so they stay as plain text. We do not even draw a faded marker. Draw one and false markers outnumber real ones in this queue. Nothing being pressable is not a fault. It means the value lives outside the queue.

Four more things go by quietly for the same reason.

  • Epic numbers that do not exist. P999 is just text.
  • Anything inside a code block. What sits inside triple backticks is a command and its output, where the literal text is the value, and eight characters in there are usually a commit hash git log spat out.
  • Text that is already a link. You cannot put a link inside a link.
  • Anything with characters attached. The last eight characters of the session ID w4-1d21592f are not a marker, and neither is the roadmap row P303-1. We only catch them when what comes before and after is neither a letter nor a hyphen.

The session stream

You watch, live, how the session holding a ticket is getting on. It has the shape of tail -f, the command that follows a file as it grows. By default it is one line per event. Which file it read, which command it ran, what it wrote.

  • The source is not a log the app writes for itself. It reads the transcript Claude Code is already writing in real time. A transcript is the record file where a session's words and tool calls are written down in order. The number of files that grow for the sake of this screen is zero.
  • A replay of a finished session lives in the same place. Open a done ticket and what that session was doing when it ended is still there, in the same shape.
  • Only claude and grok have a stream. For a ticket held by a codex or agy worker this area is empty. The empty area tells you which engine it was. It is missing because that engine writes no transcript, not because something broke.

Three doors into the same record

Three doors open this record.

  • The Progress record box on the ticket page. It is already open when you open the ticket, so there is nothing to press.
  • The Stream button at the right of a row on the workers screen. It only works on a row that is running and whose ticket we know. On the other rows the button just holds its place.
  • Expand, at the far right of the Progress record heading line on the ticket page. It reopens the very record the box above is reading, as a dialog.

The three read one file, but the screen splits two ways. The axis is the container. A box inside a column, or a dialog covering the screen. Which screen you came from does not matter. The first door opens the box, and the other two open the same dialog no matter which side you pressed.

Inline box — there as soon as you open a ticketDialog — Expand or Stream
The time at the head of a lineClock time, like 14:32:07+02:02, time elapsed since the session started
Pressing a lineThe raw text unfolds under that lineThe right-hand column takes the event
Search and filtersNoneOne row above the list
How many times each tool was calledNoneA row of chips under the head counts them
How Result is drawnThe raw charactersAs markdown, and the raw text when you press the badge

The reason they split is the size of the container. The box sits in a column shared with the body, the Done when checklist, and the questions and answers. The dialog covers the whole screen while it is open, so there is room for a search field and a right-hand column. That extra room is where a panel for looking closely at one event goes, and that is why the door is called Expand.

Opening with Expand loses nothing you had in the box. The plan-step accordion, the question and answer bubbles, and the field for talking to the session are all in the dialog too, with search and the right-hand column laid on top. The one thing that does not follow you in is the token figure on the heading line. Close it and the box behind is exactly as you left it.

Expand only shows up on tickets that have the box. A request just after submission has no session record and no bubbles yet, so there is no box at all, and nothing more to look into.

The inline box gets its own chapter below, under Progress record. Here we look at the dialog.

The dialog's head and toolbar

The session stream dialog, opened from the workers screen. The head carries the worker name and the ticket hash, and under it a Running badge and Elapsed 8m 26s, then a row of tool chips starting with Bash 41, a search field, four filters, and Records 145. The body has two columns. On the left, events on relative times like +00:32 Read docs/DESIGN.md; on the right, the input and result of the row you picked. The Result heading carries a Markdown badge and a Copy button side by side.

The top line changes with the door you came in by. Open it from the workers side and it reads Session stream — <worker name>; open it with Expand from the ticket page and it reads Progress record, the name of the section. The ticket page does not repeat the worker name. There, the big title at the top already says whose record this is. The line right below is the ticket hash, through either door.

Two more things attach below. Whether the session is alive comes up as one word, Running or Done, with Elapsed 12m 30s beside it. For a live session that is measured from the first event to now, and for a finished one from the first event to the last.

The row of chips below counts what this session did and how often. A tool name and a count go in one chip, like Bash 14, and the most-called ones sit leftmost. The names are as the engine called them, so they are in English. It counts everything, including what is folded away, so this row is right even when you have unfolded nothing.

Under the chips is the toolbar. It stays put while the list scrolls. On the left is the search field, with Search this record as its placeholder. It sweeps tool names and one-line summaries, and also the raw text you would otherwise only see in the right-hand column, and it ignores case. While you are searching, anything folded opens. That means the bubble groups, and also plan steps that are finished or cancelled. Filter with things left folded and a matching line hides inside, and the search lies to you. Clear the search term and only what you unfolded by hand stays open.

To its right are four filters. Messages · Tools · Thinking · Prompts toggle on and off. All four ship on, and that state is the screen with nothing filtered out. When you only want to see where a command went wrong, leave Tools.

One more chip sits to the right of the filters: Group by step. It ships on, and that is when the list is divided into the steps of the plan. Turn it off and the grouping comes apart. The step headings go, and events and bubbles run from beginning to end as one stream in time order. Press it when you want to read what the session did and in what order, rather than how far the plan has come. Press it again and the accordion is back. The state is kept nowhere. Close the dialog and open it again and the chip is on.

Turning it off hides no record. This is where the chip parts from the four filters on its left. The filters take events away; this chip only undoes the grouping. Records 128 at the far right of the row is what is left after filtering, so a search term or a filter you switch off makes it drop. Pressing this chip never does.

The chip is only on the dialog you opened with Expand, and only on a ticket that has a plan. With nothing grouped there is nothing to ungroup. The one you open with Stream from the workers screen does not read the ticket body, so it knows nothing about steps. Two doors open the same dialog, as written above, and this chip is the one place they part. Without it the search field, the four filters and the record count are all still there. The picture above was opened with Stream, which is why there is no chip in it.

When search and filters leave nothing, one line remains in the list: No matching records. The head and the chip row stay as they were. What you filtered is the list, not the work the session did.

Reading one line

In the dialog the time at the head of a line is +02:02 instead of the clock time. It is measured from this session's first event. It means this happened two minutes and two seconds after that first event. The clock time has not gone anywhere. Put the mouse on that cell and the old 14:32:07 comes back.

At the far right of the line is how long the tool took. The value is the gap between the time the tool was called and the time the result came back. So it appears only on the line that called the tool, and the result line does not repeat the same number. Under ten seconds it reads 8.0s, over a minute 3m 50s. A tool whose result has not arrived leaves this cell empty. A command running right now is like that.

Input and result in the right-hand column

Press a line and the right-hand column of the dialog takes that event. The head of the column repeats the tool name, the time and the duration, and two sections sit below it.

Input is what was handed to the tool. On a line that changed a file, it goes as far as what came out and what went in. Result is what came back, and if nothing has come back yet the section is not there at all. A failed result carries the word Error.

Result comes up as markdown the first time. A line starting with ## becomes a heading, and a line with | in it becomes a table. Line breaks stay as they were. Output a tool spits out often means one thing per line, and merging several lines into a paragraph loses that meaning.

When you need the raw text, press the Markdown badge at the right of the section heading. The badge turns off and the characters that section received come back exactly. Press it again for markdown. This state is not kept anywhere. Pick another line in the list and the new Result is markdown again. Only the Result section has two faces; Input is always raw.

Each section has a Copy. Whichever face you are looking at, what lands on the clipboard is the raw text. Press it while reading markdown and you get the characters from before it was drawn.

This is where you read one tool call's input and result side by side. That is why nothing unfolds under the line in the dialog. We do not draw the same thing in two places. The inline box has no right-hand column, so there the raw text still unfolds under the line, as it always did.

With no line picked, the column carries Pick a row to see its input and result. The column itself does not disappear. Press the close button at its top right and the selection clears and that sentence comes back. On a narrow window the column drops below the list instead of sitting to its right.

What you can pick is an event line. What a person wrote and what the session said to a person are already fully visible as bubbles and prose, so there is nothing to press.

Progress record

The progress record on a finished ticket page. Below the session's log lines, an Answer 1 bubble written by a person (1.(a)) sits on the right, and the right column holds the frontmatter table, relations and the requirement.

Stream lines and question-and-answer bubbles sit in one box in time order. That is why the section is called Progress record. This place answers one question. What has happened to this ticket so far.

A ticket that ran more than once gets one card per round

Some tickets do not finish in one go. A session gets stuck, posts a question, gets its answer and is assigned again, or a session dies and another worker takes over. Each time the ticket is assigned to a worker, one more round starts, and the box stacks one card per round from the top in time order. Three cards means the ticket ran three times.

The head line of a card starts with its number, like Round 1, followed by the worker that held that round, the time it started, and how it ended. The ending is the engine's own word (DONE and the like), and a round still running reads In progress.

Only the last round is unfolded. Earlier rounds show just their head. To see where a round stopped, press its head. Only the events of that round unfold, with no tool calls from later rounds mixed in. The last card is also the only place where events attach live. A round that left no record shows a single No transcript line under its head.

A question and its answer sit between cards. If the first round got stuck and posted a question, a person answered it, and the second round started with that answer, the round trip sits between the first and the second card. The time the answer was written decides which gap it falls into. An interject a person sent while a round was running stays inside that round's card. A question with no answer yet and the input field are at the very bottom, outside the last card.

A ticket that ran only once has no cards. Most tickets are like that, and for them the screen is exactly as described below. If old records were cleaned up and early rounds are gone, only the remaining rounds get cards, and the numbering starts from what remains.

The steps a session wrote down (explained below) are split across the cards by round too. A finished step is in the card of the round that finished it. To look again at a step finished in round 1, press the head of the Round 1 card to unfold it. The last card does not show that step. A step started in round 1 and finished in round 2 sits in the round 2 card.

StepCard it sits in
Finished or abandonedThe card of the round that finished (or abandoned) it. With no end time, the card of the round that started it
Running nowThe card of the round that started it
Not started yetThe last card

Inside a card, steps keep the order the session wrote them in.

Open a running ticket and the box is divided into steps. Before it starts work, the session holding the ticket writes down for itself what it will do and in what order. It is not a list a person hands over. Each line it writes becomes one step in the box, and unfolding that line shows what happened while it was on that step. Read top to bottom and you see at once how far the ticket has come and what is left.

The progress record box on a running ticket. From the top: one folded step, one open step with the field for talking to the session inside it, a not-started step showing only its title, and a cancelled step with a line through it.

A step comes up in one of four shapes.

StepShape in the box
FinishedFolded. The end of the line carries the count piled up on that step, like Records 12, and pressing it unfolds it
Running nowOpen. Events attach inside it live
Not started yetOnly the title. The end of the line reads Not started, and with nothing to unfold there is no handle
AbandonedA line through the title, and Cancelled at the end of the line

The field for talking to the session is inside the running step. The bottom of that step is where you push one line into a running session (see Talking to a running session). With no running step it goes at the bottom of the box, as before.

A session does not revise a list once it has set it. It does not delete lines, reorder them, or add to the end. If the plan goes wrong along the way it strikes through the remaining lines and hands the rest of the scope to one new ticket. People read that list and guess when something will finish, and a list that moves quietly voids that guess every time.

One more panel attaches above the plan list and one below. Assignment and Wrap-up. They are folded in the same shape as a step and open when pressed, but no count sits at the end of the line. A word and a handle, and that is all.

PanelThe stretch it holds
AssignmentUp to the moment the first step catches an event. The session taking the ticket, reading the body and working out what to do in what order goes in here
Wrap-upFrom the moment the last step caught its event. Pushing the commit, leaving a retrospective, writing ## 결과, and renaming the file to .done

The two are not steps. They repeat the same way on every ticket, so the session does not write them into the plan. That is why they wrap the list from outside it. When there is nothing inside, the panel does not appear either. That is why you do not see Wrap-up on a running ticket. The running step is holding events right up to this moment, so there is nothing after it. This panel first appears the moment the session ends and later events pile up. A ticket with no plan written yet, and a ticket that finished before this list existed, have neither steps nor the two panels. That box is one event per line, the way it used to be.

The screen looks at the times the session wrote down and attaches events to steps. Each line in the list has the time that step started and the time it ended, and events that happened between the two go inside that step. When several steps carry the same start time, the events in that stretch get shared out in the order the list gives.

Some tickets have written times that do not match reality. When a session writes times by eye instead of reading the clock, that range does not overlap the time the session actually ran. Then only a few steps catch events by their own times, or none do. Where a step caught nothing, the screen falls back to order. It cuts the flow of events into a few blocks in the order they happened, and the steps sitting there take one each from the top.

Dividing it that way is a guess. Which step an event actually happened in is not written in the ticket file. On a ticket with times that do not match, there is no ground for believing the events inside a step really belong to it. On a ticket whose times were read off a clock, this guess never gets in.

Events left between two steps are as they were. There is no named panel for them. They just appear in time order, in that space between the two steps.

Unfold a step and several lines come out. One line is one event. The time it happened comes first. The next cell is the kind of event, and after that a one-line summary.

A session works by reading files and running commands. Each of those means is a tool. On a line calling a tool, that tool's name appears as it is. Bash means it ran a command and Read means it read a file. In the summary spot, what that command was trying to do goes in a word or two. For a tool that touched a file, it is the file path.

What came back appears on the next line as Result, with how many lines came back in the summary spot. Thinking slips in between sometimes. That is where the session thought to itself before speaking, and usually it does not open, so you only see the length. What the session says to a person does not come as a folded line. It carries Session at its head and runs as prose. There is no time on it.

Press a line and the raw text replaces the summary. The full command that ran, the full result that came back, and on a line that changed a file, what came out and what went in.

A wrong result looks different. On a result line that came back from a failed tool, the word Error attaches in front of the summary. That word alone is heavier than the rest. A good result line carries nothing, so the ones that do catch your eye. We use no color. Print it in black and white and the word is still there.

You need this marker when a ticket has been running a while with no visible progress. That is when you go looking for where it went wrong yourself. Press a line with Error on it and what the tool said back comes out in full.

Two result lines inside an unfolded step. The upper one reads Result Error · 2 line(s) with only the word Error in heavy type; right below it the same tool succeeded and reads Result 1 line(s) with no word marker.

There is no switch for showing errors only. There is no place counting them either. Sweep the box and look for Error. An error inside a folded step shows only when you unfold that step. The running step is always open, so an error a live session just made is visible without opening anything.

The round trip where a session gets stuck, posts a question, and a person writes an answer belongs before and after the session's own progress. So there is one box, one scroll and one input field. What that field does is decided by the ticket's state. The three are mutually exclusive.

Ticket stateWhat the field does
In progress (.wip)Interject — pushes one line into the running session
Awaiting answerAnswer — you write the answer to the question the session posted. Once the answer exists as a file, the lock comes off
Done (.done)Follow-up — opens one new ticket that takes this one over

A question with no answer yet sits at the very end. The field for writing that answer is right below it, so question and answer are next to each other.

The token figure on the heading — how much of the limit this ticket burned

Right beside the Progress record title, This ticket 48M tokens comes up in gray, with Sessions 1 after it. Those are the tokens the sessions that held this ticket exchanged. We add up, as they are, the four numbers the engine writes into its own accounting when a session ends. Input, output, what was written to cache, and what was read from cache. It is not a figure we estimated by multiplying a unit price. This ticket, in front of the number, says whose it is.

It tells you how much you burned. It does not tell you how much it cost. On a flat-rate plan, what people actually ask is how much of the limit it ate. So the unit is tokens, not money. The trade is that the order by money does not come out here. Most of those four are tokens read from cache, and their unit price is a fiftieth of output's. A big number is not an expensive ticket. Two tickets in this queue that differ 2.8 times in tokens came to almost the same bill. This number ranks tickets by how long they held a long context. Not by price.

With several sessions it is the sum of all of them. A ticket often does not finish in one session. It waits for an answer and runs on, or it dies and gets picked up again. It is the total across every session that held that hash, not the value of the last one. 1 session next to it says how many were added. It does not cut by period either. The range is the whole time this ticket was open.

Unknown is not 0. It does not say nothing was used, it says we do not know. Tokens are read from session logs, and there are three branches where that log is missing.

Why Unknown is therePut the mouse on the word
The session is still running. Tokens get written once, the moment a session endsNo exit record in 3 log(s) for this hash
The session died without leaving a result. Those tokens are never comingThe same sentence. The screen cannot tell these two apart
The ticket is old enough that the logs are gone. A session that ran on another machine is not here eitherworkers/logs/*-<hash>.log: no matches on this machine

Logs live only on this machine, and the engine does not delete them. How much is left is decided by your disk and by you (see Reading the logs). So the older the ticket, the more common Unknown gets. Drawn as 0 tokens, every ticket from two months ago would look free, so where we do not know, we write that we do not know. The other way around, when a session ended and all four are zero, 0 tokens comes up as it is. That one is true.

If · outside this total: 3 session(s) is attached, more was actually used. It means those sessions' tokens are missing from the number in front. Sessions whose log survived but has no exit record in it get caught here. A session killed by a signal is one, and its value is never coming. So this sentence does not say it will fill in shortly. It means the same as the sentence beside the tokens on the workers screen.

Per-epic totals are on the epic screen. It is the tokens of the tickets in that epic added up, and it says how many of them we know as well (see Epics).

Three places have no token figure. The board card, the table view, and the status bar at the bottom of the screen. Do not suspect a fault when you look there and find nothing.

  • On a running ticket's card the value is always Unknown. We did not make a cell that is always empty.
  • A done card has a value, but no decision on the board turns on tokens. The axes that move a card are state, priority, epic and assignment.
  • Put a column in the table view and people will sort by it, and with logs surviving only a short while, most of the queue is Unknown. Lining up Unknown against Unknown is not sorting.

It is a different number from the tokens in the bottom status bar. The shared unit makes them easy to confuse, but the two count different things. That bottom line is what one account used in a recent window. The window is 5 hours or 7 days, and everything every worker used is mixed into one pot. This number here is what one ticket used over the whole time it was open, counting only the sessions that held that ticket. The unit of grouping differs and so does the window. Two numbers not matching is not a fault, so do not put them side by side and subtract. Because the screen has two numbers ending in tokens, the one here comes up with This ticket in front.

Workers

The dira workers screen. Eight workers in a table, one per row, each with a running badge, the hash of the ticket it holds, a context count, one line of last-activity log, a pid, a token total, and four actions.

There are eight columns. Name · Status · Holding · Context · Last activity · pid · Tokens (5h) · Actions. The Context cell is itself a toggle. Press it and the list of files this worker loads into a session unfolds below.

Every row shows a pid. A pid is the number the operating system puts on one running program. There is one reason that number is in the table. The reclaim decision hangs on the process being alive. Elapsed time is not the criterion. Whether a worker is running or stale turns on whether that pid is alive right now. Alive is running, dead is stale. The next tick, when the worker sweeps the queue, reclaims it. Elapsed time alone cannot tell a slow but healthy session from a hung one.

This is also the screen where you add workers (see Workers).

The project home

Press the logo in the header and you are home. What sits here is one conversation about this project. It is not a summary dashboard. Just write questions like what is w2 working on right now or why is this protocol the way it is. An agent reads this project's queue, repo and protocols, and answers.

  • The lower half of the left panel has two groups. Conversations starts at three lines and opens three more each time you press Show more. Worker sessions are the sessions this queue's workers held. Pick a finished one and you can ask on from inside that context. You cannot talk to a running session from here. That is Interject, on the ticket page.
  • Commands, which chain shell commands and prompts that you run by hand or at set times, are not in that lower half. They are on the surface row at the top of the panel, second icon from the left. How to make one and everything else about them is in Commands.
  • The answer flows in as the characters arrive. If it takes too long, cut it with Stop.
  • You can send the next message while an answer is still running. It waits under its bubble with Waiting for the answer. If the answer is calling a tool, the message slips into the current answer between tool calls. Otherwise it goes in as the next question once the answer ends. To put it in right away, press Interject now to the right of that line. The running answer is cut off there. What arrived so far stays on screen, and a new answer to your message starts at once. If the message had already slipped in between tool calls, pressing it sends the same message again.
  • It reads, edits, and runs commands. It has six tools: Read · Glob · Grep · Write · Edit · Bash. No MCP tools are attached. The tools carry no path limits, so inside the queue or out makes no difference. The workers' worktrees and your project source included, it can read and change anything your user account on this Mac can open. What it is given instead is an instruction: do not change what a person did not ask for, and ask first when unsure what to change or why. Nothing but that instruction holds it back. When you want something changed, name it plainly.
  • You can submit a request straight from here as well. Ask, in the conversation, to raise it as a request and one kind: request ticket appears for pm to take. It does not read dissatisfaction out of the conversation and file on its own. It writes only on the turn you ask it to.

The notification bell

One bell at the right of the header answers two things. Why this project is not moving right now, and what happened while you were away. The banners that used to pile up above the body have moved into this container. There are nine. The broadest comes first.

  1. The network is down — with no connection, nothing works even with auth in place.
  2. Stretches the queue sat stopped: 3 — while the Mac is asleep or off, the queue does not run. One such stretch is one item, and the title says how many are not archived yet. That many lines appear below it, and one line reads like 8/5 23:40 - 09:12, the stretch it sat stopped and whether it was Sleep or Off. The most recent is on top, and the date only attaches to times that are not today. Nothing was lost and there is nothing to fix.
  3. Uncommitted changes are blocking dispatch — no worker on this project picks up a ticket (see Troubleshooting, the section on the whole queue being stopped).
  4. No Claude token — auth is missing, so sessions cannot start (see Authentication).
  5. Workers that die the moment a session opens — an outside cause.
  6. Tickets no one will claim — tickets stuck at Assigned and absent from every lane.
  7. Tickets waiting on an answer — a person has to write an answer before that project moves again.
  8. Tickets resting after dying repeatedly — they died several times at the same step and are resting for now. Each ticket shows how many times it died and when it will be picked up again, and if you wait it starts moving again on its own. If you do not want to wait for the rest to end, go in through Open ticket on that line. Press Send again now in the Waiting to retry section of the ticket detail and the wait ends on the spot.
  9. Tickets that won't make their due date — the due date has passed, or it is close and a prerequisite is still unresolved.
  • The badge is the count of notifications that are on (0 to 9), not the sum of the items. Add nine things with different units into one number and nothing on the screen says how many of what that number is. Each item writes its own count into its own title.
  • The bell is there at zero too. It presses, it opens, and it tells you No notifications.

Lines waiting on an answer show what is being asked

Open Tickets waiting on an answer and each ticket gets one line. From the left it reads: the hash, the Awaiting answer badge, the question title, and the Write an answer link. The title tells you what you are being asked without opening the ticket.

The title comes from the ticket body. When a session asks a question, the body gains a section like ## 질문 1, and under it numbered items such as ### 1. What do we build first. The bell takes the last question section and shows only the title of its first item.

  • If that section holds more items, the rest are counted after the title. With three items it reads and 2 more. An item with a sub-number like ### 1-1. counts as one too.
  • When another question arrives and ## 질문 2 appears, the line switches to the first item of that section. The earlier section's title no longer shows in the bell.
  • A title too long for the line is cut with an ellipsis. Hover over it to see the whole thing.

Some lines have no title. If the body has no ## 질문 n section, or the section has no item line in the form ### <number>. <title>, the line shows only the hash, the badge and the link. The bell does not make up words to fill the gap. For those lines, click the hash and read the question in the ticket body.

The two that pile up, the seven that do not

Only two of the nine become lists. Workers that die the moment a session opens, and the return notification. One line each time a session dies, one line for each stretch the Mac sat stopped. The other seven leave no line at all.

What splits them is tense. A dead session and a sleeping stretch are past events, so you can count how many times they happened. The seven are facts true right now. Two missing tokens are still one "there is none right now". If the tickets waiting on an answer were five yesterday and three today, the item is simply 3. Write yesterday's five down separately and the bell keeps saying it after you unassign or answer. Then the bell and the queue say different things.

So waiting does not give the seven a list. Come back after three days away and those seven tell you how many there are now, not three days' worth. In exchange, six of the seven go out when you act. Save a token, unassign, write an answer, set a new due date, commit the tree that receives the work, and they drop off at the next check five seconds later. The remaining one, Tickets resting after dying repeatedly, can just be waited out. When the rest is over and a worker picks the ticket up again, it drops off on the spot. If you decided not to wait any longer, open the ticket and press Send again now. Then this item goes out at the next check too.

A worker that died overnight is still there in the morning

The workers screen and the bell look at different things. The line The session failed immediately, under that worker on the workers screen, tells you how that worker is right now. It clears after ten minutes. Those two on the bell tell you that it happened. So they do not clear with time.

If four workers hit a limit and died at two in the morning and the Mac went to sleep at four, both are still on the bell when you open it in the morning. The workers table is already quiet. Nothing is wrong right now. Keeping someone who stepped away from seeing nothing at all is the whole job of these two.

The return notification comes up holding every stretch you have not archived. Sleep three times in three days and the item is still one, with three lines below it. The item does not multiply into three.

Where does Archive send it

Only these two get an Archive button. It sits at the bottom right of the item, on its own row below the sentence. Reading the screen in Korean, it is 보관.

The notification bell popover. Under the sentence of the Workers that die the moment a session opens: 1 item, an Archive button sits at the far right.

  • Press it and the item disappears from the bell. There is one button per item, and everything listed at that moment goes in together. Four dead sessions on screen means all four; three stopped stretches means all three.
  • At the same moment that failure line clears from the workers screen too. The bell and the workers table look at one judgment. A mishap you cleared from the bell never lingers on the workers screen.
  • What disappeared disappeared only from the list. It was not deleted.

To see them again, turn on the Archived toggle at the right of the popover head (보관함 in Korean). What you archived comes up newest first. A dead session shows the time, the worker name and the reason the engine gave, as they were; a return shows the stretch it sat stopped and Sleep or Off. Turn the toggle back off and you are back on the current screen. With nothing archived, it tells you No archived notifications (보관한 알림 없음).

The popover with the Archived toggle on. Archived events come up newest first — one dead-session line and one return line mixed into the same list.

There is no undo button. Press it by mistake and it is still in the archive, so nothing is lost.

Clearing it does not bury the next mishap either. A new session dying is a new line, and the Mac sleeping again is a new stretch, so the item comes back.

This record belongs to this Mac

The list is not written into the queue. It stays inside this Mac. Those two are not facts about the queue but things that happened on this machine. The queue does not know the Mac slept. The log of a dead session is only on the Mac that started it.

  • Look at the same project from two Macs and the bells differ. That is correct. Each Mac holds what it saw. Archive on the work Mac and the bell at home does not clear. That Mac has not seen it yet. The other way around, if only the home Mac slept, the work Mac has no such stretch at all.
  • Move the queue folder and that project's list is gone. All you lose is the list; the mishaps themselves do not vanish. runner.log and the session logs travel with the queue, and the failure line on the workers screen carries that log's filename as it is (see Reading the logs).
  • The list does not grow forever either. When it overflows, the oldest get pushed out. Measured on this Mac, a few weeks' worth fits. A few days away and you will not miss anything. On a day with hundreds of deaths, though, only that day's last ones survive. To see the whole of that day, open runner.log.

The token status bar at the bottom

The thin line at the very bottom of the screen carries one cell per engine this project's workers use. Keeping you from leaving the app to check how many tokens are left is all this line does.

  • What a cell says depends on whether that engine reports its own remaining quota. When it does, you get n% used, which window that number covers, the burn rate over the last 10 minutes, and the reset time.
  • The claude cell shows a % and a reset time too. That number belongs to one active account. The name standing next to the % is that account. The name and the gauge point at one account.
  • claude has two windows, 5h and 7d, and the one used more is shown. Spend 3% of the 5 hours and 77% of the 7 days and you get 77% used · 7d. The window name next to the % tells you which one it is. Whichever hits first is the real ceiling.
  • To read that number the app makes one very small call on your behalf. It sends hi to the cheapest model and uses only the response headers. Twenty-three tokens go back and forth, no more than once a minute per account. That call is not a worker session, so it shows up neither in the consumption on the workers screen nor in this bar's rate, but it does eat that much of the account limit.
  • When no value arrives, Can't read the limit appears, and putting the mouse on those words gives the cause. It is a failure the next poll may fix. In that spot the accumulated tokens for the last 5 hours appear instead. If you have not put in an active account yet, that is an absence rather than a failure, so the spot is simply empty.
  • The window length is used exactly as the engine gave it. 5h and 7d attach right beside the %. Put one window over two engines and one of the two becomes a lie.
  • The only thing that varies per worker is how much was used. What is left is one figure per machine, per account, and every worker shares that one pot. So account-level values are in this bar and per-worker consumption is on the workers screen.
  • A consumption total is only caught once the session ends. A 90-minute session reads zero for 90 minutes, and the tokens of a session killed by a signal never arrive. That is why · outside this total: n session(s) appears beside Tokens, last 5 hours on the workers screen. Stay silent and people read it as "used less".

The settings dialog

One gear at the top right opens a dialog. A search field and a tree of items on the left, and the panel for the item you pick on the right. When you cannot remember an item's name, try the search field. It takes you there without walking the tree.

  • Project — the first group in the tree. It only appears when you open settings from inside a project. There is a single line under it, and its name is the name of the project you are looking at. Press it and ten things for that one project come up in this order — Resolved values, Ontology migration, Folder to import, Edit ontology location, the twelve metric cells, Name, Integration branch, Empty the working tree while idle, Environment variables, Unregister. The four in the middle all deal with the ontology, so they stand together. Two of those four moved here from the ontology screen: Edit ontology location and the twelve metric cells (see Archiving and the ontology). Integration branch is the branch sessions push to, the one you set when you created the project (see Your first project). Empty the working tree while idle is covered in Empty the working tree while idle below, and Environment variables in Project environment variables.
  • Authentication — claude is at the top, with codex · grok · agy one line each below it. This is where you put in the long-lived token the cron-mounted workers use. The screen runs the issuing command for you. The details are in Authentication.
  • Keyboard shortcuts — where you see and change the screen's shortcuts.
  • Usage stats — covered in Usage analytics, and how to turn them off.
  • Language — picks the screen's wording between Korean and English.
  • Autonomy — the line right under Language. It picks, from 1 to 5, how often worker sessions ask a person back. Indented right under the 5 line is the Autopilot switch, with one red line of warning beneath it: sessions push on without asking, and only tell you through a red awaiting answer when they get stuck. The switch only responds when 5 is picked, and it saves the moment you flip it. Typing autopilot in the search field brings you here too. What a session stops asking once it is on is in Submitting a request, under Autopilot.
  • Webhook — when a ticket newly starts waiting on an answer, it sends just that fact outside as one line. Covered in Sending Awaiting answer somewhere else.
  • Workers — the bottom line of the tree. At the top is Machine-wide session limit, which sets how many sessions can be up at once on this computer, and below it All workers gathers the workers of every registered project. The Project and Status filters narrow that list, and Clear filters puts it back (see How many to run at once, under this computer's ceiling).

Open settings from the home header and the Project group is not there at all. That place points at no project, so there is no way to decide whose values to show. Use the gear on a row in the project list instead, or open the switcher in a project's header and press the gear inside it. Both buttons sit where they always did, with the same icon, and pressing either opens Settings with that project's node already selected.

Everything outside the Project group belongs to this computer and applies to every registered project. Authentication, language, the session limit — none of them are set per project. Values that do differ per project sit in two places. One is the ten things in the Project group you just saw; the other is Worker settings, opened separately from the top right of the workers screen (see Workers).

Empty the working tree while idle

If the project folder takes up a lot of disk, turn this switch on. In the Project group, Empty the working tree while idle sits right under Integration branch. The line under the switch sums it up: turning it on empties everything but .dira and .git right away, the folder is filled from the integration branch again when a ticket is processed, and it is emptied again after three days without work.

Only the project folder is emptied. Sessions work in their own worktrees under .dira/worktrees, so tickets keep getting done while the project folder is empty. Nothing is downloaded again either. .git stays, so the integration branch is checked out from it, with no fetch from origin. Commits the workers pushed may not be on origin yet.

What stays and what goes the moment you turn it on:

What
Stays.dira and .git
StaysFiles named .env or starting with .env., at any depth. git cannot bring secrets back
StaysOther worktrees listed by git worktree list, and the folders above them. A worktree you made inside the project folder is not touched
GoesEvery file git tracks
GoesFiles matched by .gitignore. node_modules and build output are in this group

git status still comes back clean after emptying. The tracked files are only taken out of the working tree with git sparse-checkout, so git does not see them as deleted. To check from a terminal whether the folder is empty right now, run git sparse-checkout list. If the output is the single line /.dira-slim-empty, it is empty.

When it fills again

The folder is filled right before a worker picks up a ticket and starts a session. If filling fails, the session starts anyway and the failure gets one line in runner.log. Turning the switch off fills the folder on the spot. A project with the switch off is never left empty.

Filling brings back only the files git tracks. node_modules and build output stay gone. To run the app from the project folder yourself, install packages and build again.

Three days idle empties it on its own

Each time the worker runs, every 30 seconds, it checks these four and empties the folder when all of them hold.

  • The switch is on.
  • The folder is filled right now.
  • No ticket in the queue is in progress.
  • The last work time is 72 hours or more in the past.

The last work time is when a session was last started to process a ticket. If no session has started since the switch went on, the time the switch went on is used. Work a person does directly in the project folder does not count. If you spent more than three days working only in that folder, the refusal rules below protect your edits, but a clean tree with everything committed gets emptied.

When emptying is refused

The folder is not emptied while a person's work is in it. Any one of these refuses it.

  • There are uncommitted changes.
  • There is a new file not matched by .gitignore.
  • A branch other than the integration branch is checked out.
  • HEAD is detached.

The app does not stash or commit for you. The status line under the switch shows the reason and up to five of the paths involved. Commit or delete those paths, and if you are on another branch, go back to the integration branch. A refusal still saves the switch as on, and the automatic emptying tries again once the three-day rule holds. To empty right away, turn the switch off and on again.

Otherwise the status line says whether the folder is empty or filled, along with the last work time. If the switch does not respond and the line says the folder is not the top-level folder of a git repository, the project folder is a subfolder of a repository or a worktree belonging to another one. The option cannot be turned on for such a project.

The switch's value is one line in .dira/slim-checkout. on means on and anything else means off. Workers read this file even when the app is closed. Typing slim in the search field also brings you here.

Project environment variables

This is where you leave secret values for a project, such as an API token a session needs. In the Project group, Environment variables sits below Empty the working tree while idle and above Unregister. Values are encrypted with this Mac's OS key storage (the Keychain on macOS) and kept in the app's data folder. They are never written to the queue, tickets, git, or a .env file.

Saved values cannot be viewed again. The list shows the name, a fixed mask ••••••••, and the time it was updated. There is no show button and no copy button. If you forget a value, get a new one from the service that issued it and replace it.

  • Add - fill in the Name and Value fields on the bottom row and press Add. A name starts with a letter or underscore and uses only letters, digits, and underscores (for example TEST_API_TOKEN). If the name already exists you get That name already exists. Use Replace value in the list. A value can be up to 64 KiB.
  • Replace value - press Replace value on that row and an empty Value field opens. Enter the new value and press Save replacement.
  • Delete - press the trash icon and <name> will be deleted and gone from the next run. comes up. Nothing is deleted until you press Confirm delete.
  • There is no rename button. Delete it and add it under the new name.

The value field always opens empty. When a save succeeds or you close the dialog, what you typed is thrown away.

A changed value takes effect from the next run. A process a session has already started keeps the old value, and a deleted name is still there inside that process. If it needs the new value, run that process again.

Each project has its own values. Another project can use the same name with a different value, and changing one leaves the other alone. Worker worktrees of the same queue use this project's values. They are also kept apart from the login tokens in Authentication. Unregistering the project does not delete the values; register the same folder again and they come back. There is no way to move them to another folder or another Mac.

PATH, HOME, SHELL, ENV, BASH_ENV, NODE_OPTIONS, PYTHONPATH, and any name starting with LD_, DYLD_, TICKET_, or DIRA_ cannot be registered. They control how sessions and the engine run, so you get This name controls execution and cannot be registered.

When a save fails, one red line appears at the top of the panel. It is one of four.

On screenCauseWhat to do
Cannot reach the desktop app. Check that it is running.The dira desktop app is closed or the connection dropped. Values only open while the app is running.Start the app and try again. The list is not empty; nothing is saved or run while the app is closed.
The OS key storage is locked or unavailable. Unlock it and try again.The Keychain is locked, or the app was denied access to it.Check that you are logged in to the Mac, allow access if a Keychain prompt appears, and try again. There is no fallback that stores the value in plain text.
It was changed elsewhere first. The list was reloaded, try again.Another session or window replaced or deleted the same name first.Press it again on the reloaded list. The value you typed was thrown away, so enter it again.
That name was already deleted. The list was reloaded.Someone deleted it first.Use Add to register it again if you still need it.

This is where the protection ends. The only place a value is decrypted is the environment of a process a session starts with dira env run. Values never reach the screen, the list, command output, or a session prompt, and in the output and progress log that dira records, any string identical to a value is masked. The process itself still gets the value as is. dira cannot stop a program from printing a transformed value or sending it to another server. The assumption is that sessions and programs running under the same Mac account are trusted. If you paste a value into a ticket, a chat, or a command argument, the plain text stays in that record and dira does not erase it. Enter values on this screen only.

The commands a session uses to read these values are in the dira env section of CLI.

Connecting to Vercel

If the project deploys to Vercel, you can keep the values stored here in step with the Vercel project's environment variables. The Vercel line right under the Environment variables heading is where that happens. You connect once per project.

Press Connect to Vercel next to No Vercel project linked. dira looks for the Vercel project in this order and connects without asking once it narrows down to one.

  1. It looks for .vercel/project.json in the project folder. If the root has none, it goes down to three levels of subfolders (a place like apps/web/.vercel/project.json). If you ever ran vercel link in that folder, the file is there.
  2. Without the file, it looks for a Vercel project linked to the same repository as git origin. If there is exactly one, it connects to that.
  3. With two or more candidates you get Pick the Vercel project to connect. and the list. With none you get No linked Vercel project found. Pick one below. and every project in that account and its teams. Press Connect this project on the row you want.

Once connected, the line shows the team ID and project name, the last sync time, Sync now, and Disconnect. dira matches the two sides once the moment you connect, so there is nothing more to press. After that it syncs on its own when you open the settings screen, when the app starts, and every 5 minutes while the app runs. If Not synced yet stays where the time should be, the first sync has not finished yet or it failed. A failure shows Could not sync. Try again shortly. on the line. Wait a moment, then press Sync now.

You do not need a separate Vercel login. If you ran vercel login on this Mac, dira uses the Vercel CLI's login as is. If you never logged in with the CLI or the login expired, the line says Vercel login required. Paste a personal token. How to clear that is in When login is required below.

Disconnect removes only the connection. Variables on both the dira side and the Vercel side stay.

After connecting, values move by these rules. There is nothing to choose.

  • Adding, replacing, or deleting in dira goes to Vercel right away. dira writes to the production and preview environments as sensitive variables. It never reads or writes the development environment or variables scoped to a single branch.
  • Vercel variables whose value can be read (anything not sensitive) are brought into dira. The production value comes first, the preview value if there is no production one.
  • If both sides changed since the last sync, the value changed later wins.
  • For variables joined by sync, deleting on one side deletes on the other. A variable that existed on only one side before you connected never deletes the other side.

Sync marks on variable rows

Once connected, every variable row gets a sync mark to the right of the masked value. Before connecting there are none. Names that exist only on Vercel and not in dira appear separately at the bottom of the list.

MarkMeaningWhat to do
In syncBoth sides hold the same value.Nothing.
Waiting for VercelSaved in dira but not yet written to Vercel, because the network dropped or the Vercel login lapsed. Sessions keep using the dira value.The next sync writes it again. To match now, press Sync now. If it stays, check whether the Vercel line is asking for a login.
Conflict, matched to the later value - dira value or - Vercel valueBoth sides changed since the last sync, so dira kept the value changed later. The trailing words name the side that won. The mark goes away after 24 hours.If the remaining value is the one you wanted, leave it. Otherwise put the right value back with Replace value.
Only on Vercel, value unreadableThe variable is stored on Vercel as sensitive. Vercel does not return the value either, so dira only knows the name.If a session needs it, press Enter value, type the value, and press Add. It is added to dira and the Vercel value is replaced with it too. If no session needs it, leave it.
Not importedThe reason in parentheses keeps this name out of dira. It is one of Vercel system variable (a name starting with VERCEL_), name controls execution (the names that cannot be registered, listed above), or unusable name (a name that breaks dira's naming rule).Usually nothing. If a session needs a value marked unusable name, add it to dira separately under a name that follows the rule.

Besides those five, you may see Changed on Vercel, re-enter the value. Someone changed on Vercel a variable dira had written, and because it is sensitive dira cannot read the new value. dira does not put the old value back on Vercel. Enter the value you want with that row's Replace value and both sides are matched to it.

When login is required

Under Vercel login required. Paste a personal token. you get a Vercel token field and a Vercel token page link. Recover with whichever is easier.

  • Run vercel login again in a terminal, then close and reopen the settings window. dira reads the CLI login fresh every time it uses it, so there is nothing to paste.
  • Create a token on the Vercel token page, paste it into the Vercel token field, and press Save token. dira keeps only a token Vercel accepts, encrypted with the Keychain, and reconnects right away. Like the variable values, the token cannot be viewed again.

If both a CLI login and a pasted token exist, the CLI one is used first. Values you change in dira while the login is lapsed are saved in dira and marked Waiting for Vercel. After you recover, press Sync now and they go to Vercel.

If the token cannot be saved, the reason appears under the field.

On screenWhat to do
Vercel did not accept the token.The token expired or was deleted. Create a new one on the token page.
The token format is not valid.The token was cut off or has spaces in it. Copy the whole token again.
The OS key storage is locked or unavailable, so the token was not kept.Unlock the Keychain and save again.
Cannot reach the desktop app. Check that it is running.Start the dira desktop app and save again.

If connecting itself fails, the Vercel line shows the reason in red with Retry. For Could not reach Vercel. Check the network., check the network and press Retry. The key storage and desktop app messages are cleared the same way as in the table above.

Changed values apply from the next deployment

When a Vercel variable changes, the site already deployed keeps running with the old value. The new value goes in only with another deployment. When dira changes a Vercel variable, the Vercel line shows Applies from the next deployment. and Redeploy production.

To apply now, press Redeploy production. It creates a new deployment from the latest production deployment. Preview is not redeployed. If you do not press it, dira never deploys on its own and the new value goes in with your next regular deployment. If you see Could not redeploy., the project has no production deployment yet or Vercel could not be reached. Deploy from the Vercel dashboard.

The project list

The first screen you see when you open the app. To get back here from inside a project, open the project switcher in the header and press Manage projects at the bottom. Registered projects come up as a table at the top, with the product introduction below it. The introduction is the same writing as the page you see on the web. In the app, the list rides on top of it as the first screen.

  • One row is one project. The columns are Name · Path · Open · In progress · Done · Connected · Actions. Press the name for that project's board.
  • For a project that is not connected, the three count cells are empty. Not zero. Could not read and zero are different facts.
  • The gear in the Actions column opens Settings. That row's project comes up already selected under the first tree group, Project, and the ten things from resolved values through unregister are there. No separate Project settings dialog opens any more (see The settings dialog above).
  • The right of the header carries Manual · Market · Star · New project · Settings. Settings here is a word, not a gear.
  • With zero registered projects, the creation form unfolds where the table would be, and New project drops out of the header (see Create your first project).

The market

Where projects on one Mac hand personas and squads to each other. When you want the writer you raised in this queue over in the project next door, you put it here and pull it down instead of copying files by hand. The store is one directory, ~/.config/dira/market/, and nothing leaves this Mac. No account, no upload. Each version of an item gets its own <kind>s/<owner>/<name>/<semver>/ folder holding one APM package (apm.yml with PROFILE.md and skills.md, or members for a squad). Old v<integer> folders are read as <integer>.0.0.

Two doors lead in: Market at the top right of the Squads screen, and Market in the header of the project list.

Putting something up

You deploy from the origin project. Pick a persona in the left list of the Squads screen and Deploy to market sits in the head of the right pane. Pick a squad and the same button shows up in the same place. A persona with no profile yet does not get the button, since there is nothing to carry.

  • The dialog asks for Note (required) and Tags (comma-separated, optional). Leave the note empty and Deploy stays dead.
  • That one line of note is the version's name tag. It sits next to the timestamp in the version list, and it is what you read later in the origin's Deploy history section and in the market item's Versions list. Stack up four notes that say fix and the list is just numbers.
  • Versions are semver (three parts, like 1.2.0). Under Bump, pick patch (fix), minor (addition) or major (breaking); patch is the default. The first deploy is 1.0.0 whatever you pick. Deploy the same bytes twice and you get two versions. Old versions are never deleted. When the origin project has .dira/team/, its local package is copied as is and the version in apm.yml is set to the new value.
  • Tags are what narrow the list later on the market screen. You can leave them blank.

What a deployed copy leaves behind

A deployed persona carries PROFILE.md and skills.md, plus the apm.yml dira adds, and nothing else. A squad carries one member list and its apm.yml.

Memory does not travel. The retrospectives under memory/ are lessons that hold in this queue only, so shipping them means the receiving side loads someone else's project history into its own prompt. The session limit and the engine setting stay behind for the same reason. Whoever imports it gets the profile and the skill lines, and builds its own memory from there.

The skill names written in skills.md cross over as text. If a skill is not installed on this Mac, the line is all you get. Importing from the market never installs a skill for you (see Personas).

Deploying a squad deploys its members first

A squad carries member names only. So if a member persona is missing from the market, whoever imports the squad gets a shell with names in it. Deploy order closes that hole.

Press Deploy to market on a squad and it counts the members that are not in the market yet, then asks first with Some members aren't in the market. Choose Deploy them too and it puts the members up one at a time, then the squad. Each member gets the same note line you wrote for the squad. Cancel and the squad does not go up either; nothing is left half deployed. If one member fails on the way, it stops there and skips the squad. Members already up stay up, and pressing again picks up where it left off.

Finding something

The market screen lives outside any project. It is the same list whichever project you opened it from, and the project panel on the left is not there.

  • Two tabs, Personas and Squads. One card carries the name, the owning project, the latest version, the tags and a favorite star. If anyone has imported it, Imported in and a count ride along.
  • The search box sweeps the name, the owning project's name, the tags and the first line of PROFILE.md. Press a tag and only that tag is left. Both filters show as badges at the top and Reset filters clears them in one press.
  • Turn a star on and it stays on through a refresh. Favorites are per Mac too.
  • Press a card and the detail opens: the body of PROFILE.md, the skill lines and the version list, all read-only. You cannot edit anything from the market. Editing happens in the origin project, always.

Importing

Import at the top right of the detail opens a dialog.

  • Target project is where it lands. With no project registered yet, you get a note telling you to register one first.
  • Name comes pre-filled with the market item's name and you can change it right there.
  • Import a squad and it pulls in any member persona the target is missing, at the latest version. The result screen lists them under Members brought along:. Names the target already has are left alone, because one squad should not overwrite a persona you have been editing locally. If a member is missing from the market as well, the import still succeeds and that name shows up separately under Members missing from the market:.
  • When the target project has .dira/team/ and the item has more than one version, a Version field appears. It starts on the highest version. The version you pick is copied to .dira/team/market/<kind>/<owner>/<name>/. A project without .dira/team/ has no such field, and import always takes the highest version there.

When the name is already taken

If a persona by that name already sits in the target, Import stops right there and offers two ways forward. Nothing is overwritten quietly.

  • Overwrite replaces PROFILE.md and skills.md, and those two only. That persona's memory/, its session limit and its engine setting stay put, because nothing in the deployed copy gives a reason to erase them.
  • Different name sends you back to the Name box with the text selected. Change it, press Import again, and it lands under the new name with the old one untouched.

When the receiving project has .dira/team/ - a pinned copy

When the receiving project's queue has .dira/team/apm.yml, what you import stays inside that queue as a copy. Pressing Import does this.

  1. It copies that version's folder to .dira/team/market/<kind>/<owner>/<name>/. The version in the copy's apm.yml is the version you took.
  2. It adds one line, ./market/<kind>/<owner>/<name>, to the dependencies in .dira/team/apm.yml.
  3. It installs the packages and records the result in .dira/team/apm.lock.yaml.

The copy and those two files are inside the queue, so they are not committed to the project repository. Even if the market's versions change later, python3 dira_apm.py install <project root> reinstalls the same content from this copy (Install). The copy is pinned. A newer version from the origin leaves it as is; only the badge appears.

Items owned by dira are the shared packages in the dira repository's packages/. For those no copy is made; it adds a single git dependency line of the form proofer-tech/dira/packages/<package>#<package>-v<version>.

A project without .dira/team/apm.yml still gets the files written straight into the queue's persona folder, as before.

What the origin sees

Pick that persona in the origin project and open the Profile tab: two more sections sit at the bottom right, below the memory section. For a squad there are no tabs, and the same two sit below the Members section.

  • Deploy history lists what you put up, newest first, one line each with the version, the time and the note. Never deployed reads Not deployed yet.
  • Installs stacks one line per import: which project took it, which version, and when. Empty reads None yet.

Telling what you deployed from what you imported

The left list on the Squads screen shows which rows have anything to do with the market. One or both of two badges sit after the name.

  • Deployed v1.2.0 means this project has put that name up on the market. The version is the newest one you deployed and matches the top line of Deploy history in the right pane. Hover it and it reads Deployed to the market.
  • Imported means the row is a copy taken from the market. Hover it to see the origin as <owner>/<name> v<version you took>. The badge stays even when the origin has not deployed anything newer and no Update available badge is showing.

If this project deployed again something it had imported, both badges appear. A row that has never touched the market carries neither. The badges are the same with Group view on or off, and on the member rows under a squad.

Pick an imported item and the right pane shows an Imported from line just above the Deploy history section. It reads <owner>/<name> v<version you took>, the same as the Imported badge's tooltip.

A newer version raises a badge on the receiving side

On the Squads screen of the project that imported it, a badge like Update available v1.1.0 sits next to the persona's name in the head of the right pane. It shows only while the version in the copy's apm.yml is below the highest version in the market. Squads carry the same badge.

See what changes before you take it. Press the badge and Fetch the latest version? opens. In a project with .dira/team/, Reading what changes… shows briefly, then Files that change when you take it · v1.0.0 → v1.1.0 appears below. Each file is listed with Added, Removed or Changed, and under it the changing lines show as + (green) and - (red). If the contents match, it says File contents match your copy. Only the version label changes.

Once you have read it, Take update replaces the copy with the new version and installs it. If you do not want it, press Cancel; the copy and the lock stay as they were. Edits you made to the copy show up in the diff as - lines, so move anything worth keeping before you take the update. Memory is untouched here as well.

In a project without .dira/team/apm.yml there is no diff. The dialog says the current PROFILE.md and skills.md will be overwritten and that this can't be undone, and the button is Fetch update. Pressing it overwrites them right away.

An imported persona is not tethered to its origin. Edit it after the import and it is simply a file in that project; the badge only tells you the two versions have drifted apart. There is no two-way sync.

The way to the manual and back

Manual at the right of the header opens this document. The screens inside a project share the header, so pressing it from the board and pressing it from the workers screen land in the same place.

Open this document from the app and the manual header carries Manage projects as well. Those two buttons are the round trip for breaking off reading, crossing to a screen, and coming back. Reading on the web, you do not have that button. It only appears inside the app.

Next is Talking to a running session.