Terminal, files, and source control

There comes a point where you want to open the file a worker changed and look at it yourself. Running the tests once, or checking the commits a worker has piled up and taking them to the integration branch, is the same kind of thing. None of it means leaving for another app.

Press the logo in the header and you are home. Six icons sit in a row at the top of the left-hand panel.

The six surfaces

Sessions · Commands · Terminal · Source control · Explorer · Browser. These six are the surfaces. The row carries icons only, with no names written out, so if you cannot tell which icon is which surface, hover over it. The name comes up as a tooltip. Those are the names this chapter uses below. Until you have a tab open, Sessions is the one picked, and below it are two groups: Conversations and Worker sessions. The word repeats, but the two are on different layers. Sessions is the surface name that covers both groups, and Worker sessions is one of the lists that surface opens.

Changing surfaces does not change the address. The screen list on the header stays where it is. What changes is the lower half of the left-hand panel and the column on the right, and nothing else.

Surface pickedLower half of the left panelThe column on the right
SessionsConversations · Worker sessionsThe conversation tab strip and the thread
CommandsThe command list and the way in to New commandThe steps and last scheduled run of the command you picked
TerminalThe list of terminals you have open, the Working directory picker, and the way in to New terminalThe terminal tab strip and the shell
Source controlThe root and the worktrees, and git status for whichever one you pickedThe conversation tab strip and thread, unchanged
ExplorerThe file tree and findThe one file you have open
BrowserThe browsers workers are holding right nowThe screen of the one you picked

What you do on the Commands surface is covered in a chapter of its own, Commands. What is left for this one is the other five.

Four things become tabs: conversations, terminals, files you open in the explorer, and browsers. Twelve tabs open in all. Past that, the one you have looked at least recently closes on its own.

A refresh keeps you where you were

Refresh the browser and the tab you were on comes back still picked. If you were on a file tab, that file is in the column on the right; if you were on a terminal tab, that terminal tab; if you were on a conversation, that conversation. The marker on the tab strip sits on the same tab too.

The left panel follows that tab. A file tab picks Explorer, a terminal tab picks Terminal, a browser tab picks Browser, and a conversation tab picks Sessions. Only a project with no tabs open starts on Sessions.

Source control and Commands are the two exceptions. Neither opens a tab, so nothing on the screen after a refresh tells which surface you were on. The left panel goes to Sessions and the conversation you were reading shows on the right. Press the icon once more to get your surface back.

The shell does not come back with it, though. Refresh the browser, or leave a surface and come back, and the terminal tab reads Terminal disconnected, while its row in the list on the left reads Disconnected. The shell is only in memory for as long as the app runs, so redrawing the screen breaks the connection. Press Reopen and a new shell comes up in the same directory. What you typed before, and what it printed, do not come back.

One project in two windows

You can keep one project open in two browser windows at once. Some of it the two windows share, and the rest each window keeps to itself.

Both windows see itEach window keeps its own
The tabs laid out on the tab stripWhich of them is picked, and the marker on the strip
What you saved to a file, and the commits piled upThe conversation in the column on the right

Open a file in the other window and that tab shows up on this window's strip soon after. Nothing on this screen moves for it. The marker stays on the tab you were on, and so does the column on the right. Switching conversations over there is the same. Refresh over here and you come back to what this window was on.

One thing does follow. When the other window closes the tab this one was on, that tab goes from this strip as well. The marker does not stay on an empty spot: it moves to whichever open tab you looked at most recently, and the left panel follows that tab.

Open a new window and the tabs are laid out as they were, since both windows see the same ones, with the most recently looked at among them picked.

Where tabs close

Every tab has an X on its right edge. Press it to close that one. You do not have to press it ten times to clear a strip of twelve, though. Right-click a tab and a menu comes up. It holds four items.

ItemWhat it closes
Close Tabs to the LeftEvery tab to the left of the one you right-clicked
CloseThe one tab you right-clicked. Same as pressing its X
Close Tabs to the RightEvery tab to the right of the one you right-clicked
Close Other TabsEvery tab but the one you right-clicked

Left and right mean the order the tabs sit in on screen. Neither the tab you looked at most recently nor the one you have selected changes that. The tab you right-clicked is on neither side. Press Close Tabs to the Left and that tab stays where it is.

The bottom item, Close Other Tabs, takes no side. Press it and the tab you right-clicked stays while every other one closes. That is where the left item followed by the right one would leave you, in one press instead of two.

Right-click the leftmost tab and Close Tabs to the Left comes up greyed out and takes no click, because there is nothing on that side to close. Open one tab on its own and Close Other Tabs greys out for the same reason. The item does not disappear, so what you reach for is in the same place on every tab. Right-click empty space in the tab strip and this menu does not come up. With no tab under the pointer, there is no left or right to work out.

A file tab you have edited and not saved stays open under all three items that close more than one tab. If you close five tabs on the left and one of them is still there, that is the one. Close Other Tabs leaves it open alongside the tab you right-clicked. When every tab but the one you right-clicked is a file tab like that, Close Other Tabs greys out and takes no click. The app will not throw away an edit in progress without saying so. Save the file, right-click again, and it closes with the rest.

Naming that one tab with Close is another matter. It closes then and there, the same as pressing its X, and the unsaved edit is gone.

The persona on Sessions

One Persona select sits at the top of the conversation column. Every persona in this project that has a profile shows up in it. It starts on archive-manager. Pick pm and ask, and the answer comes back with pm's profile loaded. The Personas chapter covers what that profile is.

  • One run in and the select locks. When two personas speak in one conversation, nobody can work out later what any given answer was based on. To ask as a different persona, press New conversation.
  • A command's Prompt step has no such field. It runs as a single claude -p without a profile (see Commands).

Changing the persona does not widen what it may do. Pick developer and it still cannot edit under apps/; pick pm and it still cannot commit or push from here. The tools the session carries, and the places its writing reaches, are one set whichever name you picked (see The screens). The only thing that changes is the one profile that goes into the prompt.

Work that needs wider permission goes out as a ticket. Once a worker takes that ticket, it carries the full set of tools. You can ask in the home conversation to have it filed as a request, or file it from the board yourself (see Writing a ticket yourself).

The terminal

Pick Terminal and the lower half of the left-hand panel becomes a list of terminals. New terminal sits at the right of that list's header row, with the Working directory picker just below it. Opening a new one and seeing the ones you already have open happen in the same place.

  1. In Working directory, pick where the shell should start. The project root and every worker's worktree are all in the list.
  2. Press New terminal. A row is added to the list on the left and a prompt is drawn in the column on the right.
  3. Type your command. Colored output comes through as it is, and programs that draw the whole screen, like vim or top, run too.

What is left in the column on the right is the terminal tab strip and the shell.

One row in the list

A row is one terminal you have open. The top line, on the left, is the last command you pressed enter on in that terminal, written out as you typed it. Before you have pressed enter even once, that spot reads No command yet.

The right of the top line is where a mark goes. While the command you typed is still running it reads Running. Once the shell has been cut off it reads Disconnected. When the shell is back at the prompt waiting for the next command, no mark is there at all.

The bottom line is the working directory the shell runs in. Open the terminal on the root and it reads Root. Open it on a worktree and the id of the worker who uses that worktree shows there instead. Those are the same words you see under Source control below, so a row reading Root points at the same folder on either screen. Either way you picked the directory when you pressed New terminal, and it does not change afterwards. To move, type cd yourself.

The app re-reads this list every five seconds for as long as you are looking at the Terminal surface. Set something slow like sleep 30 going, do something else, come back, and the list alone tells you which terminal is still busy. Switch the surface to Source control or anywhere else and the app stops reading it while you are away.

Press a row and the column on the right switches to that terminal, the same as pressing its tab in the strip. Closing happens in the tab strip alone: the rows on the left carry no close button.

The shell is the one you normally use on this Mac. The app does not pick one for you.

There is no allowlist on commands. Anything you can type in a terminal app you can type here. Eight open at once. Try for a ninth and Up to 8 terminals can be open at once. comes up. Close a tab and that shell ends with it.

Nothing here stops you from editing an in-progress ticket. The app not giving you a place to edit, and a person opening vim on their own Mac, are two different things. What stays true is that a session is working on that file right now, so read The exception - in-progress tickets below first.

The explorer

Pick Explorer and the left-hand panel becomes the file tree of the project root.

  • Press a directory and it reads that one level. Even in a large repository the first draw does not take long.
  • It opens with Show hidden files on. That is because .dira, which holds the queue, is inside one. Turn it off and names starting with a dot drop out of the tree.
  • It draws up to 2,000 entries per directory. Past that, one line in that spot says how many of them it drew.
  • It goes down into worktrees as well. What it will not expand is a spot pointing back at a directory already open above it, like the .dira inside a worktree, and it tells you why. Otherwise the app digs into the same place forever.

Press a file and it comes up in the right-hand column with coloring on it. Edit it, press Save, and the file on disk changes. Saving writes a temporary file and then renames it. A session reading that file never catches it half-written.

The editor does three things: it opens, it edits, it saves. There is no autocomplete and no formatter.

Files it will not open

  • Files over 1MB, and files that are not text, do not open. You get the reason and one Open with default app button. macOS hands the file to whatever app knows it.
  • The editor does not open the markdown of tickets, personas, or protocols. Press one and you go to the screen that already handles that file. This is so that no place exists where the same file is open in two editors.
  • A file someone else changed after you read it does not get overwritten. Just before saving, it measures the file again, and if it has changed it does not write, and tells you. Workers run in this repository by the handful, so this comes up more often than you would think. Open it again, check, then save.

The exception - in-progress tickets

An in-progress ticket file cannot be edited on any screen. Press it in the explorer and the editor does not open; you go to the ticket page, where it says A session holds this ticket — editing and deleting are locked.

That is because a session is working on that file right now. All the while it works, it ticks the checkboxes in that file and writes ## 결과 (the result section). If a person overwrites the same file at the same time, one of the two disappears without a word. When you have to change it, press Unassign on the ticket page to put it back in the queue, then change it (see The states a ticket passes through). And if it really has to be touched right now, the way in through a terminal tab is not closed off.

Finding files

Two tabs sit at the top of the explorer's left panel: Tree and Find in files.

Finding by name is the field at the top of the Tree tab. As you type, the tree filters down to files whose names hold what you typed. It sweeps once under the project folder to build a list of names, leaving out .git, node_modules, and .next. Past 50,000 names it cuts there and tells you to narrow it down.

Finding by content is the Find in files tab. Type in the field, press Find, and lines holding those characters come up with the file name and the line number. Press a result row and that file opens at that line. Results stop at 200 lines, and the search stops at 10 seconds. If it was cut, that fact attaches as one line under the list, so narrow the search and run it again.

Both finds leave worktree copies out by default. With eight workers, the same file exists in nine copies and the results come back nine times over. Turn on Include worktree copies and those copies come in too.

⌘F finds inside what you are looking at

Press ⌘F and a find bar comes up over the top of the right-hand column. A count attaches as you type, reading something like 1/3. To the right of the count are two arrows and an X. The up arrow is previous and the down arrow is next, and pressing enter also takes you to the next one. Close it with Esc or the X and the highlighting goes away. That key is the default and you change it in the keymap under settings.

What the bar sweeps depends on the surface.

  • On the Explorer surface it is the one file you are looking at. Other files in the tree do not count. Characters you have not saved yet are found too. If you have not opened a single file, all you get is 0/0. Close the bar and the cursor goes back to the editor.
  • On the Terminal surface it is the one terminal tab you picked. It does not stop at the 32 rows on the screen. It searches the rows scrolling has carried above them as well, and it goes back 5,000 rows. When the hit is a row off the screen, pressing the down arrow brings that row into view. Close the bar and you carry straight on typing your command.
  • On the rest of the surfaces it sweeps the conversation thread still sitting on the right.

Change the surface or change the terminal tab and the bar closes. The count from before does not carry over to the new place.

Source control

Pick Source control and the left panel fills with every working folder in this project. Root at the top, Worktrees n below. The root is the project folder itself, and a worktree is one copy split off per worker (see Workers). In a project that does not use worktrees, only the Root row shows.

Pick one and what sits under it fills in.

  • The branch name and Ahead n · Behind n. That is how many commits ahead of and behind the upstream it is.
  • The upstream select. The current value is written there, and you change it by picking from the list of remote branches. If there is none yet it reads No upstream.
  • A Stage all button and two lists, Staged n and Working tree n. Press a row and it moves between the two lists. In front of the file name goes Modified · New · Deleted · Renamed.
  • The commit message field and Commit. You cannot press it while the staged list is empty or the message is empty.
  • Push and Pull.

In the message field, Cmd+Enter (Ctrl+Enter on Windows and Linux) does the same as pressing Commit. When the button cannot be pressed, the shortcut does nothing either.

Press a button and its label changes to an in-progress label ending in .... That tells you the app took the press and git is running. Until it finishes, pressing the other buttons does nothing. Press a file row and that row dims while the word on its right changes to the same kind of in-progress label.

When the label goes back, it is done. A commit, push, or pull that succeeds leaves one line under the buttons: Committed, Pushed, or Pulled. The line stays until you press another button or pick another working folder. If it fails, the reason shows up instead.

The commit message field is cleared only when the commit succeeds. If it fails, what you wrote stays in the field, so read the reason, fix it, and press again.

The app does not re-read this surface on its own. It reads the moment you open the surface, when you press Refresh, and right after a commit, a push, or a pull. Leave it open and walk away and no new git process starts. If a worker committed in the meantime, you have to press Refresh to see it.

Nothing is attached to a commit message automatically. The Ticket: line at the bottom of a worker's commits is put there by the worker as it wraps up. A commit a person makes here does not hang off a ticket.

Where Push goes

There is no field to choose. Which working folder you have picked is where it goes.

What you pickedWhere Push goes
A worktreeThe integration branch on this Mac
The rootThe upstream set for this branch (the remote branch shown in the upstream select)

Pushing from a worktree takes the same path the workers take. So that eight of them pushing at once do not collide, push.sh in the queue puts them in order (see Workers). In a project without that file, This project has no push.sh sits where the button would be. The app does not write one in for you.

When you press Push on the root, the app first fetches and merges the upstream the same way Pull does below, then sends to that remote branch. With no upstream you get NO_UPSTREAM and nothing is sent. If your git config would send the push somewhere other than the upstream (a different pushRemote or push refspec), it shows PUSH_TARGET_MISMATCH and stops. The app does not guess a destination.

Pull fetches the upstream, compares it with your branch, and acts on what it finds.

StateWhat Pull does
Same, or only yours is aheadChanges nothing and succeeds
Yours is only behindFast-forwards
Each side has commits the other lacksMakes one merge commit. The message is git's default

It never rebases and never rewrites existing commits. If there is something to bring in and the working tree has uncommitted changes, it shows DIRTY_CHECKOUT and does not start. If the merge hits a conflict, it aborts only the merge it just started (git merge --abort) and shows MERGE_CONFLICT with the reason git gave. The folder is back where it was before you pressed the button. To resolve the conflict and merge, use a terminal tab.

Browser

Some tickets need a worker to look at a screen. QA opening the deployed site, a designer checking the page they just changed. The worker brings up a browser with no window for that, so nothing appears on your screen and there is no way to tell what page it is on.

The Browser surface shows you. One row stands in the left panel per browser someone is holding, and the row carries the name of whoever holds it with the eight-character hash after it. When a ticket holds the browser, that name is the ticket's persona and title, and if the queue has no ticket under that hash the worker's own name stands there alone.

A browser opened from the home chat lands in the same list under the name Home chat, and one you started yourself by calling browse.sh in a terminal reads External call. A row opened by pressing a link inside the app reads Link (see The screens). Some rows carry a hash and nothing else. Those are older browsers, opened before the rule that writes the owner into the slot, and the app will not guess a name to fill the gap.

The small dot at the left end of a row means a command is running through that browser right now. Between commands it goes out. The name tells you who is holding the browser; the dot only tells you whether the screen is changing this second.

When nobody is using a browser, the panel reads No browsers running right now. The list rereads itself every five seconds.

Press a row and a tab opens on that hash. If the tab is already open, nothing new is made and you move to it. That makes four kinds of tab, and the limit of twelve is shared among all four. Up in the tab strip there is no room for a name, so a browser tab carries the hash alone with the same dot beside it.

Almost nothing in the app turns a browser on or off. Opening it and handing it back are the work of whoever holds it. The one exception is the Link browser: the screen opens that one and the screen hands it back. Close the tab and the browser keeps going. What closes is the one pipe carrying the picture. The row leaves the list on the left once the owner finishes and hands the browser back.

A row also goes when the owner dies without handing anything back, which is what a session cut off mid-run leaves behind. Within five seconds the row disappears and the browser still sitting in memory is cleaned up with it. The app clears only slots whose owner is already gone, so a browser held by a live session keeps running.

If you had that tab open when the row went, the screen turns into The browser was released and the screen went dark. The tab does not close itself, so close it by hand.

Touching it takes one approval

A browser tab opens locked. Press on the screen and the press never reaches the worker's page. What comes up instead is a confirmation:

A session is working in this browser right now. Touching it may throw off that run's measurements. Continue anyway?

Cancel and it stays locked. Approve and your mouse and keyboard go through from then on. The head of the screen reads <owner name> in use whether the screen is locked or open. While it is open, Input unlocked joins that same row and a Lock again button appears at the right-hand end, a marker put there so you do not forget it is open and keep clicking. Press Lock again and it locks straight away.

The reason for asking is that you are touching the same page as the worker. There is only one page, so scrolling moves what the worker was looking at too. If the worker was measuring the screen, the numbers for that run are off. Press if you need to, but press knowing the ticket's result is shaken once by it.

The approval is not kept. Close the tab or refresh and it starts locked again.

If all you want is to watch a running ticket's screen, you never have to come this far. The right-hand column of the ticket page lays that screen out with nothing to unfold (see The screens).

What is not here

  • There is no diff viewer. Press a file row and it opens in the editor.
  • There is no merge, no rebase, no branch creation, no tags.
  • There are no push --force, reset --hard, or stash buttons. The commands that undo things are left to people.
  • There is no autocomplete, no formatter, no debugger. Running things is the terminal tab's job.
  • It opens no remote server and no container. What it opens is the one folder of the project you registered.

If you need something that is not here, type it in a terminal tab. The app does not narrow what a person can do on their own Mac.

Next is Writing a ticket yourself.