Workspace
One local folder at the account level. Files, artifacts, and handoff attachments all live here, and all Bots share it. Bots are not isolated from each other. It says where work is kept, so every Bot's output is managed in one place; it is not a permission boundary: what a Bot may do is set by its permission mode, whether a path is in the workspace or not (ADR 0092). The sidebar can open the whole workspace folder (on desktop it is a pane with a file tree and a preview, and it does not take over the artifact preview beside the conversation; on narrow screens and phones it is still an overlay that slides in from the right); UTF-8 text files in the workspace can be edited in the viewer and saved back to the same path.
Avoid: cloud computer, one folder per Bot, sandbox (unless a separate one is added later)
Work dir
A plan's folder, under the workspace's work/, named after the first 12 code points of the Goal (or of the opening request) plus a short id, with no date; under it, each ticket has its own NN-<title>/. A turn's work dir is the folder of the ticket it is filed under, or the plan folder if it is not filed under a ticket; the shell runs in it by default, while file tool paths stay relative to the workspace root. Both levels have reserved subfolders, tool-results/ and scratch/, neither ever attached as an artifact; map.md and ticket.md are the app's mirror files and likewise do not count as artifacts. Details: Behavior · Work dir.
Behavior details
Level-2 attribution: the directory comes from the current work item's plan/ticket, not the waking turn's ticket or an organizer stamp. An unbound desk may not act; the one-change bound and protected Continue are under Desk segment. Directory names, reserved files and previews below still apply; inheritance, the single current plan and organizing first describe level-0/1 legacy paths only. This change neither makes the work directory a sandbox nor claims every proposed cross-ticket write restriction is enforced.
A plan's folder, under the workspace's work/, named after the first 12 code points of the Goal (or of the opening request) plus a short id, with no date and no @ (it becomes -, so citing a file inside does not read as a mention; older folders with a date or an @ are left as they are); under it, each ticket has its own NN-<title>/, with any @ in the title replaced the same way. A turn's work dir is the folder of the ticket it is filed under, or the plan folder if it is not filed under a ticket; the shell runs in it by default, while file tool paths stay relative to the workspace root. Who inherits it: handoffs, mentions, joining in after a judgement, Bot↔Bot directs, resuming an interrupted run, and check-backs all use the plan and ticket of the waking turn, so one piece of work stays in one place across Bots and sessions; your message is stamped with a plan and ticket by the organizer, and every turn it opens lands there. Folders are not switched by the clock: a session's current plan stays open until the organizer judges that the work has moved on to a different thing, returned to an earlier one, or is done or parked. A routine has its own standing plan and opens a new ticket each time it fires. The folder is created only when it is first actually used, so turns that only talk leave no empty folder behind. Deliverables are not forced into it: if you named a path, they are written there; if you did not, they land in this turn's ticket folder. Both levels have reserved subfolders: tool-results/ holds large tool results saved by the daemon (cleared automatically once the plan has been closed long enough), and scratch/ holds purely intermediate files; neither is ever attached as an artifact. map.md and ticket.md are the app's mirror files and likewise do not count as artifacts. Deleting a work dir is up to you; the app only clears tool-results/. In the app, you read the work's trace from top to bottom along who woke whom; each card shows which ticket it worked on, artifacts hang on the turn that handed them over, and clicking one opens it in the preview.
Avoid: one folder per Bot, artifact library, treating it as a sandbox, the app deleting the whole folder for you, the app moving files to archive them, switching folders by date or by idle time
Artifact
A workspace-relative path, a file or folder on this machine written as an absolute path (outside the workspace too, read-only), or an http/https link, referenced in a message; the file itself lives in the workspace, elsewhere on the machine (or at the remote URL), and files written during a turn appear in its final message automatically (not those the turn deleted again). Opening one shows it in the preview panel to the right of the chat (image / audio and video / PDF / text / single-file HTML / Word / Excel / PowerPoint); other kinds offer a download or opening with the default app. In a handoff, the path goes into the message to the other party, with no separate kind; artifacts inside the workspace can be annotated (see "Annotation"). Details: Behavior · Artifact.
Behavior details
A workspace-relative path, a file or folder on this machine written as an absolute path (/Users/…, ~/…, C:\…, outside the workspace too), or an http/https link, referenced in a message. The file itself lives in the workspace, elsewhere on the machine (or at the remote URL). The workspace bounds where Bots work, not what you can open: a folder outside it lists what is in it and its files preview as usual, but read-only — no typing in the source view, no annotations, no Move to Trash from the tree (ADR 0090). Files inside the workspace written during a turn appear in its final message automatically; not those the turn deleted again, nor anything in a folder it deleted — on 2026-10-04's real-model run a Bot wrote slogans.md at the workspace root, wrote it again in its ticket's folder and deleted the first, and the group showed two slogans.md bubbles, one of them gone. Opening one shows it in the preview panel to the right of the chat (image / audio and video / PDF / text / single-file HTML / Word / Excel / PowerPoint); other kinds (subtitles, archives…) state that preview is not supported: the app window on this machine offers "Open with default app", and phones and browsers offer a download button. Every file opened remotely can be downloaded: on a phone from the right end of the preview's top bar, on wide screens from the row of buttons above the file, and on the flow board's file cards from the card header. Opening remotely, downloading and sending attachments have no file size limit; on desktop this preview can also be dragged out into a pane of its own. Opened from a message, the tree on the left of the panel lists only the files that message names — its attachments and the paths its text points to — not what other messages in the job referenced. Opened from a file card on the flow board, it lists every path this job has referenced — not every file in the work dir; "associated" means it has been referenced. That tree is rooted at the work dir, paths this job referenced outside that directory sit flat beside it, and the ones this step itself references are marked. The panel shares one column with the chat, with a drag bar between them to change the width; when one message has several paths, or when you open the workspace, the left side is a file tree, and the split between tree and content can be dragged. Preview column and file tree widths you have dragged are still there after you quit and reopen. Text is edited with Monaco + Shiki (line numbers, find / replace via ⌘F, bracket and tag matching, heading folding, line wrap); the preview itself no longer has find, wrap, copy, save or close buttons. Markdown and single-file HTML show the rendered result by default; a floating button at the top center of the content, which does not scroll with the body, switches between preview and source. One with more than 500,000 characters of text opens as source, with no such button and a line at the top saying why (rendering that much holds the window for seconds, a phone for longer; for HTML only the text the page shows counts, so a report carrying megabytes of inline chart script still renders). PDFs are rendered with the built-in pdf.js (paging, zoom, fit width / whole page, in-page find), not the system PDF viewer. UTF-8 text inside the workspace can be written back to the same path with Cmd+S / save. Text that is not UTF-8 is read as GBK (GB18030), or, when that fails too, with the characters it cannot read replaced; either way it is read-only here, as a line at the top says (saving writes UTF-8, and would change the file's encoding or lose the bytes that could not be read); switching files or closing the panel with unsaved changes asks for confirmation first. On desktop the preview has no title bar of its own: the file name and close are on the workbench tab; narrow screens and phones keep a strip with back and the file name. A device on a remote connection has no workbench tabs either, whatever its width (a tablet included): there the preview opens as a full screen of its own with that same strip, not a column beside the chat — before 2026-10-08 that column offered no way to close it at all on such screens. Right-clicking any item in the file tree offers "Show in Finder" and "Open with default app", which take effect only in the app window on this machine. A file a Bot or a project session's agent names in a message (its inline chip, a picture's card too) has the same menu on a right click: "Open with default app", "Show in Finder" and "Copy absolute path". A Bot's path is looked up in the workspace, a project agent's in the directory it worked in; a path that is not found, or found in several places, gets a short notice. For now only the native (NSH) build's window on this Mac offers it: on a phone, in a browser or in a remote window the files are on another computer, and the Windows and Linux shells cannot open files yet, so there a right click still opens the message's menu. Files and folders in the tree (several at once when picked with ⌘ or Shift) can be dragged straight onto the composer, which lights up under the pointer; dropped, they wait above the input as attachments and go out with the next message by their workspace path — nothing is uploaded or copied into inbox/, the Bot reads them as "附件:path" lines, and pictures still reach the model as pixels. Esc during the drag puts them back. The file-drop session, read-only conversations and a composer that is still sending take nothing; there is no dragging on phones or touch screens. In a handoff, the path goes into the message to the other party; there is no separate kind. The kind is inferred from the extension at preview time. A file named in a message's text shows as a small chip led by an icon picked from that same kind (folder, picture, audio, video, PDF and documents, sheet, slides, Markdown, code, archive); a path ending in / counts as a folder, and a link to a picture shows as a thumbnail card. Artifacts inside the workspace can be annotated (see "Annotation").
Avoid: asset library, Artifact table, snapshot copy, per-Bot artifact folder, @file
Annotation
A remark you write about one spot in an artifact, attached to a workspace-relative path, an anchor, and the message that delivered the artifact. It starts as a draft the Bot cannot see; drafts collect into a batch sent all at once as one reply that quotes the delivering message and @-mentions the Bot that delivered it; once sent it is "Pending", and a Bot or you mark it "Resolved", and a resolved one can be reopened. An annotation is not a snapshot of the artifact: it records only the quote, position and file hash at the time and does not keep the old file; only files inside the workspace can be annotated, and link artifacts cannot. A project session has no Bot: there you annotate files in the project directory, each attached to its absolute path and one of the agent's replies; a batch goes out as your line to the agent (no quote, no @), and only you mark one resolved (ADR 0095 decision 28). Details: Behavior · Annotation.
Behavior details
A remark you write about one spot in an artifact. It is attached to a workspace-relative path, an anchor, and the message that delivered the artifact. It starts as a draft the Bot cannot see; drafts collect into a batch that is sent all at once, combined into one reply that quotes the delivering message and @-mentions the Bot that delivered it. Once sent it is "Pending", and a Bot or you mark it "Resolved"; a resolved one can be reopened. As soon as it is marked resolved it comes off the file — the box on an image, the dot in the code margin, the mark in Markdown, the box on a PDF page, the number on HTML, the marker on a timeline — so what stays on the file is what is still unresolved; the list keeps listing them all. The list has tabs for All / Pending / Resolved / Drafts, each with its count, and each state has one colour — Pending teal (as the marks drawn on the file), Resolved green, Drafts grey and dashed — on the tab's dot, the row's left edge and its state label; an empty tab shows the app's usual empty state, saying what would appear there. They are drawn back only when "Show resolved" is checked in the preview column, and only for that preview; clicking a resolved one in the list to locate it draws that one while it is located, and clicking it again to deselect takes it down; clicking its card in the conversation only opens the list at that item and does not draw it back on the file. When the file has changed and the anchor no longer matches, it is marked "Text changed" and its status stays the same; when the file is gone, it is marked "File gone". An annotation is not a snapshot of the artifact: it records only the quote, position and file hash at the time and does not keep the old file (when the selection is longer than the quote limit, it also records the whole span's length and fingerprint, used to tell whether that span is still there and whether it has changed). What it attaches to: a preview opened from a message attaches to that message and the Bot that delivered it; when the delivering message is in a Bot↔Bot direct you are not in, the batch goes to your direct with the delivering Bot, and the message records the origin. Only files inside the workspace can be annotated; link artifacts cannot. Each Bot that an annotation message wakes keeps the work dir of the turn in which it delivered the artifact (its most recent delivery in this batch), even if the session has been quiet long enough for that job to have closed — it is changing the same deliverable; this turn only works in that directory: it does not reopen that job or take the session's current plan's place, likewise when that job belongs to another session (it was delivered in a Bot↔Bot direct), and what each of the two sessions is carrying on with is unaffected. It is an ordinary follow-up message: it lands on the delivering turn and joins the correction chain, with no extra weight. A batch holds at most 50 annotations, and each body at most 2000 characters. In a group, one batch can go to several Bots at once: in the context, every annotation states which Bot it is for (the Bot that delivered that artifact, or "a deleted Bot" if it has been deleted), and list_annotations includes this too; each Bot handles only the ones for itself and leaves the ones for other Bots to those Bots, though it may mention them; ones for a deleted Bot have no one to take them, so the Bots this batch woke handle them. What a Bot can do: work through the ones for itself one by one; mark the ones it changed as resolved with resolve_annotation, with one sentence on how it changed them (any Bot can mark one — a Bot is not a permission boundary — and who marked it is recorded); check what is still unresolved with list_annotations (paths resolve the same way as in read_file, and a path outside the workspace is an error right away); and it gets a reminder when read_file reads a file that still has pending annotations. What a Bot cannot do: reopen, delete or create annotations. Clearing history or deleting a session deletes the annotations attached to those messages along with them; deleting a file does not delete its annotations. Anchor kinds: text / code line range, a selection in rendered Markdown, a box drawn on an image, a region on a PDF page, an HTML element, an audio / video time point.
In a project session (ADR 0095 decision 28): there is no Bot. You annotate files in the project directory, each attached to its absolute path and one of the agent's replies, with bot_id null; a batch goes out as your line in that session (no quote, no @, no job), and the agent gets that line with every annotation spelled out and its crops. Only you mark one resolved: a Bot's resolve_annotation refuses them, and list_annotations and read_file's reminder leave them out. Details: Project sessions.
Avoid: comment (kept for a possible multi-person future), review, a new message kind, annotations storing old versions, waking once per annotation, a Bot annotating for you
Attachment
A file you drop into the chat, copied into the workspace's inbox/, with a link to that copy kept on the message. A remote connection also has a session just for sending files: files sent there also go into inbox/; you can send text there too, and the text stays only in that session; that session has no Bot and wakes no one. A file sent in an ordinary session still wakes that session. When a Bot attaches a file already in the workspace as an artifact, it uses the same attachment rows, but nothing is copied and nothing goes into inbox/; so does a file or folder you drag from the file tree into the composer, which goes out as its own path (the file-drop session does not take these). The workspace is the computer; attachments are not a second file system. Raster images that enter a turn's window are sent to the model as pixels, but a turn carries at most 20 images and 20 MB: they are taken from newest to oldest starting at the trigger message, and older images that do not fit keep only their path; a large image is first scaled down to 1568 on its long edge, and an opaque one is converted to JPEG before it is sent. When a Bot itself reads a PNG / JPEG / GIF / WebP in the workspace with read_file, the image is scaled the same way and attached as an image after that step's tool result: at most 12 images and 8 MB per step; these images take their share of the turn's 20 images and 20 MB first, and the transcript window gets what remains; when later-read images do not fit, earlier-read ones are moved out in the order they were read, keeping only their path, and to see one again the Bot reads it again. Other files are given only as paths; reading them goes through read_file.
Avoid: a ghost file that exists only on the message
Search
Lookup across Bots, groups, files and routines that jumps back to the spot in the original session. In v1 it is a local search on this Mac, not another Bot.
Avoid: semantic memory layer
Mirror files
map.md in the plan folder (the plan's fields plus a ticket index) and ticket.md in each ticket folder (that ticket's fields, with the plan's Done when and Rules attached), rewritten by the daemon after every organizing pass and after every edit you make to the plan. They are the app's own files: a Bot may read them with read_file, but may not edit them or hand them over, and they are not artifacts; the plan folder is created the first time the plan is written up. To change their content, edit the plan or the tickets on the flow board.
Avoid: editing mirror files by hand, treating a mirror file as a deliverable, having a Bot maintain them, using them as the single source of truth (the database is)