A Laravel core, a local-first Svelte client, one small Go binary on every machine and a relay for terminals. Here is every piece, and how a run moves through them.
One central core serves many organisations. Browsers sync with it, daemons take orders from it, and terminal bytes travel through the relay so the core never carries them.
Carries terminal bytes between browsers and daemons. It knows tickets, sessions and connections, never issues. Sessions survive a relay restart.
The daemon dials out: HTTPS to the core, a websocket to the relay. Terminal bytes never pass through the core.
No exotic dependencies. The Go side has exactly one: a websocket library.
| Piece | Built with | Why it is there |
|---|---|---|
| Core | ||
| Framework | Laravel 13, PHP 8.4 | The one central core |
| Database | MySQL | Org boundary as composite foreign keys |
| Queues | Redis + Horizon | Jobs, imports, the scheduler's work |
| Realtime | Reverb | Live events to clients and daemons |
| Files | S3 | Attachments and images |
| Auth | Fortify, Socialite | Magic link, Google, GitHub, passkeys, device flow |
| Agents and API | laravel/mcp, Scramble | MCP server and REST API docs |
| Quality | Pest 4, Larastan, Pint | Suite runs on SQLite and MySQL |
| Client | ||
| UI | Svelte 5 (runes), TypeScript | The whole app |
| Build | Vite 8, Tailwind 4 | Fast builds, tokens for light and dark |
| Offline | vite-plugin-pwa, Workbox, idb | Installable, data in IndexedDB |
| Live | Echo + Reverb | Events the moment they happen |
| Terminal | xterm.js 6 | Agent sessions in the browser |
| Editor | TipTap 3 | Issues, documents, mentions |
| Tables | TanStack table + virtual | Long lists that stay fast |
| Look | Lucide, Geist | Icons and type |
| Machines | ||
| Daemon | Go 1.27, coder/websocket | One binary per machine, runs agents in tmux |
| Relay | Go 1.27, coder/websocket | Terminal bytes between browser and daemon |
| Updates | sha256 + ed25519 | Signed self-update, atomic swap |
| Service | launchd, systemd | Keeps the daemon running across updates |
What happens between "queue this issue" and a green PR on the release branch.
You queue an issue, or a release train queues a whole project. The issue already carries its spec, order and readiness, so the agent never guesses.
The core places the run on the machine with the shortest wait, ordered by skip-queue, rank, train position, priority and time queued. Private machines only take work from their owner and members.
slotsaccountsquotaThe daemon on that machine makes a git worktree for the run and starts the agent CLI in tmux, with a brief and the profile's model and effort. The agent uses the login that already lives on the machine.
tmuxworktreeclaude · codex · grokInside the worktree the agent reports with short verbs. A question lands on your phone; your answer goes straight back into its session.
statusaskblockedattachgatedonedone reports the PR. The GitHub App links it to the issue by branch, title and magic words, and moves the issue by your team's rules.
One gate job per PR head runs on your fleet. A conflict starts a conflict run with a brief of the colliding changes.
Green PRs merge into the release branch, never into main. When the train is done it opens one ship PR from release to your default branch, and a person merges it.
Every view reads from IndexedDB on your device. The server keeps the order of things, the client keeps them close.
One way to change anything. Every change, from a person, an agent, the API or an import, goes through one mutation bus. Each change writes one event with a sequence number. There is no second path that could skip it.
The server is the clock. The sequence comes from the core, so every client agrees on what happened in which order. Clients never decide time on their own.
Optimistic, then confirmed. Your edit shows at once from a local outbox, gets its sequence from the core, and arrives live on every other screen over Reverb.
The first load: everything you can see, into IndexedDB.
Every event since the last sequence you have.
Parts that load only when you open them.
Your changes, sent from the outbox.
Composite foreign keys keep every row inside its organisation. A row cannot point at another organisation's data.
Agent logins stay on your machines. The core never stores them, so there is nothing there to leak.
The daemon checks a sha256 and an ed25519 signature before it swaps itself, atomically.