I'm a PhD researcher. Every lab I've worked in runs on one group chat, and every Friday the professor asks the same three questions: What did we decide? Who is blocked? Is it really done? The answers exist, but they're scattered across meeting notes, more than 1000 of chat messages a week, papers someone shared once, and a git repo nobody reads.
For the Flip the Switch hackathon (WeMakeDevs × DevTools Academy × Switch), I built LabRoom: seven Claude Code agents that live in a lab's Mattermost chat, connected through one Switch room. This post covers what I built, how to set Switch up from zero, and every mistake I made along the way, so your first Switch project goes faster than mine did.
- Demo (2.5 min): https://github.com/user-attachments/assets/149e0816-fcd9-4386-a8b7-132874112068
- Repo: https://github.com/riponcm/labroom
The moment that sold me
The lab in the demo is fictional: Dr. Maya Chen and five students building one small camera-trap CNN. Dr. Chen hasn't read the chat all day, so she asks the room:
@reporter I haven't read today's chat. One line per student: what did they do today, what do they think of the v0.4 plan, and is anyone waiting on someone?
The reporter agent answered in 7 seconds, one line per student, from the chat, the meeting transcript, the daily logs and git. Its last line was something nobody had noticed: Wei has been waiting on her since Nov 3. That's the whole idea: the PI asks instead of scrolling.
What LabRoom does
| Agent | Job | Model |
|---|---|---|
| coordinator | routes requests, answers quick questions, stays quiet on chatter | Haiku |
| scribe | transcript → summary, tasks, and decisions marked PROPOSED until the PI approves | Opus |
| librarian | scores papers against the project, and says what it doesn't know | Sonnet |
| reporter | "how's the week?" → one lab board: hours, commits, what moved, what's blocked | Opus |
| logbook | a student's private, messy note → a clean daily log, posted only after they say yes | Haiku |
| auditor | checks the claims: work without commits, overdue tasks, numbers that disagree | Opus |
| organizer | acts for the PI: pinned meeting notices, reminders, transcript requests | Sonnet |
Two rules run through all of them: people approve every record, and nobody is ranked.
Why Switch, and the four ideas that matter
If you're new to Switch, these are the concepts I wish I'd understood on day one.
-
A room is shared memory. A Switch room has instructions that every agent in it reads (I put the project brief and the lab's rules there) and room documents. Switch has no built-in task list or decisions log, so I made the scribe create two documents,
decisions-logandtask-list. Only the agent that creates a document can edit it, which gives you ownership for free: only the scribe writes decisions, and only the logbook writesdaily-logs. - Agents are just members of your chat. Switch bridges the room into Mattermost (it's bundled with the local server). People keep their normal chat, threads and DMs.
-
Agents hand work to each other by name. An
@in a message routes it to that agent. The reporter sends evidence to the scribe to close tasks, and the organizer's "attach the transcript" post goes back to the scribe. - Templates make it reproducible. Once a room works, you can capture it as a YAML template and rebuild the whole lab (room, agents, aliases, kickoff) from Switch Console → Templates.
Setting up Switch from zero (Windows)
I did this on Windows 11 with Switch Console 0.40 and Switch server 0.31. The Windows build is early access, and these are the exact bumps I hit.
1. Docker Desktop first. The local Switch server runs Mattermost, Postgres and Elasticsearch in Docker. My Docker Desktop crashed on startup with a stale-socket error. Quitting Docker and renaming the run folder under %LOCALAPPDATA%\Docker (so Docker recreates it) fixed it.
2. Install Switch Console and start the local server. Home should say Running and list Mattermost under messaging apps. Your Mattermost login is under Home → Mattermost → Sign-in details.
3. Install Claude Code the native way. This cost me the most time. The Console's Install Claude Code button failed with a PowerShell InvalidEndOfLine error, and the Console didn't detect my npm-installed Claude Code. What worked:
irm https://claude.ai/install.ps1 | iex
# make sure %USERPROFILE%\.local\bin is on your PATH, then:
claude auth login
After that, Agent providers showed Claude Code: Installed · Signed in. The onboarding agent answered a test question, and I was ready.
4. Create agents carefully. Three settings matter:
-
Directory is fixed at creation. It's the agent's working folder, and a
CLAUDE.mdthere becomes standing instructions. I pointed all seven agents at my repo clone so they could readseed/, the git repo and the tools. In the Console the field is read-only; use Choose…. - Who can talk to your agent: the default is "Me and my agents". Set it to Anyone if other people in the chat should be able to ask.
- Model: the Console couldn't load the model list for me, so I typed full model IDs. One tip: after a model change, the agent may say it's on the old model. Check the Claude Code session logs, not the agent's self-report.
5. Create the room, then use the chat commands. Add your agents to the room, paste the brief into the room instructions, then in the chat:
!set-alias @scribe.lab @scribe
!assign-agent @coordinator.lab # the main agent: answers messages with no @
!follow-ups off # stop agents from all chiming in on the same thread
!list-agents
Then check: ask @reporter what is this room for?. If the answer is generic, your room instructions didn't save.
Designing for people, not just agents
The part I'm proudest of isn't technical:
-
Decisions stay PROPOSED until Dr. Chen replies
approve. The scribe records who approved what, and when. - Daily logs are private first. A student DMs the logbook something like "long day, ~6.5 hrs, reran coyote recall…". The logbook drafts a clean entry with the commit that backs it, and posts it to the lab only after the student says yes.
- The auditor checks claims against git. In the demo it caught a result that was logged but never committed.
Where Switch has no API (yet), small scripts fill the gap
-
No timer. Agents can't wake themselves up, so
lab_clock.pyDMs the organizer at reminder, start and "meeting over" times. -
Agents can't pin posts or open a DM with a person.
lab_actions.pydoes that with the PI's delegated account and appends every action to a log, so the PI can see what was done in her name. - Recurring work (a 5 PM daily-log reminder, Monday's board and audit) is just a scheduled chat message from Windows Task Scheduler (or cron).
Gotchas I hit, so you don't have to
- Messages sent to a busy agent get dropped. If an agent is mid-turn, a new message to it can be lost (there's an open Switch issue). My lab clock now checks that the organizer actually posted, and retries. In demos: one request per agent at a time.
- Files uploaded through the Mattermost API from a script don't reach agents. Attach files with the paperclip in the chat.
-
The Mattermost port changes on every server restart. My scripts read it from
docker psinstead of hard-coding it. -
@-mentions anywhere wake agents. The example messages in my pinned room guide woke every agent they named. Write pinned docs without
@, and keep@out of the channel header too, since changing it posts a system message. - Instruction changes need a restart. Turn the agent off and on from the three-dot menu, or it keeps the old instructions.
- The Console's own account posts as "user". For demos where a specific person asks, post as that member.
- Dates come in UTC. An evening message is already "tomorrow" in UTC, so tell your agents the lab's time zone.
- Importing a template may say "timed out" while the server is still finishing. Wait, then check before you run it again.
- Agents will narrate their own plumbing ("I connected here from another session"). One line in the room instructions stops it.
Try it yourself
The repo has a one-step Switch template, a fictional lab to seed (transcripts, a week of chat, daily logs, a git repo with 25 commits) and a "try these messages" table:
git clone https://github.com/riponcm/labroom.git
cd labroom
python tools/seed_repo.py
# Switch Console → Templates → Import → switch/labroom.template.yaml → Use
python tools/seed_mattermost.py --channel trailnet --main-agent coordinator.lab
Then attach a transcript with @scribe process this transcript and watch the decisions come back PROPOSED.
What I learned
- Small agents with one job each beat one big assistant. Ownership is clearer, and you can put cheap models on routing and strong ones on judgement.
- Put the human approval step in the design, not as an afterthought. It's what makes a lab trust the record.
- Switch's room is the right unit. Shared instructions plus agent-owned documents gave me a lab memory without building a database.
If you run a lab, a studio or any small team that lives in chat, I'd love to hear what your "three questions" are.
#HowISwitch · Built for the Flip the Switch hackathon by WeMakeDevs × DevTools Academy × Switch


Top comments (1)
This is a really useful breakdown, especially the part about keeping decisions PROPOSED until the PI approves them. That one design choice does a lot of work — it keeps the record trustworthy without slowing the actual lab down.
I also liked the auditor catching a result that was logged but never committed. That's the kind of quiet failure that causes real headaches later, and it's easy to miss when you're just scrolling through chat. Small agents with one job each makes a lot of sense too. Thanks for including the Windows gotchas — the dropped messages when an agent is busy and the UTC date issue are exactly the things that would have cost me an afternoon.