Inspiration
In the age of harnesses like claude code and codex, it has become harder to collaborate as a small team to build projects. We have talked with many teams in this hackathon and the most common bottleneck we found for teams building amazing projects was not having the infrastructure to collaborate easily with agentic development tools, first with fellow team-members and then with different agents running in the same computer. Thus we came up with the idea to build an Agent Development Environments (ADE) called "Teamree" to solve this problem by letting agents collaborate with other agents on the computer and also with agents run my other team-members over an encrypted network.
What it does
"Teamree" makes it easy for agents to communicate with other agents using the teamree-cli, and then automates the process of collaborating with your teammates agents over a locally hosted encrypted network to relay chats with agents for the entire team to interact with each other.
The way it works is that every task you start gets its own git worktree, which is a separate checkout of the same repository on its own branch, so you can have five agents working on five different things at the same time and none of them are ever touching each other's files. Each of those worktrees has its own real terminals inside the app, and you can split them, so one agent can be writing code in one pane while a build or a test suite runs beside it in another. The window keeps track of what every pane is doing and tells you which one is actually working, which one has gone quiet because it is waiting for you to answer something, which one finished and which one failed, so you are not clicking through five terminals trying to work out where things are stuck.
The teamree-cli is what makes this an agent development environment instead of just a nicer terminal app. Everything the window can do, the CLI can do, because they are the same program talking to the same runtime — so an agent sitting in one pane can create a worktree, open a terminal in it, run a command, read the output back, and check whether its branch would merge, all by typing commands, and the window updates live while it happens. Every command takes a --json flag and gives back exactly one JSON document, because the thing we actually designed the CLI for is another program reading it, not a human squinting at it. That is how an agent ends up driving the whole environment and coordinating with the other agents running next to it.
Then the teamwork part is where your teammates come in. You add each other's public keys to the repository itself, so your team is just the people you already share a repo with and there is no account to make and nothing to sign up for. Once that is done, your teammate's worktrees and their panes show up in your sidebar under their name, and you can watch what their agent is doing live and type into it — which usually means answering the one question that has had their agent blocked for the last twenty minutes while they were away from their desk. All of that traffic is end-to-end encrypted with a Noise handshake, and because two laptops behind two different routers cannot reach each other directly, both of them dial out to a small relay that just splices the two connections together. The relay is never trusted with anything — it only ever sees encrypted bytes — and each team runs their own with one command, because the app carries it inside itself.
How we built it
We built Teamree as a desktop app with Electron, React and TypeScript, and the whole thing is organised around the idea that every task gets its own git worktree. That choice is what makes parallel agents actually safe rather than just possible, because five agents attempting the same task never see each other's files and throwing an attempt away is deleting a directory instead of unpicking commits.
The terminals are real terminals, not emulated ones — we run node-pty underneath and render with xterm.js on WebGL, so an agent running inside a pane behaves exactly the way it would in your own terminal. That also gave us the activity states almost for free, because we read them straight off the pty output and the process exit codes instead of trying to understand what any particular agent is saying. It is deliberately a narrow reading: we know the output stopped, which is not the same as knowing the agent asked you a question, and we say so rather than pretending we know more than we do.
For the CLI, the thing we are proudest of architecturally is that there is one frozen contract in the codebase that types the runtime, the window and the CLI together, and they all talk newline-delimited JSON over a unix socket. That is why the CLI and the GUI cannot drift into two different products sharing a name, and it is why an agent driving Teamree gets exactly the same capabilities a human clicking around gets, rather than some reduced API bolted on afterwards.
For the teamwork side we implemented the Noise IK handshake over X25519, so both ends authenticate against the public keys that are committed into the repository. The relay is a Cloudflare Worker with Durable Objects, and it only ever handles ciphertext and opaque rendezvous tokens, so a team can deploy their own and nobody has to trust ours.
Challenges we ran into
The one that nearly killed the entire teamwork feature was that we had more than 1800 tests passing and then found out that Electron's crypto does not have chacha20-poly1305 in it at all. Node has it, our tests ran under Node, everything was green, and in the actual shipped app the cipher just throws "Unknown cipher" — which meant the whole encrypted layer was dead in the only environment that actually matters. We moved to a userspace implementation and then wrote a test that asserts it is running under Electron and that the native cipher is genuinely absent, so that test can never quietly pass for the wrong reason again. That one taught us more than anything else in this project.
We also found that unix socket paths have a 104 byte limit, and the limit is in bytes and not characters, which means a profile directory with Chinese or Cyrillic characters in it is comfortably under 104 characters and well over 104 bytes, and the runtime would have simply refused to start for those users with a completely unhelpful error.
We wrote a command for agents called terminal wait --for quiet and then discovered it was lying to them — it would say a command had finished while it was still inside a sleep 2, because the output had gone quiet. Silence is not completion. So we built terminal run, which waits on the actual process exiting, and we wrote down honestly what quiet can and cannot tell you instead of pretending the first version was fine.
macOS fought us right at the end. /var on macOS is a symlink, and our relay deploy command was comparing an unresolved path against a resolved one, so it silently did nothing and exited zero for every temporary path. Our app icon was being assembled by hand and wrote a chunk type that macOS is allowed to read as raw pixels instead of PNG, so the icon came out as red and green noise in the dock even though every individual piece of the file decoded perfectly on its own. And GitHub Actions charges ten times the minutes for macOS runners, so we ended up pulling every check into a release script that refuses to publish anything if any one of them fails.
Accomplishments that we're proud of
We proved the teamwork actually works over the real internet and not just on localhost. Two peers, a relay really deployed to Cloudflare, twelve runs, and we measured all of it — 395ms to dial the relay against 46ms locally, and 53ms for a keystroke to be acknowledged across the network against 1ms on the same machine. Every timeout in the system had between 60x and 190x of margin. It is one thing to say that encrypted peer-to-peer collaboration between two laptops works, and a different thing to have the numbers for it.
The single shared contract between the runtime, the window and the CLI is the decision we are happiest with, because it let several parts of this get built in parallel and still integrate, and it is the reason an agent can drive the whole environment rather than a subset of it.
And honestly we are proud of the things we refused to ship. The app never overwrites something that is already sitting where it wants to put a file. It never force pushes and there is no flag to make it. It reads a link back and resolves it before telling you it worked, because a command that exited zero is not the same fact as a thing that actually works. We also went through our own landing page and cut four claims that turned out not to be true of the build we were shipping, including calling it open source before we had actually added a licence file.
What we learned
The biggest thing is that tests passing only proves that your tests pass. The chacha20-poly1305 problem is the whole lesson of this project for us — 1800 green tests under Node told us nothing at all about the environment we actually ship into, and the only way to know is to run the real thing. So everything we checked at the end, we checked against the built app, mounted from the actual .dmg, launched and driven.
The second thing is to read back what you did instead of trusting that you did it. A command that exited zero, a file that got written, a deploy that returned a 200 — none of those are evidence on their own. We shipped two demo clips to production that were truncated, one of them to literally zero bytes, and both of them served a perfectly clean 200 with the right content type. The only thing that caught it was comparing the actual bytes.
And the third is that silence is not success. Half the bugs we found late were things that failed without saying anything: a command that exited zero and did nothing, a CSS rule that was correct but whose class was never applied to anything, an icon whose pieces were all individually valid. Anything that can fail quietly eventually will.
What's next for Teamree
First is Windows and Linux builds properly supported, and getting an Apple Developer ID so the macOS build is signed and notarised and people stop meeting a Gatekeeper dialog the first time they open it. The packaging is already written for all of that, it just needs a certificate.
Then the part we wanted from the very beginning, which is a graph based unified memory shared across a whole team's agents, so that what one agent figured out about a codebase is available to the next one instead of every session starting from nothing. Right now Teamree lets agents work in parallel and lets teammates watch and type into each other's panes, and the next step is letting them share context and not just screens.
We also want to get teamwork setup down to a single button. At the moment it needs a repo both people can push to, a relay deployed, and each person's key committed, and we have cut that down a lot already but it is still more steps than it should be — and the entire point of this project is that collaborating should not be the hard part.
Built With
- chacha20-poly1305
- chrome-devtools-protocol
- claude
- cloudflare
- codex
- durable-objects
- electron
- figma
- git-worktree
- node-pty
- node.js
- noise-protocol
- react
- typescript
- unix-sockets
- vite
- webgl
- websockets
- x25519
- xterm.js
- zod
- zustand
Log in or sign up for Devpost to join the conversation.