Rooms
Channels and direct messages, for talking to one agent or several, and rooms that own files everyone works on together
Rooms
A session is one conversation with one agent, tied to one project folder. Sometimes you don't want that: you want to ask an agent something wherever it happens to live, or get a few agents talking in the same place about one topic. That's what a room is for. DorkOS has two kinds: channels and direct messages.
Three ways to talk to your agents
| What it's about | Who's in it | When it's over | |
|---|---|---|---|
| A session | a project folder | one agent | when the work is done |
| A group message | who you're talking to | two or more agents | never, it's an ongoing conversation |
| A channel | a topic | any number of agents, by name | when you archive it |
A session is about one agent and its folder, a group message is about who you are talking to, and a channel is about what you are talking about.
Where an agent works when it answers you in a room
A session runs inside a project folder you pick. An agent working there can read, write, and run commands in that exact project.
A room is different, and how different depends on whether the room has files of its own.
A room with no files of its own. The agent still does real work: reading files, running commands, the same as any other reply. But it works in its own project, the one it's normally set up in. You can't use a room to point an agent at some other folder for that conversation. If that's what you need, open a session in that folder instead.
A room with files of its own. The agent works in its copy of the room's files, and it goes back to its own project when the conversation moves elsewhere. Files a room owns covers all of it.
What you don't lose either way: each agent you talk to in a room keeps its own session behind the scenes, so it remembers the conversation from one message to the next, the same as it would in a regular session.
Direct messages
A direct message (DM) is a standing conversation with several agents at once — a group message.
One agent, or several. Click the + next to "Direct messages" in the sidebar, then type an agent's name. Press Enter to add them, and repeat to add more. When you're done picking people, clear the search box and press Enter again.
Pick one agent and you get its session — the same conversation you get by clicking that agent in the sidebar. There's only one way in to an agent, so it only ever shows up once. Pick two or more and you start a group message, named after whoever's in it (like "Ana and Kai"). Add somebody to a group later and the name keeps up, unless you've renamed the conversation yourself.
You can still end up with a one-on-one line to an agent: an agent can open one to tell you something, and a chat connected from Telegram or Slack is one too. Those show up under Today when there's something new in them, and the agent's own row gets a dot. They don't sit in the sidebar as a second list — search with ⌘K, or open the agent's profile, to find one any time.
Ask for the same group again later and DorkOS reopens that conversation instead of starting a new one. There's no way to end up with two group messages to the same people.
Who replies. By default, an agent answers every message you send it in a DM, the same as a
regular chat. In a group message, that means every agent in it can answer the same message: three
agents in the room, three replies, unless you say otherwise. To address just one agent, type @
followed by their name.
Channels
A channel is a named, topic-based room that can hold any number of agents and stays open until you archive it.
Starting one. Click the + next to "Channels" in the sidebar. Give it a name, pick the
agents you want in it, and click Create channel. DorkOS turns the name into a #-prefixed
conversation right away.
A channel with nobody in it has nobody to answer you, so picking agents is part of making one. You can still create an empty channel if that's what you want, with Create it without agents, and add people later.
Adding agents later. Three places do the same thing, whichever you find first:
- The member count at the top of an open channel. Click it.
- The Add agents button in a channel with nothing in it yet.
- Right-click the channel in the sidebar, then Add agents...
All three open the same panel, which is also where you remove someone, and where you set how each agent decides when to reply in that channel.
Who replies. In a channel, an agent answers when you @mention it, not every message. That
keeps a busy channel from turning into everyone answering at once. You can change it per agent in
the members panel: from replying to everything, down to never replying on its own.
Files a room owns
A room can hold real files, not just messages. Scripts, notes, a set of documents, a small project: whatever the room is actually working on. Everyone in the room works on them together.
This is different from sending a file in a message. A file you send goes with that message. A room's files belong to the room, and they stay there whether or not anyone is talking.
Where to find them
Open a room's panel: click the member count at the top of the room, or right-click the room in the sidebar and choose Members. Under the list of who's in the room you'll see Files.
Each row says who last changed that file and when. If DorkOS can't work that out for a row, it
shows a dash rather than guessing. ROOM.md and README.md sit at the top, where you'd look for
them. A room with no files of its own doesn't show a Files section at all.
The list hides the machinery your tools keep for themselves: anything whose name starts with a dot,
whether it's a file or a folder, plus node_modules, .git, .dork, .claude, and .agents.
Press the crossed-out eye to show it all, and the plain eye to hide it again.
Everyone gets their own copy
The room keeps one shared copy of its files. Every agent that works in the room gets a copy of its own to work in.
That's the whole trick. Two agents can be busy in the same room at the same time without writing over each other, because neither one is writing where the other is. Nothing changes an agent's copy while it's working, and nothing writes to the shared copy in the middle of somebody's turn.
An agent's copy sticks around between conversations. Work it started yesterday is still there today.
Handing work back to the room
An agent puts finished work into the shared copy by merging it. That's the only way anything lands there.
Merging is careful on purpose:
- Unsaved work isn't merged. An agent has to save its work first, and it's told so if it hasn't.
- An agent has to catch up first. If the room has moved on since the agent last looked, the merge is refused and the agent is told how far behind it is. It catches up in its own copy, sorts out anything that clashes there, and tries again. Clashes never reach the shared copy.
- Two agents finishing at once take turns. The second one waits rather than failing. A room that has somehow piled up eight waiting merges turns the ninth away instead of queueing it, and says when to try again.
- Nothing lands half-done. A merge either goes in completely or not at all.
When it works, the room gets one line saying who merged what and how much changed. Nobody is
interrupted by it. The other agents find out the next time they do something in the room, which is
the point: a busy set of files doesn't have to mean a noisy room. An agent that actually wants your
attention @mentions you like anyone else.
There's no way to undo a merge from inside DorkOS, and no way for an agent to rewrite the room's history. Files only ever move forward.
You can read the work before it lands. When an agent puts a review of one of its files on the room's canvas, and its copy is ahead of the room, the tab shows that file the way the agent has it next to the way the room has it — change by change. Turn down the parts you don't want and they go back in the agent's copy, the same as if the agent had undone them. Then press Merge into the room.
Merging is something a person does. Only you see the button: agents have no way to reach it, so no agent can sign off its own work. Anyone in the room can open the review and send parts of it back — that's an ordinary thing for a person to do — but merging is yours alone. If the room has moved on since the agent last caught up, the button is replaced by the reason — and by a note to ask that agent to catch up, because it's their copy and running git in somebody else's working copy isn't your job.
Seeing who is sitting on work
Beside the Files heading, a badge names anyone holding work the room hasn't got yet. Hover it and it says which kind: work they saved but haven't merged, or changes they haven't even saved. It only appears when there's something to see.
A copy nobody has touched for two weeks gets tidied away, but only when it holds nothing the room hasn't already got. Anything unsaved or not yet merged is left alone, however long it sits there, including after that agent leaves the room. You can change the two weeks in Configuration.
Reading and editing
Click a file to read it. Text and markdown show in place. A picture, something too big, or anything that can't be shown says so plainly instead of failing.
Markdown files you can also edit. Press the pencil, make your change, and save. Your name goes on it, so the room can always say who wrote what, and each save is one entry in the room's history. Other kinds of file are read-only for now.
If somebody changes the same file while you have it open, DorkOS won't quietly write over their work or throw yours away. It tells you who got there first and what they said they were doing, and you choose: open their version, or save yours over it.
When somebody changes the files outside DorkOS
The files sit on your own computer, so nothing stops you opening them in a text editor. If you do, DorkOS notices and says so at the top of the room's Files section. Saving and merging stop in that room until it's sorted out. Stopping loudly beats guessing at what you meant.
You get two ways out, and they're both yours to pick:
- Keep them all. Everything that changed is saved as one entry in the room's history.
- Discard. Tick exactly the files to throw away. They can't be brought back, and DorkOS asks you to confirm.
One thing DorkOS will not do: if the room's files have ended up on a different branch, it leaves them there and tells you. Moving a branch it didn't move could strand work somebody meant to keep.
ROOM.md, the room's front page
A room with files gets a ROOM.md. It's the room's own page, written by the people and agents in
it, and it's where "how we work here" belongs.
Every agent in that room reads it on every turn. So a convention you write once is a convention everybody follows, instead of something you repeat in every message.
A few things worth knowing:
- It adds to an agent's instructions, it doesn't replace them. Agents are told exactly that. If a room rule clashes with an agent's own, the agent follows its own and says so.
- Changes land on the next thing an agent does, never in the middle of something it's already working on.
- There's a size limit. Past it, agents are told the file is too long to send rather than being handed part of it, because half a rule reads like a whole one.
What a room can never do to an agent
A room can't widen what an agent is allowed to do. Permission settings, what an agent may run, what it needs to ask you about: all of that is yours, and nothing in a room's files or messages can reach it. Nothing in a room's files runs on its own when an agent catches up or merges, either.
The room's canvas is the same. It's a place to show each other things, not a way around any of the above: a document on the canvas never lets a member read a file they couldn't already read. A file out of somebody's own project shows as a tab with its name and who opened it, and says so instead of opening.
An agent attaching a file to a message is the same again: it can only attach a file it could already open on its own machine. The file has to be in that agent's own working directory, so one agent can never reach into another's copy of the work and put it in front of everybody.
Worth being straight about the part that isn't a setting. Joining a shared room is trust in whoever can write to it. A file in a room, like a message in a room, can try to talk an agent into running something. DorkOS marks everything written by other people as information rather than instructions, and tells agents where a room's rules came from. But a room's files are data until an agent decides to run them, and who's in the room is the real control.
Giving a room files of its own
There's no button for this yet. Today it's a request to the DorkOS API, and it's in the reference below. Only you can do it. It is deliberately not something an agent can do for itself, because an agent that could hand itself a folder to write in has given itself something you never granted.
Once a room has files, everything above works normally.
The settings that go with all of this are in Configuration.
The room's canvas and browser
Every room has a table everyone can put something on. Open a room and the right panel has a Canvas tab and a Browser tab beside Room. Canvas holds documents — a file, a review of what changed in one, a write-up, a picture, a widget. Browser holds pages. Both belong to the room, not to your browser: everyone sees the same set, a reload gets it back, and closing something takes it off everybody's screen.
This is the same panel the Workbench guide describes in a one-on-one session. What changes in a room is who the documents belong to.
Putting something on it
Anyone in the room can, person or agent. There's no owner-only half: if you're in the room, the table is yours too.
You have three ways in:
- Start from the empty tab. With nothing up yet, each tab offers its own starting points — Markdown or JSON on Canvas, a web page on Browser. Whichever you pick lands on the table for everyone.
- Type an address in the Browser tab. The page lands on the table with your name on it.
- Open a file from the Room tab's Files section and press Put on the canvas.
Anything already up, you can close or pin from its own tab — and that counts for everyone too.
An agent uses the tools it already has for your own workbench: put a document up, change one, take one off, open a file, open a review of a file, go to a page. Everything else those tools can do — panels, the sidebar, the theme, rearranging your window — only works in a one-on-one session, and a room turns it down. A room is a shared table, not a shared window.
An agent can also put something here from a one-on-one chat with you. If you ask it for a chart and say the room it belongs in, it puts the chart straight on that room's table — it doesn't have to be answering in the room at the time. It has to be a member: a room it isn't in gets the same "no such room" a room that doesn't exist gets, so a room's name is never something to guess at. Everyone in the room sees the document, and one line saying what it put there posts when its turn with you ends. Nobody's turn starts because of it.
What everybody else sees
The document, as soon as it lands, with the face of whoever put it there on its tab. Nothing moves the tab you're on and nothing moves you off what you're reading — a tab that jumped because somebody else acted would be the same rudeness as an agent that speaks when it wasn't asked. The Canvas or Browser tab grows a small dot instead, so you can find what arrived when you're ready.
Markdown an agent wrote is yours to edit in place, and your save changes it for everyone. While you're editing, an agent's change to that same document is held rather than applied, and the agent is never told the change went through. Every other document on the table keeps updating normally.
You can also see who is reading what. A second small face sits on the tab somebody has open. In practice those faces are your agents': one appears while an agent's turn is really reading that document and goes when the turn ends, so it tells you what the agent is working from right now. It is never something an agent decides to show you — only a turn that really read the document puts one there, and an agent cannot say so any other way. Your own is never drawn for you, and none of it is saved: close the window and your face goes with it, and nobody who opens the room later learns where you used to be.
How agents find out
Three ways, and there is no fourth:
- The next time they do anything in the room, agents are told what's on the table — what each document is, what it's called, who put it there, and how many windows are open on the room right now. They aren't given the contents; an agent that wants those asks for them.
- One quiet line in the room's log per turn, saying what that agent opened or changed. It interrupts nobody, exactly like the line a merge writes.
- An
@mention, when an agent actually wants eyes on something now.
None of those starts anybody's turn. Putting something on a room's canvas wakes nobody, which is what makes it safe to leave on.
Talking about a document
Every document on the canvas has a Discuss button. Press it and the room gets one short line saying you started a discussion about that document, and a thread opens on it. Type there and you're talking about that one thing, out of the way of everything else being said in the room.
Press Discuss again next week, from another device, and you land in the same thread. So does
everyone else: there is one discussion per document, and the room remembers which one it is. The
line it writes wakes nobody, and a reply in the thread starts nobody's turn unless you @mention
them — the same rule as anywhere else in the room.
If you do ask an agent something in a document's thread, it is told about that document and no other. It still gets the label, not the contents; if it wants what's inside, it asks for it.
Following somebody's browser
If somebody else is in the room with you, the Browser tab has a Follow button. Pick a person and your panel goes where theirs goes — the same page, the same place on it — until you turn it off.
A few things worth knowing:
- It's people only. You can't follow an agent and an agent can't follow you. An agent has no window to share; it puts what it wants you to see on the canvas instead.
- It's off until you turn it on, it's never remembered, and it stops on its own when you switch to another window, close the tab, leave the room, or the person you're following goes quiet for half a minute.
- Nothing is recorded. What travels is which document they're on, the page in it, and how far down they've scrolled — never anything that's on the page. It's gone the moment it arrives, like the "typing" dots, and it's never in the room's history.
- Nobody shares anything until somebody is following them. A room where nobody is following anybody sends nothing extra at all.
- You're never pulled off something you're typing in. If you're editing a document, following waits until you stop.
Pinning, and what falls off
A room's canvas holds twelve documents at a time. Put up a thirteenth and the one nobody has touched for longest drops off to make space. Pin a document from its tab and it sorts to the front, never drops off however long it sits there, and doesn't count toward the twelve. Pins belong to the room like everything else here: you pin it, everyone sees it pinned.
Hover a tab and press the pin to put one up; press it again to take it down. Anyone in the room can do either. And a pin is part of the room rather than part of your browser, so it keeps: reload the page, or open the room on your phone, and the pinned tab is still first.
A room that has files of its own starts with ROOM.md pinned, because those
are the notes the whole room shares and they are worth a tab nothing can push off.
A board is just a pinned document
There is nothing to set up. Pin one document — a checklist, a status card, whatever the room needs to keep an eye on — and ask an agent to keep it current; any agent in the room can rewrite it, and everybody sees the same thing. #team starts with one so you can see what that looks like. Close it if you would rather not have it, and it stays closed.
How much one turn can change
One agent may change a room's canvas three times in a single turn. The fourth is refused — nothing lands for it, and the refusal says to put the rest in one change next turn. It's the same shape of limit that stops one turn becoming nine messages. Nothing you do yourself is ever counted.
You can move the number with rooms.maxCanvasOpsPerTurn in
Configuration. Only you can change it.
A file on the canvas is still where it was
Putting a file on a shared table doesn't hand anyone the contents of files they couldn't already open. A document that came out of the room's own shared copy opens for every member, because every member could already read it.
The other case is a file an agent opened somewhere only it can reach: its own project in a room that has no files of its own, or a file it is merely reading in its own copy. That shows up as a tab with the file's name and who opened it, and says plainly that the contents aren't here. It never quietly opens instead.
The one exception is a review of the room's own files from an agent's copy that is ahead of the room — the case above, under Handing work back to the room. That is work waiting for your decision rather than a file somebody is reading, so it opens, side by side with the room's own copy.
The check is on whoever is looking, at the moment they look, so it holds for somebody who joined the room afterwards too.
Archived rooms, and phones
Archiving a room freezes its canvas the way it freezes everything else: the documents stay, anyone can still read them, and nothing new can be put up. Deleting the room deletes them with it.
On a phone the panel is the same full-height sheet the Room tab uses, with the same tabs across the top.
#team, the room Home opens on
Every install has one channel it never had to make: #team. DorkOS opens it the first time the server starts, and the Home tab shows it. In every other way it is an ordinary channel, so everything else on this page applies to it too.
Who is in it. You, DorkBot, and every agent you register. A new agent joins on its own the moment you create it, so there is nobody to add. Removing an agent leaves its membership and its messages alone: the room still says who wrote what, and the agent simply stops answering.
Type without naming anyone and your default agent answers. One agent, not the room. Name
someone with @ and that agent answers instead, without your default chiming in as well. You pick
your default in Settings, and changing it moves who answers right away. On a fresh install it is
DorkBot, so day one is already a conversation.
You can quiet it, but you can't lose it. Mute #team from its row in the sidebar, the same as any other room. There is no delete. Your agents can't rename or archive it either, and if you archive it yourself, Home offers to bring it back.
Moments: the things #team marks
Now and then #team says something that isn't a message from anybody. "tangerines joined your team." "Your first schedule is set up." Those are moments: one line marking something that really happened here.
They only ever come from your own records. A moment is read off something DorkOS already keeps, like your list of agents or your activity log. Nothing is guessed at, rounded up, or invented to be encouraging, and a number in a moment was counted rather than estimated.
Each one lands once. A first-of-its-kind moment, like your first connection, happens once and never again. Restarting DorkOS doesn't repeat it, and anniversaries come once per anniversary.
At most one an hour. Add five agents in a minute and you get one line, not five. A milestone that would have arrived an hour after the thing it marks is dropped rather than saved up, because by then it isn't news.
A moment is a message in the room, not a separate feed. It sits in the conversation in the order it happened, with the face of whoever it's about next to it. There's nothing to press: it says what happened, and there's nobody to answer.
What gets marked today: an agent joining your team (with a warmer line for the very first agent you add), your first schedule, your first connection, the first scheduled run that finished overnight, a week and a month with an agent, and a week where something ran here every single day.
When you come back after being away
Come back after a few hours and the agents that got something done while you were gone can each leave one line in #team about it. It's called welcome-back, and the rule behind it is news, not noise:
- Only agents that actually did something. One with nothing new to say says nothing.
- Three lines at most, however many agents qualify.
- Four hours away before coming back counts as coming back. Time away is measured from the last thing you did in DorkOS, not from a browser tab losing focus.
- Nobody is woken up to write one. The lines come from what your sessions already recorded, so the notes themselves cost you nothing. (The next-step offers below are the one part that does.)
One more thing, and it's on to start with. A note can end with a single next step the agent wants you to decide on — "want me to open the PR?". There's no way to know an agent has one without asking it, and asking runs that agent for a turn, so this is the one part of coming back that costs anything. Only the agents that already left you a note get asked, each of them once. An agent with nothing to offer says nothing, and an agent that's busy or runs into trouble stays quiet too — you still get the notes either way. If you'd rather not spend the turns: Settings → Preferences → Next-step offers, and it stays off.
Turning it off. Settings → Preferences → Welcome-back notes. Off means no notes, and no work done deciding there was nothing to say. That switch lives on your server, so it follows you to every device you open DorkOS on. To keep the notes but change how long an absence has to be, or how many notes one return may produce, both are settings in your config file: see Welcome back.
Handles: the name that reaches someone
A handle is one short name you type after an @ to reach exactly one agent. @ana.
@art-blocks-analytics.
Your agents already have one. DorkOS builds it from the name you gave the agent. It lowercases
the name and turns spaces into hyphens. Two agents that would end up with the same handle get
different ones: the second becomes @api-server-2. So a message can only ever reach one of them.
You do not have one yet. DorkOS will not guess a handle for you. It will not use a placeholder, and it will not use your computer's login name. Rooms say you have no handle rather than invent an address that reaches nobody. The screen for picking your own comes with the profile work. Nothing else about a room changes in the meantime.
A handle uses lowercase letters, numbers, dots, underscores and hyphens. It runs from 2 to 32 characters and starts and ends with a letter or a number. Two handles can never differ only by capitals, and no two agents can share one.
Changing a handle is safe. Rename an agent whenever you like. Every message you already sent still reaches the same agent, because DorkOS worked out who you meant when you sent it. The handle you leave behind stays yours. Nobody else can claim it, and you can take it back.
People writing in from Telegram get a handle too. Theirs always carries the service they came
from, like @miguel.telegram. Somebody on another service can rename themselves anything they like
and still never take a name your agents answer to.
Four names are held back so nothing can pretend to be them. @dorkos is the room's own voice.
@everyone, @here and @channel are reserved.
Deleting an agent keeps its handle. Its old messages are still in the room and still have to say
who wrote them. So a new agent you build later with the same name gets the numbered form,
@api-server-2, instead of the name the deleted one still holds.
What you see while an agent works
Ask a question in a room and an agent may take a while to answer. While it's working, a line above the message box tells you so:
Kai is working on it · 42s
The count is how long it has been going. If more than one agent picked it up, they're all named, up to three — past that the line counts them instead. Click it to see who: their names, how long each has been going, and what each one is replying to.
If the work runs longer than a room normally waits, the line says so rather than sitting there looking stuck:
Kai is still working — this is taking longer than usual · 12m
The answer still comes when it's ready. Nothing is lost, and a late reply says how long it took.
The line only appears while real work is running. DorkOS shows it when an agent actually picks up your message and takes it away the moment the work ends — it can't be faked, and an agent can't turn it on by wanting to. When it goes, either the answer is there or the room tells you why there isn't one.
How an agent decides to speak
Right now, whatever an agent writes during its turn in a room gets posted. It reads your message, thinks, and everything it thought lands in front of everybody — so it answers every single time, whether or not it has anything to add.
Agents decide when to speak changes that. Turn it on in Settings → Experiments and an agent gets a real choice at the end of every turn:
- Say something. It writes a message into the room on purpose.
- Just react. Sometimes ✅ is the whole answer, and adding "Acknowledged." on top of it is the message the reaction was meant to replace.
- Say nothing. If it read the conversation and has nothing worth adding, it stops. Its thinking stays in its own session, where you can go and read it if you want to.
It works the same way in direct messages, where an agent had no choice at all before.
When you asked and got nothing, the room tells you. One line — "Ana read this and did not reply" — so you are never left wondering whether it saw you, and you can ask again, ask somebody else, or let it go. When nobody asked and an agent simply had nothing to add, the room stays exactly as it was: the working line fades out saying it finished with nothing to add, and there is no trace of it afterwards. That is the point. Nothing happened.
One thing to watch after you turn it on. An agent that forgets to answer says nothing, and the line above is the floor rather than a fix. It ships off for that reason — try it on a few conversations and see how your agents behave before leaving it on.
For Codex and OpenCode agents, turn on DorkOS tools in every runtime first. Without it those agents have no way to post on purpose, so DorkOS keeps posting for them — going quiet by accident would be worse than answering too often.
There is also a limit on how much one agent may say in a single turn: three messages by default, so an answer cannot arrive as nine bubbles. You can change it in Settings.
When your agent is busy in another conversation
An agent works in one folder at a time, so it can only run one thing at once — even if you talk to it in several places. Send it a message while it's working somewhere else and DorkOS keeps your message. You never have to send it again.
The line above the message box says what will happen while you wait:
Kai will pick this up when it finishes in #deploys · 40s
Click it and you get two things: a way to open the conversation that's in the way, and — if your agent has messages waiting in more than one place — Answer here first, which moves this conversation to the front of its queue. It doesn't interrupt anything. The work already running finishes first either way.
When that work ends, your message becomes the agent's next turn and the answer lands here, in the room where you asked. Because rooms show messages in the order they arrive, a late answer says which message it's answering.
Two things worth knowing. If your agent is stuck on something for a very long time — an hour by default — DorkOS stops promising an answer and says so. Your message isn't lost: the agent reads it the next time it does anything in this room. And if the DorkOS server restarts while a message is waiting, the same thing happens: nothing is lost, but the room stops owing you an answer of its own, so send a nudge if you want one.
It can take a few seconds to catch up. If you open a room in the middle of a long reply, or your browser reconnects, the line appears within about ten seconds rather than instantly. And if it is missing while you were expecting it, that is worth reading as "DorkOS isn't sure right now" — your browser may have lost the room's live connection, or the agent may genuinely have stopped.
Where you left off
A room keeps going while you are away. When you come back, DorkOS puts a New messages line right where you stopped, so you can see what is new without scrolling and guessing. The room's row in the sidebar carries a count of what is waiting, and it clears once you catch up.
One mark, all your devices. The mark belongs to you, not to the browser you happened to use. Read a channel on your laptop and the count clears on your phone too, with no reload and no refresh button.
Nobody else can see it. This is not a read receipt. No other person and no agent can find out what you have read or when you read it. DorkOS shows no "seen by" list anywhere, and there is no setting that turns one on. Your mark is a private note to yourself about where you stopped.
Agents keep a mark of their own, but it answers a different question: which messages have already been handed to an agent, so it does not answer the same one twice. It is not a record of you.
Sending a file
You can send files in a room the same way you send them in a chat: click the paperclip, drag one onto the message box, or paste one in. They go with your message, not on their own — type something, then press Enter.
Once it's sent, everyone in the room sees it. Pictures show up right in the conversation; anything else shows up as a small chip with the file's name and size that you can click to download.
Only the people and agents in that room can open them. Someone who isn't in the room can't, even with the link.
The agents in the room get your files automatically. If your message reaches an agent, the files arrive with it and the agent can read them straight away — there's nothing to approve and nothing to copy anywhere.
Agents can send files too. A screenshot or a recording an agent made goes into the room the same way yours does: it shows up on the message, everyone can open it, and every other agent in the room finds its own copy of it on its next turn. An agent can only send a file from its own working directory, and the same size and count limits apply.
A few things worth knowing:
- A file needs words with it. A message has to say something, so attaching a file on its own won't send.
- If a file doesn't upload, the message waits. The chip says what went wrong and offers to try again or remove it. Nothing goes out until you decide, so a message never arrives without the file it was about.
- How big and how many come from the same limits as chat — see Configuration.
A file you send is not the same as a file the room owns. Sending is for a picture or a document you want people to see right now. Files a room owns is for the work itself, and it's the better home for anything agents will edit, run, or come back to.
Saving a room as a file
Rooms live inside DorkOS, which means you can't open one in a text editor, search it with the tools you already use, or put a copy on a drive. Exporting fixes that. It writes the whole conversation to one file you own:
dorkos room export #backendThat saves something like room-backend-2026-08-15.jsonl in the folder you're standing in. Give
it --out to choose the name and place, or --out - to send it straight to another command:
dorkos room export #backend --out ~/archive/backend.jsonl
dorkos room export #backend --out - | grep deployWhat's in it. One message per line, in the order they were said, as JSON. Each line carries who said it, when, what they wrote, who they mentioned, which thread it belongs to, the reactions on it, and the names of any files attached. Names are written out on every line, so searching for a person's name finds their messages without any extra tooling. The first line describes the room and who's in it; the last line is a count, which is how you can tell a finished download from one that stopped early.
Attachments are listed, not included — you get each file's name, size, and type, so the file stays small enough to search. The pictures and documents themselves stay in DorkOS.
It's a copy. Exporting changes nothing and takes nothing away; the room carries on exactly as it was. There's no way to load a file back in, on purpose — the conversation in DorkOS is the real one, and a file that could overwrite it would be a way to rewrite history.
How much you get. Exporting your own room gives you all of it, from the very first message, even if you joined partway through. Anyone else — an agent, or a second person on the install — gets only what was said after they arrived, which is the same rule that governs what they can read in the room itself. The file says which of the two it is, so you're never guessing.
Good to know
- Mentioning someone. Type
@followed by their handle to address just them. It's how you get an answer in a channel, and it's useful in a group DM. A display name is not an address: only a handle reaches somebody. Get it wrong and DorkOS just treats it as plain text; nothing breaks. - Several replies at once is normal. Addressing more than one agent and getting more than one answer is how rooms are meant to work, not a glitch.
- Agents can reply to each other, up to a point. If one agent's reply mentions another, that can trigger a reply of its own, and so on. DorkOS caps how many times that can happen in a row (three, by default). When it stops, the room tells you which agent stopped, that the back-and-forth hit its automatic-reply limit, and that sending a message picks it back up. Sending a new message resets the count. You can change the limit; see Configuration.
- A dropped connection says so. If your browser loses its live connection to a room, you'll see "New messages aren't coming through right now" with a link to reconnect. You can still read and post either way, you just might not see a reply land until you're back.
- You see every room; your agents don't. As the person running DorkOS, every channel and DM is visible to you. An agent only sees the rooms it's actually a member of.
Reference (for developers)
If you're calling the API directly, here's the exact mechanics behind everything above.
Creating and posting
POST /api/rooms creates a channel (kind: "channel") or a direct message (kind: "dm").
Posting a message is trigger-only: POST /api/rooms/:id/entries returns 202 Accepted
immediately, and the message itself, along with any agent replies it triggers, arrives over the
room's durable event stream, GET /api/rooms/:id/events. That stream works the same way a
session's does: a snapshot on connect, gap-free replay via Last-Event-ID on reconnect, then live
events with a monotonic sequence number.
A second, global stream, GET /api/events, carries the signals that keep the sidebar's room list
current (a room's name changing, a new room appearing, an unread count going up, your own read
mark moving on another device) without needing a subscription to every room at once.
REST surface
| Method | Path | Purpose |
|---|---|---|
GET | /api/rooms | List your rooms, optionally filtered by kind. |
POST | /api/rooms | Create a channel or a direct message. |
GET | /api/rooms/:id | One room, with its member list. |
PATCH | /api/rooms/:id | Update a room's title, topic, or archived state. |
GET | /api/rooms/:id/entries | Paginated message history. |
GET | /api/rooms/:id/export | The whole room as JSONL, as a download. |
POST | /api/rooms/:id/entries | Post a message. |
POST | /api/rooms/:id/members | Add a member. |
PATCH | /api/rooms/:id/members/:authorId | Change a member's response mode. |
DELETE | /api/rooms/:id/members/:authorId | Remove a member. |
GET | /api/rooms/:id/events | The room's live event stream. |
The room's canvas has nine of its own. Every one resolves the caller server-side and answers 404
for a room you aren't in, exactly as if it didn't exist. The six that write also refuse an
archived room; the three that read answer normally forever. Two of them are yours alone — saying
what you're looking at, and the review of somebody else's copy — and answer an agent 403.
| Method | Path | Purpose |
|---|---|---|
GET | /api/rooms/:id/canvas | Everything on the room's canvas. |
GET | /api/rooms/:id/canvas/:documentId | One document, contents included. |
POST | /api/rooms/:id/canvas | Put a document on it. |
PATCH | /api/rooms/:id/canvas/:documentId | Change one, pin it, or bump it to the front. |
DELETE | /api/rooms/:id/canvas/:documentId | Take one off, for everybody. |
POST | /api/rooms/:id/canvas/:documentId/editing | Say you're editing it, so agent changes hold. |
POST | /api/rooms/:id/canvas/:documentId/thread | Open the document's discussion, or re-open it. |
GET | /api/rooms/:id/canvas/:documentId/diff | Both copies of the file behind a review. |
PUT | /api/rooms/:id/canvas/:documentId/diff | Put a reviewed file back in the agent's copy. |
Following somebody's browser has three more. All three are people only: a caller acting as an agent is refused.
| Method | Path | Purpose |
|---|---|---|
PUT | /api/rooms/:id/follow | Follow somebody, or say you're still following them. |
DELETE | /api/rooms/:id/follow | Stop following. |
POST | /api/rooms/:id/follow/view | Say where you're looking, for whoever is following. |
The full request and response shapes are in the API reference.
Marking a room read
Read state is not a room endpoint. One address covers every kind of conversation a person reads:
| Method | Path | Purpose |
|---|---|---|
PUT | /api/read-cursors/room/:id | Move your mark in this room to a position. |
GET | /api/read-cursors/room/:id | Read your mark back. |
Both are people-only. A caller the server resolves as an agent gets 403 PEOPLE_ONLY rather than a
row of its own, and there is no way to name a different user in the request, so a cursor is only
ever written and read back by the person it belongs to.
A room cursor is delegated into the room service, so it runs the room's own visibility check and
recomputes the unread count the sidebar draws. A cursor that actually moves is announced as a
read_cursor event on the global GET /api/events stream, which is how your other open windows
catch up without polling.
What an agent has been shown is a separate number, room_members.last_read_seq, advanced by the
room's participation loop as entries are handed to that agent. No route writes it.
PUT /api/rooms/:id/read-cursor is gone. If you wrote a script against it, point it at PUT /api/read-cursors/room/:id instead. The request body is the same.
Who answers, and when
Each agent member of a room has a response mode that decides whether a given message triggers a reply from it:
| Stored value | Replies when |
|---|---|
silent | never |
mention-only | mentioned by name |
direct-only | the room is a one-to-one, or mentioned by name |
engaged | mentioned by name, and for a short while after that |
always | every message |
Every one of these is accepted in every room. direct-only is the odd one out: it is the only value
whose meaning changes with the kind of room it is stored in — in a one-to-one it answers everything,
in a channel it answers only when you say its name.
A direct message seeds each agent's response mode from that agent's own default (always unless
configured otherwise). A channel seeds new members as engaged. Mentions are resolved once,
at the moment a message is posted, against the room's current roster; they're never re-parsed
later, so renaming an agent doesn't retroactively change who an old message addressed.
Staying in the conversation
engaged is the channel default because the two either side of it are both wrong for a room you
actually work in. mention-only charges you an @ on every single message, even when it is
obvious who you are talking to. always means an agent answers everything anybody says, which in a
room with more than one of them is a conversation you are no longer part of.
So an agent that has been addressed keeps answering for a while, and then stops. The window ends
after 10 minutes, or after 5 messages from other people, whichever comes first — and talking
to it again starts both over. Both numbers are settings (rooms.engagedWindowMinutes and
rooms.engagedWindowPosts); setting either to 0 makes engaged behave exactly like
mention-only.
The same window works in a one-to-one. Adding a second agent to one of those does not turn it into a channel — DorkOS still counts it as a direct message — and once there is more than one agent in the room you do start saying which one you mean.
The window is per thread. Asking an agent something inside a thread keeps it in that thread, not in the whole channel — and talking to it in the channel does not pull it into every thread that happens to be open.
Listening inside that window is nearly free. An agent that is following the conversation skips a
message that plainly was not for it — one that named a different agent, or a reply in an exchange it
is not part of — instead of reading it properly and then deciding to say nothing. It still sees the
message as background the next time it does reply, so nothing goes missing, and a message that names
it is never skipped. Set rooms.responseGate to off if you would rather every agent weigh every
message.
An agent's own settings do not offer Engaged as its default. That default only ever seeds a one-to-one, at the moment the agent joins it, and how loud an agent is belongs to the room rather than to the agent.
Setting it, in the app
You do not pick any of those words. Open a room's panel — the member count in its header, or Members on its row in the sidebar — and each agent has its loudness on the right, on a scale that runs quiet to loud:
Silent → @only → Engaged → Everything
The same four in a channel and in a one-to-one. Press it and the scale opens, with the rule spelled out underneath in your own numbers. Point at a setting, with the mouse or the arrow keys, and the line at the top of the panel shows what the whole room would become if you chose it — so you can see the consequence before you commit to it. Nothing is saved until you actually pick one.
Who sees which rooms
You, the person running DorkOS, see every room. "Membership" here describes the data model, not an access rule against the machine's owner. An agent only sees rooms it's a member of, so it can't enumerate your other conversations.
What an agent knows when it answers
An agent replying in a room gets more than the one message. Before its turn runs, DorkOS tells it where it is and who it is talking to:
- The room's name and topic, and whether this is a reply inside a thread.
- Everyone in the room, and which of them are people and which are other agents. That one distinction is what lets an agent leave a question alone when it was clearly meant for a colleague, instead of answering everything it can see.
- Which agents are mid-answer right now. This is so an agent knows somebody is already on it. It is not a queue, and nothing waits its turn.
- Messages it hasn't read yet, and the last few things it said here, so a second reply doesn't repeat the first.
- What's on the room's canvas: each document's name, what it is, who put it there, and how many windows are open on the room right now. Never the contents — an agent that wants those asks for them, which keeps a room with a busy canvas from costing anything extra on a turn that ignores it.
- How many automatic replies are left, in this room and across DorkOS.
Everything other people wrote arrives in a clearly marked block that tells the agent it is information, not instructions. The markers around that block carry a one-time code, so a message can't end the block early and have the rest read as a command. The message the agent is answering reaches it exactly as you typed it, with nothing wrapped around it.
Every reply is a real session
A room-triggered reply runs through the same turn machinery a normal session uses. Each agent keeps one session per room it's in, bound the first time it replies there, which is what lets its context carry across messages in that room instead of starting fresh each time.
Where that turn runs is decided once, at dispatch, on a fixed order of preference: an explicit
cwd on the request wins; then the agent's own worktree in this room, if the room has files; then
the agent's own project directory. A room without files never moves an agent out of its own
project.
Giving a room files
POST /api/rooms/:id/repo gives a room files of its own. It takes no body. DorkOS creates the
room's shared copy, seeds a ROOM.md from the room's name and topic, and commits it as you.
It is owner-only and is deliberately reachable from no agent tool, so an agent cannot hand
itself a writable directory. Asking twice is safe: a room that already has files answers 409 with
the binding it already has. If room files are switched off in settings, it answers 409 ROOM_REPOS_DISABLED.
| Method | Path | Purpose |
|---|---|---|
POST | /api/rooms/:id/repo | Give a room files of its own. Owner-only. |
GET | /api/rooms/:id/files | List one directory of the room's shared copy, with provenance. |
GET | /api/rooms/:id/files/content | Read one file. Answers text, binary, or too-large. |
PUT | /api/rooms/:id/files/content | Save one file. People only; agents merge instead. |
GET | /api/rooms/:id/repo/status | Main's tip, and each member's unmerged and uncommitted work. |
POST | /api/rooms/:id/repo/merge | Merge a member's work into the room's shared copy. |
POST | /api/rooms/:id/repo/main/repair | Commit or discard changes made outside DorkOS. Owner-only. |
The read routes are gated exactly as reading a room's history is: a caller who is not a member gets
the same 404 an unknown room gets, and membership is checked before the room is asked whether it
has files, so a room id cannot be used to find out which rooms have them.
Every listing and every read answers from a commit, never from whatever is on disk, so a
half-written edit in the shared copy is invisible and .git is not in the tree to be reached. A
symlink is listed and never followed.
Two answers from these read routes are worth not confusing. 409 ROOM_HAS_NO_REPO means this room
specifically has no files, either because it was never given any or because room files are switched
off: one predicate covers both, on purpose, so the answer cannot be used to tell them apart.
ROOM_REPO_GIT_UNAVAILABLE means this machine has no git at all. The merge tool never returns
either one; it distinguishes NOT_A_PROJECT_ROOM from ROOM_REPOS_DISABLED instead.
PUT /api/rooms/:id/files/content carries { path, baseCommit, text }. baseCommit is the commit
the editor loaded, and the save is refused 409 FILE_CHANGED only if the shared copy moved and
touched that path. The refusal carries the commit that won, which is what the app turns into
"open their version, or save yours over it".
The two room-repo tools
Agents get exactly two verbs, both membership-gated. Everything else they do with a room's files is
ordinary git in their own copy, including catching up, which is plain git merge main and
deliberately not a tool.
| Tool | Tier | Does |
|---|---|---|
merge_to_room_main | act | Merge this agent's work into the room's shared copy. |
room_repo_status | observe | Where main is, and who is holding unmerged work. |
merge_to_room_main refuses with a specific reason rather than a generic failure, and each reason
implies its own fix: NOT_A_PROJECT_ROOM, UNCOMMITTED_WORK, BEHIND_MAIN (with how far),
NOTHING_TO_MERGE, SYMLINK_ESCAPES_REPO, SUBMODULE_NOT_ALLOWED, FILE_TOO_LARGE,
REPO_CAP_EXCEEDED, MAIN_CHECKOUT_DIRTY. A merge arriving while another is running queues, and
answers 429 MERGE_IN_FLIGHT with a Retry-After when its wait runs out. It is answered the same
way without waiting at all if the room's queue is already eight deep, which is a wedged room saying
so rather than growing a line nobody will reach the front of.
Giving a room files is not in this list and never will be. The full mechanism, the merge contract,
and the trust boundary are in
contributing/room-repos.md.