<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Akshay R</title>
    <description>The latest articles on DEV Community by Akshay R (@imakii).</description>
    <link>https://dev.to/imakii</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4188471%2F5ab5c393-465a-42a7-9835-98ea5befd177.png</url>
      <title>DEV Community: Akshay R</title>
      <link>https://dev.to/imakii</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imakii"/>
    <language>en</language>
    <item>
      <title>Hermit: a creature with no home, built on Switch</title>
      <dc:creator>Akshay R</dc:creator>
      <pubDate>Sat, 07 Nov 2026 15:37:05 +0000</pubDate>
      <link>https://dev.to/imakii/hermit-a-creature-with-no-home-built-on-switch-6l3</link>
      <guid>https://dev.to/imakii/hermit-a-creature-with-no-home-built-on-switch-6l3</guid>
      <description>&lt;p&gt;&lt;em&gt;How three friends built a tiny visitor that wanders between our laptops, carries favors, and grows a shared shell, with Switch as its nervous system.&lt;/em&gt; Flip the Switch · Track 02: Best Personal or Creative Workflow · Nov 7, 2026 · Akshay (@Im-Akii)&lt;/p&gt;

&lt;h2&gt;
  
  
  Friends don't drift apart because of distance
&lt;/h2&gt;

&lt;p&gt;We are three friends in Bengaluru: Afreen, Abhishek and Akshay. We live about 25 km apart, and we still go weeks without talking. Nobody is avoiding anybody. Somebody just has to start every conversation, and a group chat makes that feel like a chore.&lt;/p&gt;

&lt;p&gt;So we built a reason to reach out that starts itself. &lt;strong&gt;Hermit&lt;/strong&gt; is a small creature with no home of its own. It lives on one friend's laptop at a time, borrows that friend's AI as its voice, and moves on when they go quiet. On its way, it carries a small favor to whoever is awake next.&lt;/p&gt;

&lt;p&gt;Finish the favor and a piece grows on Hermit's shell. Over days, the shell becomes a record of small things we actually did for each other. Every part of this runs on &lt;strong&gt;Switch&lt;/strong&gt;: the presence, the handoff, the favors, the notes and the shared memory all travel through Switch rooms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkxn8gmfw7ay3q939eaok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkxn8gmfw7ay3q939eaok.png" alt="The Hermit journey page: hero, mascot preview and the three-step loop" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Hermit journey page. The banner marks this route as sample data; the live parts of Hermit are shown further down.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post walks through what we built, how we set Switch up from nothing on three Windows laptops, and what we learned the hard way. If you have never used Switch, the setup section is written for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How to read the screenshots.&lt;/strong&gt; We label every image. &lt;strong&gt;Live (real Switch)&lt;/strong&gt; means our keepers talked to a real Switch server. &lt;strong&gt;Stand-in&lt;/strong&gt; means the real keeper code running against a local copy of Switch's HTTP API. &lt;strong&gt;Sample&lt;/strong&gt; and &lt;strong&gt;Simulation&lt;/strong&gt; mean made-up data. We would rather show you less than show you something that isn't true.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Meet Hermit: one visit, start to finish
&lt;/h2&gt;

&lt;p&gt;Hermit's whole game is one loop: arrive, carry, hand on, grow. Here is one full visit, captured from our app with three keepers running the real code against a Switch stand-in on one machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Hermit arrives on whoever is at the keyboard
&lt;/h3&gt;

&lt;p&gt;Each laptop runs a small Python process we call the &lt;strong&gt;keeper&lt;/strong&gt;. It watches one thing: is my person at the keyboard right now? When someone has been active for a minute and nobody else holds Hermit, their keeper claims it. A little creature walks onto their desktop.&lt;/p&gt;

&lt;p&gt;The creature is a transparent, always-on-top window. It never blocks clicks on the apps underneath it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftkvbgfag13zhh7u2kw1l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftkvbgfag13zhh7u2kw1l.png" alt="Hermit on a real Windows desktop, over another app" width="443" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hermit sitting on a real Windows desktop, on top of whatever you are doing. The small square is its shell badge.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The host leaves a favor for the next friend
&lt;/h3&gt;

&lt;p&gt;While Hermit is with Akshay, he opens Hermit's menu and leaves a favor: "Share one song that got you through this week." His keeper writes a &lt;code&gt;FAVOR_LEFT&lt;/code&gt; line into the shared Switch ledger room. Hermit is now carrying it, but nobody knows yet who will receive it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr80fllmffobzpi7bkexd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr80fllmffobzpi7bkexd.png" alt="Akshay's menu: Hermit is carrying his favor" width="800" height="1448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Akshay's menu (stand-in run). The brain badge shows which AI is hosting (the stand-in hands out brains by default; on his real laptop Akshay runs Claude Code). The Quest tab shows the favor Hermit is carrying.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Friends can reach the host without opening a chat
&lt;/h3&gt;

&lt;p&gt;Abhishek is not hosting, so his menu offers a &lt;strong&gt;Friends&lt;/strong&gt; tab. He types a short note and presses &lt;strong&gt;Send through Switch&lt;/strong&gt;. His keeper works out who holds Hermit from the ledger, and the note appears in a speech bubble on Akshay's desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4dbohuz9q1fksrnkrp6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4dbohuz9q1fksrnkrp6e.png" alt="Abhishek's Friends tab with Send through Switch" width="800" height="1448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fesxpnrofar93mrlg3bc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fesxpnrofar93mrlg3bc0.png" alt="The note arriving on Akshay's critter" width="640" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Above: Abhishek's Friends tab. Below: the note arriving on Akshay's critter (stand-in run).&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Hermit moves on when its host goes quiet
&lt;/h3&gt;

&lt;p&gt;Akshay steps away. After his idle threshold and minimum stay, his keeper releases Hermit and writes &lt;code&gt;SOUL_RELEASED&lt;/code&gt;. Abhishek is awake, so his keeper claims it. Every screen updates: Akshay's Hermit curls up asleep and says where it went.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqgxz03u64xro1ovx7s2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqgxz03u64xro1ovx7s2.png" alt="Akshay's Hermit asleep, saying it is with Abhishek" width="640" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Akshay's desktop after the handoff: Hermit is asleep here and tells him it is with Abhishek.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The favor is delivered, and the shell grows
&lt;/h3&gt;

&lt;p&gt;Abhishek's keeper reads the open favor from the ledger and assigns it to him: &lt;code&gt;FAVOR_ASSIGNED&lt;/code&gt;. His Hermit arrives with an envelope and a red mark. He shares his song and presses &lt;strong&gt;I did it · grow the shell&lt;/strong&gt;. &lt;code&gt;FAVOR_COMPLETED&lt;/code&gt; and &lt;code&gt;SHELL_PIECE_ADDED&lt;/code&gt; go into the ledger, and every keeper folds the new piece into its view of the shell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F554d7m53rgp2x8zbdbdp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F554d7m53rgp2x8zbdbdp.png" alt="Abhishek's Hermit arrives with an envelope" width="640" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvolpgqr5e5sh4n1vtre.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvolpgqr5e5sh4n1vtre.png" alt="Abhishek's Quest tab: favor from Akshay, assigned" width="800" height="1448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Abhishek's Hermit arrives carrying Akshay's favor, and the Quest tab offers to grow the shell.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7smc0k6anab4pip47dcu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7smc0k6anab4pip47dcu.png" alt="Abhishek's Shell tab: one piece" width="800" height="1448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;After he finishes it: one shell piece. Afreen's keeper, which was never involved, reported the same piece from the ledger.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That last detail matters. Three separate processes, with three separate memories, agree on one shell because they all read the same Switch room.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Switch is the engine, not a plugin
&lt;/h2&gt;

&lt;p&gt;Hermit has no server of ours. Three laptops on three home networks share exactly one thing: a self-hosted Switch server. Take Switch away and Hermit stops, by design. The keepers report &lt;code&gt;switch: offline&lt;/code&gt;, the holder becomes unknown, and nothing pretends otherwise.&lt;/p&gt;

&lt;p&gt;We use Switch in two roles at once. It is the &lt;strong&gt;group's shared memory&lt;/strong&gt;: every presence beat, claim, release, favor, note and shell piece is a line in a Switch room. It is also &lt;strong&gt;where people and AI agents meet&lt;/strong&gt;: each friend's own coding agent joins the same rooms as Hermit's brain.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Switch feature&lt;/th&gt;
&lt;th&gt;What Hermit uses it for&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rooms + agent HTTP API (&lt;code&gt;POST /agents/{id}/message&lt;/code&gt;, &lt;code&gt;GET /agents/{id}/events&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;hermit-ledger&lt;/code&gt; is the group's only shared memory. The holder, the group view, favors and the shell are all folds over its lines.&lt;/td&gt;
&lt;td&gt;Verified on a real &lt;code&gt;switch-v0.9.0&lt;/code&gt; server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom agents (&lt;code&gt;POST /agents&lt;/code&gt;, &lt;code&gt;connector_type: custom&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Each keeper is a registered Switch agent, &lt;code&gt;keeper-&amp;lt;you&amp;gt;&lt;/code&gt;, sitting in rooms beside coding agents.&lt;/td&gt;
&lt;td&gt;Verified live: all three keepers registered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coding agents in Switch Console&lt;/td&gt;
&lt;td&gt;Each friend's brain, &lt;code&gt;hermit-&amp;lt;you&amp;gt;&lt;/code&gt;, is their own off-the-shelf agent: Claude Code, Codex or OpenCode.&lt;/td&gt;
&lt;td&gt;Akshay's Claude Code is detected and signed in; agent creation in progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent working directory&lt;/td&gt;
&lt;td&gt;Each brain can only see &lt;code&gt;~/HermitWindow&lt;/code&gt;, so Switch enforces our privacy promise.&lt;/td&gt;
&lt;td&gt;Part of setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exclusive role + role instructions&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;soul&lt;/code&gt; role: whoever holds it &lt;em&gt;is&lt;/em&gt; Hermit, and Hermit's personality is the role's instruction text.&lt;/td&gt;
&lt;td&gt;Read in Switch source; not yet proven live&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session-bound lease&lt;/td&gt;
&lt;td&gt;A slammed lid frees the soul without a goodbye; the stop is recorded as abrupt with a cracked shell piece.&lt;/td&gt;
&lt;td&gt;Read in source; expiry not measured yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Room instructions&lt;/td&gt;
&lt;td&gt;House rules: bedtime, "mute", privacy, one soul.&lt;/td&gt;
&lt;td&gt;Written, pasted in Console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-hosted, bring your own agent&lt;/td&gt;
&lt;td&gt;No central server and no AI bill. Messages stay on the group's own machine.&lt;/td&gt;
&lt;td&gt;By design&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Two holder modes, and why we're upfront about them
&lt;/h3&gt;

&lt;p&gt;The cleanest design gives each friend's AI an &lt;strong&gt;exclusive Switch role&lt;/strong&gt; called &lt;code&gt;soul&lt;/code&gt;. A second &lt;code&gt;assume_role&lt;/code&gt; fails, so there can never be two Hermits. We built that path (&lt;code&gt;agent_instructed&lt;/code&gt;), but the role step needs a connected brain, and we have not proven it on the live server yet.&lt;/p&gt;

&lt;p&gt;So the mode we actually run today is &lt;code&gt;keeper_claimed&lt;/code&gt;. The keepers claim Hermit themselves, and the &lt;strong&gt;order of lines in the Switch ledger&lt;/strong&gt; settles who won. Switch orders the claims but does not enforce them. Our tests show the keepers still never produce two holders, and we say clearly which guarantee is ours and which would be Switch's.&lt;/p&gt;

&lt;h3&gt;
  
  
  What breaks without Switch
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No shared holder.&lt;/strong&gt; Keepers cannot agree who has Hermit, so they show "offline" instead of guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No favors, notes or shell.&lt;/strong&gt; Each of those is a room event. Without the room, nothing crosses laptops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No meeting place.&lt;/strong&gt; Friends and their AI agents have nowhere in common to talk to Hermit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How the pieces fit
&lt;/h2&gt;

&lt;p&gt;Every laptop runs the same three pieces, and they all meet in one Switch server reached over Tailscale.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fihlwmfzwpo93qiwiiq43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fihlwmfzwpo93qiwiiq43.png" alt="Hermit's architecture: one Switch server, two rooms, three laptops" width="799" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The keeper and the brain on each laptop are both Switch agents. The critter only ever talks to its own keeper, on loopback.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Talks to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Keeper&lt;/strong&gt; (&lt;code&gt;keeper-&amp;lt;you&amp;gt;&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Python 3.11+, FastAPI. Watches keyboard idleness, runs the state machine, folds the ledger, serves a local API on &lt;code&gt;127.0.0.1:47800&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Switch over HTTP; the critter over loopback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Brain&lt;/strong&gt; (&lt;code&gt;hermit-&amp;lt;you&amp;gt;&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;The friend's own coding agent, onboarded in Switch Console, scoped to &lt;code&gt;~/HermitWindow&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Switch rooms, as a normal Switch agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Critter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Electron + React. A transparent always-on-top window plus Hermit's menu.&lt;/td&gt;
&lt;td&gt;Only its own keeper, on loopback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Journey map&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vite + React static page. Exported history, plus an optional live card.&lt;/td&gt;
&lt;td&gt;A &lt;code&gt;journey.json&lt;/code&gt; export; optionally the local keeper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Switch server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;switch-v0.9.0&lt;/code&gt; in Docker on Afreen's laptop, with the Gateway and Mattermost.&lt;/td&gt;
&lt;td&gt;Everyone, over the tailnet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two rooms carry everything. &lt;strong&gt;&lt;code&gt;hermit-den&lt;/code&gt;&lt;/strong&gt; is where friends and Hermit talk, and where the &lt;code&gt;soul&lt;/code&gt; role lives. &lt;strong&gt;&lt;code&gt;hermit-ledger&lt;/code&gt;&lt;/strong&gt; is a machine room of &lt;code&gt;HERMIT/1&lt;/code&gt; lines: heartbeats, claims, releases, favors, notes and shell pieces. Humans can read it, but nobody needs to.&lt;/p&gt;

&lt;p&gt;The keeper has exactly &lt;strong&gt;one&lt;/strong&gt; background reader of &lt;code&gt;GET /agents/{id}/events&lt;/code&gt;. That endpoint is a draining queue, so a second reader would silently steal events. The reader buffers what it receives, and every view in the keeper reads from that buffer.&lt;/p&gt;

&lt;p&gt;The critter and map never talk to Switch. They read the keeper's loopback API, so no Switch key ever reaches a browser or an Electron renderer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Switch from zero: a first-timer's walkthrough
&lt;/h2&gt;

&lt;p&gt;None of us had used Switch before this hackathon. This is the path that worked for three Windows laptops on three home networks, including the screens that confused us. Allow about an hour for the server and 20 minutes per laptop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: pick one machine to host the server, and keep it awake
&lt;/h3&gt;

&lt;p&gt;One laptop runs the Switch stack for everyone. If it sleeps, Hermit stops for the whole group. On Windows, set &lt;strong&gt;Settings → System → Power → sleep when plugged in → Never&lt;/strong&gt;, and set the lid action to &lt;strong&gt;Do nothing&lt;/strong&gt; while plugged in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: start the released Switch stack in Docker
&lt;/h3&gt;

&lt;p&gt;We ran the released &lt;code&gt;v0.9.0&lt;/code&gt; compose file with the collaboration and gateway profiles. That gives you the API on &lt;code&gt;:8000&lt;/code&gt;, the Gateway admin site on &lt;code&gt;:3000&lt;/code&gt; and Mattermost on &lt;code&gt;:8065&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; deploy/local/standalone-v0.9.0.yml &lt;span class="nt"&gt;--profile&lt;/span&gt; collab &lt;span class="nt"&gt;--profile&lt;/span&gt; gateway &lt;span class="nt"&gt;--project-directory&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check it with &lt;code&gt;curl http://127.0.0.1:8000/health&lt;/code&gt; before you go any further.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: connect everyone with Tailscale, not port forwarding
&lt;/h3&gt;

&lt;p&gt;The stack binds to &lt;code&gt;127.0.0.1&lt;/code&gt; by default. We put all three laptops on one private Tailscale tailnet and set &lt;code&gt;SWITCH_BIND_ADDR&lt;/code&gt; to the host's &lt;code&gt;100.x.y.z&lt;/code&gt; Tailscale address. Nothing is exposed to the public internet.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The host creates a tailnet and invites the others by email.&lt;/li&gt;
&lt;li&gt;Each friend installs Tailscale, accepts, and signs in. A new user may need the admin's approval in the Tailscale console.&lt;/li&gt;
&lt;li&gt;From every laptop, &lt;code&gt;curl http://&amp;lt;100.x.y.z&amp;gt;:8000/health&lt;/code&gt; must return 200.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4: register a keeper agent for each laptop
&lt;/h3&gt;

&lt;p&gt;A custom agent is one HTTP call. Use the server's registration token once, and keep each agent's own key from then on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://&amp;lt;server&amp;gt;:8000/agents &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;AGENT_REGISTRATION_TOKEN&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"content-type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "keeper-akshay", "connector_type": "custom", ...}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns &lt;code&gt;{id, api_key}&lt;/code&gt;. Our &lt;code&gt;bootstrap_rooms.py&lt;/code&gt; script registers all three keepers and creates both rooms, writing keys only to a git-ignored file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: install Switch Console and join the server
&lt;/h3&gt;

&lt;p&gt;Download the Console installer from the official Switch README. On first run:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;Join an existing server&lt;/strong&gt;, not "On this computer" (that starts a second server).&lt;/li&gt;
&lt;li&gt;Enter the API address, &lt;code&gt;http://&amp;lt;100.x.y.z&amp;gt;:8000&lt;/code&gt;, not the Gateway port.&lt;/li&gt;
&lt;li&gt;Sign in with your own Switch account. The host creates it in the Gateway's &lt;strong&gt;Users&lt;/strong&gt; page at &lt;code&gt;:3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If it says &lt;strong&gt;We can't find any of your workspaces&lt;/strong&gt;, choose &lt;strong&gt;Skip&lt;/strong&gt;. Home then showed &lt;strong&gt;Connected&lt;/strong&gt; for us.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 6: onboard your own coding agent as Hermit's brain
&lt;/h3&gt;

&lt;p&gt;First check &lt;strong&gt;Settings → Agent providers&lt;/strong&gt;. Your CLI must show &lt;strong&gt;Installed&lt;/strong&gt;. Akshay's Claude Code CLI (v2.1.318) was detected automatically from his PATH, already signed in. Then go to &lt;strong&gt;Your Agents → +&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run location&lt;/td&gt;
&lt;td&gt;this computer&lt;/td&gt;
&lt;td&gt;the brain runs on your laptop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent provider&lt;/td&gt;
&lt;td&gt;Claude Code, Codex or OpenCode&lt;/td&gt;
&lt;td&gt;a different brain per friend is the point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Working directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/HermitWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the only folder Hermit's brain can see&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hermit-&amp;lt;you&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;must match &lt;code&gt;brain_agent&lt;/code&gt; in the keeper config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who can talk to your agent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Anyone&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the default, &lt;em&gt;Only me&lt;/em&gt;, silently blocks the keeper and your friends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bypass permissions&lt;/td&gt;
&lt;td&gt;off&lt;/td&gt;
&lt;td&gt;Hermit never needs it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Put Hermit's stage directions in &lt;code&gt;~/HermitWindow/CLAUDE.md&lt;/code&gt; (Claude Code) or &lt;code&gt;AGENTS.md&lt;/code&gt; (Codex, OpenCode).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: create the rooms and invite everyone
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;hermit-den&lt;/code&gt; with a messaging app and paste the house rules into its &lt;strong&gt;Instructions&lt;/strong&gt;. Create &lt;code&gt;hermit-ledger&lt;/code&gt; with no messaging app. In each room, invite every agent with &lt;code&gt;!invite-agent @hermit-akshay&lt;/code&gt;, and so on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: point the keeper at Switch and run it
&lt;/h3&gt;

&lt;p&gt;The keeper reads a git-ignored &lt;code&gt;hermit.config.toml&lt;/code&gt; with your host id, area-level location, server URL, agent id and the two room ids. The key lives only in an environment variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;HERMIT_SWITCH_TOKEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your keeper api_key&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hermit_keeper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--switch&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hermit_keeper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;pnpm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;hermit/critter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;check --switch&lt;/code&gt; probes &lt;code&gt;/health&lt;/code&gt;, then makes one authenticated, non-draining call with your key. When &lt;code&gt;http://127.0.0.1:47800/v1/group&lt;/code&gt; lists every friend, you are connected.&lt;/p&gt;

&lt;h3&gt;
  
  
  The gotchas that cost us the most time
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Brain ignores the keeper and friends&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;Who can talk to your agent&lt;/em&gt; was left on &lt;strong&gt;Only me&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Set it to &lt;strong&gt;Anyone&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console's "Full admin interface" fails, 404 toasts&lt;/td&gt;
&lt;td&gt;Console v0.40.1 is much newer than server v0.9.0&lt;/td&gt;
&lt;td&gt;Use the Gateway web admin at &lt;code&gt;:3000&lt;/code&gt; for users and agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;curl&lt;/code&gt; to the server times out&lt;/td&gt;
&lt;td&gt;the host laptop slept, or left the tailnet&lt;/td&gt;
&lt;td&gt;Keep it plugged in and awake; check &lt;code&gt;tailscale status&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tailscale CLI login hangs on Windows&lt;/td&gt;
&lt;td&gt;the device was logged out&lt;/td&gt;
&lt;td&gt;Finish the login in the browser link it prints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Events go missing&lt;/td&gt;
&lt;td&gt;two processes read the same agent's &lt;code&gt;/events&lt;/code&gt; queue&lt;/td&gt;
&lt;td&gt;Exactly one reader per agent key&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What we learned building on a real Switch server
&lt;/h2&gt;

&lt;p&gt;Our first plan was written from Switch's docs and source. The live server corrected it in three places, and building the rest taught us four more lessons. Each one changed the code, and each is worth knowing before you build your own Switch project.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Roles live in the agent tools, not the HTTP API
&lt;/h3&gt;

&lt;p&gt;We planned for the keeper to ask Switch "who holds the soul?" The live server's &lt;code&gt;/openapi.json&lt;/code&gt; has 39 paths, and none of them mention roles. &lt;code&gt;assume_role&lt;/code&gt;, &lt;code&gt;release_role&lt;/code&gt; and &lt;code&gt;list_roles&lt;/code&gt; exist only in the operations layer that a connected coding agent reaches through Switch's agent tools.&lt;/p&gt;

&lt;p&gt;So the keeper &lt;strong&gt;observes&lt;/strong&gt; the holder instead of querying it. The brain acknowledges each claim in the ledger, and &lt;code&gt;SOUL_CLAIMED&lt;/code&gt; / &lt;code&gt;SOUL_RELEASED&lt;/code&gt; lines are written on every transition. If you need roles from a script, plan for the same pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;/events&lt;/code&gt; is a draining queue: read it once
&lt;/h3&gt;

&lt;p&gt;Room history did not return the messages the keeper needed; the agent event queue did. But reading an event removes it. Two readers on one agent key race each other, and the loser simply never sees the event. Our keeper has exactly one background poller, and everything else reads its local buffer.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A favor is not a Switch Task
&lt;/h3&gt;

&lt;p&gt;Switch Tasks look perfect for favors, but a Task needs a performer agent when it is created. A favor is left for &lt;em&gt;whoever Hermit visits next&lt;/em&gt;, and nobody knows who that is yet. Favors became ledger lines instead: &lt;code&gt;FAVOR_LEFT&lt;/code&gt; → &lt;code&gt;FAVOR_ASSIGNED&lt;/code&gt; → &lt;code&gt;FAVOR_COMPLETED&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Two events can share a timestamp
&lt;/h3&gt;

&lt;p&gt;Polling by "everything after time T" lost the second of two notes sent in the same instant. The keeper now tracks message IDs while it folds the recent ledger. A test sends two notes without advancing the fake clock and checks that both arrive, in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Lag was in our pipe, not in Switch
&lt;/h3&gt;

&lt;p&gt;In our 5 November three-laptop run, Hermit's movement felt laggy. One cause was ours: a keeper already knew about a remote claim, but its mascot waited for the next 30-second status poll. The keeper now pushes remote claims, releases, favors and shell pieces straight to its desktop stream. The first ledger load stays quiet, so a restart doesn't replay old arrivals.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. The "I'm busy, go" button looked broken
&lt;/h3&gt;

&lt;p&gt;When a host sent Hermit away, their own keeper was often still the most eligible host and took it straight back. Now a host that hands Hermit on &lt;strong&gt;stands aside&lt;/strong&gt; for five minutes, but only while another friend is awake to take it. If nobody else can host, it takes Hermit back rather than leave it stranded.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Windows display scaling stretches transparent windows
&lt;/h3&gt;

&lt;p&gt;On a laptop at 125% scaling, every &lt;code&gt;setPosition&lt;/code&gt; on our transparent Electron window rounded a little, and the window grew wider while you dragged it. Worse, a click on Hermit started a drag that captured the mouse, so the desktop stopped taking clicks.&lt;/p&gt;

&lt;p&gt;We now move the window with &lt;code&gt;setBounds&lt;/code&gt; at a fixed size and lock its min and max size. A drag only starts after the pointer moves 4 px. A 15-second safety timer, a grip dead-man switch and a panic key (Ctrl+Alt+H) mean the companion can never hold your desktop hostage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering: one soul, never two
&lt;/h2&gt;

&lt;p&gt;The hardest rule in Hermit is also the simplest to say: &lt;strong&gt;at most one laptop holds Hermit, ever.&lt;/strong&gt; Three keepers on three networks, each deciding on its own, must never both believe they are the host.&lt;/p&gt;

&lt;h3&gt;
  
  
  The state machine
&lt;/h3&gt;

&lt;p&gt;Each keeper runs a small state machine, driven by a &lt;code&gt;tick()&lt;/code&gt; call so a simulated day runs in milliseconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stateDiagram-v2
  [*] --&amp;gt; ASLEEP
  ASLEEP --&amp;gt; AWAKE_WAITING : present past debounce
  ASLEEP --&amp;gt; BEDTIME_LOCK : present, but bedtime
  AWAKE_WAITING --&amp;gt; ASLEEP : idle
  AWAKE_WAITING --&amp;gt; CLAIMING : soul free for claim delay + jitter
  CLAIMING --&amp;gt; HOLDING : claim ok
  CLAIMING --&amp;gt; AWAKE_WAITING : rejected, back off
  HOLDING --&amp;gt; DEPARTING : idle after min dwell, bedtime, or "I'm busy"
  DEPARTING --&amp;gt; AWAKE_WAITING : released, still present
  DEPARTING --&amp;gt; ASLEEP : released, idle
  HOLDING --&amp;gt; ASLEEP : lease lost, no goodbye
  BEDTIME_LOCK --&amp;gt; AWAKE_WAITING : bedtime over, present
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details carry most of the fairness. A keeper waits a &lt;strong&gt;claim delay plus random jitter&lt;/strong&gt; before reaching for a free Hermit, so the friend who hosted least recently tends to go first. And &lt;code&gt;BEDTIME_LOCK&lt;/code&gt; never claims, however awake you are.&lt;/p&gt;

&lt;h3&gt;
  
  
  How we test a rule like that
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Property tests (Hypothesis).&lt;/strong&gt; Random presence timelines for three hosts over two simulated hours, asserting at most one holder after every single tick. A second test throws arbitrary claim, release and expiry interleavings at the lease.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Races over real HTTP.&lt;/strong&gt; Ten three-way claim races against the Switch stand-in, with a watchdog sampling throughout. It must record zero double holders, and it does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure drills.&lt;/strong&gt; Idle handoff, lid slam recorded as abrupt, Switch outage reported as offline, recovery with the same holder, a favor crossing laptops, and brains that lie about claiming.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-compressed scenarios.&lt;/strong&gt; A whole day of three friends, a bedtime eviction, everyone asleep, three time zones, each in seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suite&lt;/th&gt;
&lt;th&gt;Result on 7 November&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Keeper tests (&lt;code&gt;pytest -m "not live"&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;268 passed, 2 live tests deselected, 72 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scenarios (&lt;code&gt;python -m sim all&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;9 of 9 PASS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI unit tests (Vitest)&lt;/td&gt;
&lt;td&gt;104 passed: ui-shared 61, map 33, critter 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static checks&lt;/td&gt;
&lt;td&gt;ruff, ruff format and strict mypy in the gate; CI runs all of it plus the map's Playwright e2e&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The scenario numbers are labelled &lt;strong&gt;SIMULATION&lt;/strong&gt; everywhere they appear. Their handoff latency counts 30-second simulation ticks, so it says nothing about Switch's speed, and we never quote it as if it did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing a creature people want on their desktop
&lt;/h2&gt;

&lt;p&gt;A companion that lives on your screen has to earn its place. Our rules were simple: be small, be readable at a glance, never get in the way, and never guilt anyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  One character, many moods
&lt;/h3&gt;

&lt;p&gt;Hermit is a round sprout in a borrowed shell, with a heart patch and a flower charm. Every screen draws the same character from one shared UI package, &lt;code&gt;@hermit/ui&lt;/code&gt;, so the desktop, the menu and the map never disagree. The mood follows the keeper's state, never an animation timer: the holder's screen can never show Hermit walking away while the banner says "with you".&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mood&lt;/th&gt;
&lt;th&gt;When you see it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Arriving&lt;/td&gt;
&lt;td&gt;your keeper just claimed Hermit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visiting&lt;/td&gt;
&lt;td&gt;Hermit is with you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Curious&lt;/td&gt;
&lt;td&gt;a favor or a note just arrived&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Favor done&lt;/td&gt;
&lt;td&gt;you finished a favor and the shell grew&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Away&lt;/td&gt;
&lt;td&gt;Hermit is on a friend's laptop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sleeping&lt;/td&gt;
&lt;td&gt;you are idle, or it is past your bedtime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;The "Preview a movement" panel in the first screenshot of this post plays each mood on demand.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The shell is the scoreboard
&lt;/h3&gt;

&lt;p&gt;Every finished favor adds one pixel-art piece to Hermit's shell. Its &lt;strong&gt;colour&lt;/strong&gt; is the hour Hermit arrived (night, dawn, day, dusk), lighter when it was hot. Its &lt;strong&gt;pattern&lt;/strong&gt; is the brain that was hosting: Claude, Codex or OpenCode. Its &lt;strong&gt;edge&lt;/strong&gt; says how the visit ended: graceful, bedtime, or an abrupt lid slam.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbzddgp8b69j6dgm2hju3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbzddgp8b69j6dgm2hju3.png" alt="The pixel shell with its colour, pattern and edge key" width="800" height="1242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The shell from the sample journey: 8 pieces, 3 brains, 3 friends. Hover any piece to find its stop.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The journey map is history, clearly labelled
&lt;/h3&gt;

&lt;p&gt;The map draws each friend's house at area level, the dotted trail of every hop, and a quest log of every stop. It reads an exported &lt;code&gt;journey.json&lt;/code&gt;. A separate "Right now" card can read the local keeper live, and the page says plainly that everything else is history, not a feed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5g68avi4dul4tf6calm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5g68avi4dul4tf6calm8.png" alt="The journey map: three friends' houses and the dotted trail" width="800" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The journey view of the sample Bengaluru data: three houses, every hop coloured by how Hermit left.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq66zid6b5p7e5auzt95g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq66zid6b5p7e5auzt95g.png" alt="The quest log: one card per stop" width="799" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The quest log: one card per stop, with the brain, the weather, how long Hermit stayed and the favor carried.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs49ux7b3v00bah6ndy1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs49ux7b3v00bah6ndy1b.png" alt="The Right now card: three friends, Hermit with Akshay" width="799" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The "Right now" card during our stand-in run: all three keepers agree Hermit is with Akshay.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It works on a phone and in dark mode too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fina27qxcaer7784ehclz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fina27qxcaer7784ehclz.png" alt="The journey page on a phone" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxyk8pf58j9bts6a57os.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxyk8pf58j9bts6a57os.png" alt="The journey page in dark mode" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Privacy by design
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One folder.&lt;/strong&gt; The brain's working directory is &lt;code&gt;~/HermitWindow&lt;/code&gt;, set in Switch Console. The keeper reports only the &lt;strong&gt;number&lt;/strong&gt; of files there, never names or contents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Area-level location.&lt;/strong&gt; Each friend types an area such as Koramangala into a git-ignored config. No street, no tracking, and coordinates never leave the group's own server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bedtime.&lt;/strong&gt; Past your bedtime, Hermit leaves and stays away until morning. It never rewards staying up late.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consent.&lt;/strong&gt; The den's house rules tell Hermit to stop when anyone says "mute".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No server of ours.&lt;/strong&gt; Keys live in environment variables, and the mascot API listens only on &lt;code&gt;127.0.0.1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where Hermit stands today: real, stand-in and open
&lt;/h2&gt;

&lt;p&gt;Hackathon projects love to blur "it ran once" into "it works". We split our evidence into three columns instead, so you can see exactly what each claim rests on.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;th&gt;What we saw&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live (real Switch)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All three keepers registered as custom agents on a real &lt;code&gt;switch-v0.9.0&lt;/code&gt; server. One keeper posted a ledger line and another received it through &lt;code&gt;/agents/{id}/events&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Afreen's server, live API probe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live (real Switch)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Three real laptops, over Tailscale, in one group view. Akshay's keeper listed Abhishek awake and waiting, Afreen holding Hermit and himself, all folded from the shared ledger.&lt;/td&gt;
&lt;td&gt;Akshay's &lt;code&gt;/v1/group&lt;/code&gt;, 5 November&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live (real Switch)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A controlled claim went &lt;code&gt;CLAIMING&lt;/code&gt; → &lt;code&gt;HOLDING&lt;/code&gt;, Afreen left one real favor through Switch, then released Hermit.&lt;/td&gt;
&lt;td&gt;Afreen's keeper, 7 November&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stand-in&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The full loop in this post: claim, favor, note, idle handoff, favor completed on another keeper, and the shell piece seen by a third keeper.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;python -m sim live --switch standin&lt;/code&gt;, 7 November&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stand-in&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ten three-way claim races with zero double holders, a lid slam recorded as abrupt, a Switch outage reported as offline and then recovered.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;test_switch_standin.py&lt;/code&gt;, over real HTTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Simulation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nine time-compressed scenarios, from bedtime eviction to three time zones.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;python -m sim all&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Still open, and we won't pretend otherwise
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] A complete, &lt;strong&gt;measured&lt;/strong&gt; three-laptop handoff with timings. Our 5 November run partly worked and felt laggy; we fixed the lag we found, but have not re-measured.&lt;/li&gt;
&lt;li&gt;[ ] Switch enforcing the exclusive &lt;code&gt;soul&lt;/code&gt; role between real brains: two brains race &lt;code&gt;assume_role&lt;/code&gt;, and the second is refused.&lt;/li&gt;
&lt;li&gt;[ ] The real lease expiry after a lid slam. Our config uses 8 seconds as a placeholder.&lt;/li&gt;
&lt;li&gt;[ ] Real brains speaking as Hermit in the den, with memory carried across Claude Code, Codex and OpenCode.&lt;/li&gt;
&lt;li&gt;[ ] A pilot with friends outside the team. No pilot numbers exist yet, so none appear here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The shared server lives on one friend's laptop, which is also its weakest point. On the morning we wrote this post, Hermit stopped for everyone because that laptop dropped off the tailnet. The keepers handled it correctly, showing "offline" and recovering on their own, but a real deployment wants an always-on host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself in 10 minutes
&lt;/h2&gt;

&lt;p&gt;You don't need Docker, Switch or a second laptop to see Hermit work. You need Python 3.11+, Node 20+ with pnpm 9, and git.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone and install the keeper.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/afreenorbit/hermit.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;hermit
   python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate   &lt;span class="c"&gt;# Windows: .\.venv\Scripts\Activate.ps1&lt;/span&gt;
   pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"keeper[dev]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the quality gate: ruff, strict mypy, every keeper test and every scenario.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   python scripts/test_gate.py &lt;span class="nt"&gt;--quick&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start three keepers against the Switch stand-in. This is the real keeper code path over HTTP.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   python &lt;span class="nt"&gt;-m&lt;/span&gt; sim live &lt;span class="nt"&gt;--switch&lt;/span&gt; standin
   curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://127.0.0.1:47801/v1/status   &lt;span class="c"&gt;# 47802, 47803 for the other two friends&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Break things on purpose and watch the keepers cope.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:47804/lid-slam/akshay   &lt;span class="c"&gt;# slam the holder's lid&lt;/span&gt;
   curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:47804/switch/down       &lt;span class="c"&gt;# every keeper reports offline&lt;/span&gt;
   curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:47804/switch/up         &lt;span class="c"&gt;# same holder comes back&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Open the journey map with the live card.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm dev:map
   &lt;span class="c"&gt;# then open http://localhost:5173/?live=http://127.0.0.1:47801&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run Hermit for real across laptops, follow the setup walkthrough above and the &lt;a href="https://github.com/afreenorbit/hermit/blob/main/docs/switch-setup.md" rel="noopener noreferrer"&gt;Switch setup runbook&lt;/a&gt; in the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The next milestone is the one that makes Hermit truly Switch-native: each friend's own AI takes the exclusive &lt;code&gt;soul&lt;/code&gt; role, and Switch itself guarantees there is only one Hermit. After that, we want to measure handoffs across three real laptops, run a small pilot with friends outside the team, and move the server to an always-on machine.&lt;/p&gt;

&lt;p&gt;The bigger idea outlasts the hackathon. Switch lets people and their own AI agents share rooms without a central app owning their data. Hermit uses that for something small and human: a reason for friends to do one kind thing for each other this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  The team
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Afreen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Switch integration, the keeper, the lease and the state machine; hosts the server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Abhishek&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gameplay and data: favors, the shell, bedtime, the journal, metrics and the pilot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Akshay&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UI and story: Hermit's design, the desktop critter, the journey map and this post&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/afreenorbit/hermit" rel="noopener noreferrer"&gt;github.com/afreenorbit/hermit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Built on &lt;a href="https://github.com/sandbox-quantum/switch" rel="noopener noreferrer"&gt;Switch&lt;/a&gt; for &lt;a href="https://www.wemakedevs.org/hackathons/switch" rel="noopener noreferrer"&gt;Flip the Switch&lt;/a&gt;, Track 02: Best Personal or Creative Workflow&lt;/li&gt;
&lt;li&gt;Share yours with #HowISwitch&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
