nullhex

Greebo: One Server That Runs Everything

10 Mar 2026·11 min read·infrastructure

There is a machine sitting in a rack somewhere that runs everything. Not metaphorically. Literally everything. The memory engine, the email PA, the Telegram bot, three MCP servers, a database, a print spooler, cron jobs, Claude Code sessions, and the development environments for three SaaS products. One machine. No cluster. No Kubernetes. No load balancer. Just a server named after a fictional cat that refuses to die.

The conventional wisdom says this is wrong. You are supposed to decompose into microservices, deploy to containers, orchestrate with Kubernetes, scale horizontally behind a load balancer, and monitor everything with a distributed tracing system. The conventional wisdom is written by people selling you the tools to implement the conventional wisdom.

Greebo is our answer to the question: what happens if you ignore all of that and just run everything on one box? The answer is that everything works, you can actually understand your own system, and you spend zero time debugging distributed failures that only exist because you distributed things in the first place.

// the philosophy

This is not "monoliths are better than microservices." That debate is tiresome and context-dependent. The philosophy is simpler: do not introduce complexity until complexity solves a real problem. A single server is the simplest possible infrastructure. One failure mode (the server dies), one deployment target (the server), one place to look when something breaks (the server). You see the pattern.

When everything runs on one machine, there are no network partitions between services. No eventual consistency to worry about. No container orchestration failures, no pod eviction policies, no ingress controller misconfigurations. Services communicate through local sockets or direct function calls. Latency between them is measured in microseconds, not milliseconds.

This is not scalable in the way venture-backed startups mean when they say "scalable." It does not handle ten million concurrent users. It does not auto-scale. It does not have five nines through geographic redundancy. We do not need any of that. What we need is a system that works reliably for the actual load it serves, that we can understand completely, and that we can fix at 3am without consulting a runbook written by someone who left the company two years ago.

Greebo serves that purpose perfectly. This is not architecture designed for a hypothetical future. It is architecture designed for the present, and it is a deliberate choice. A well-specced single server gives you full control, instant debugging, zero network latency between services, and none of the distributed systems complexity that most teams spend half their engineering time fighting. Why introduce problems you do not have?

There is a liberating clarity in knowing exactly where everything lives. When something breaks, you SSH into one machine and look at the logs. That simplicity is not a limitation. It is the point.

// what runs on it

The inventory is deliberately broad. Each service is managed by systemd, which gives us process supervision, automatic restarts, logging, and dependency ordering without additional tooling.

Claude Code sessions. The primary development environment. Multiple concurrent sessions against different projects, each with MCP server access and the memory engine. This is where the actual work happens - writing code, managing deployments, handling email.

Telegram bot. A systemd user service acting as a mobile interface to Claude Code. Send a message from your phone or iPad and it gets processed by a full Claude session on the server. The bot handles text, images, and file attachments, routing them into active sessions or spawning new ones as needed.

PA MCP server. The personal assistant with 24 tools covering multiple email accounts, Google and Apple calendars, a network printer, morning and evening briefings, contact management, spam cleanup, and action tracking. Reads email, drafts replies, schedules meetings, prints documents, generates daily intelligence briefings.

Memory engine. An FTS5 full-text search index with salience scoring and hook-driven indexing. Stores and retrieves memories across Claude Code sessions, giving every conversation access to project context, user preferences, feedback history, and reference material. An hourly cron job runs a thinking loop that processes recent memories and generates a fresh briefing.

eBay MCP server. Seven tools for listing management, photo uploads, shipping estimation, and policy configuration. Built, tested, and awaiting API key approval.

X MCP server. Eight tools including Grok-powered search, timeline management, draft composition, and a safety gate requiring explicit confirmation before posting. The draft-then-post pattern prevents accidental tweets from automated sessions.

SurrealDB. Version 3.0.4 on port 8822 with RocksDB storage. Handles persistent data for the PA, action tracking, and contact management. Chosen for multi-model flexibility and the fact that it runs as a single binary with no external dependencies.

Cron jobs. Hourly thinking loop for the memory engine. Two-hourly spam cleanup across all email accounts. Morning briefing at 9:30 AM. Midnight briefing for overnight processing. Each job is a simple script calling into the relevant MCP server.

CUPS print spooler. Connected to an Epson ET-2850 on the local network. Unexpectedly useful for boarding passes, receipts, and reference material.

$ systemctl --user status claude-telegram
● claude-telegram.service - Claude Telegram Bot
     Loaded: loaded (~/.config/systemd/user/claude-telegram.service)
     Active: active (running) since Mon 2026-03-10 08:14:22 GMT; 2 weeks ago
   Main PID: 14822 (node)
      Tasks: 11 (limit: 38292)
     Memory: 142.8M
        CPU: 4h 23min 18.442s

$ systemctl status surrealdb
● surrealdb.service - SurrealDB Server
     Loaded: loaded (/etc/systemd/system/surrealdb.service)
     Active: active (running) since Mon 2026-03-10 08:12:01 GMT; 2 weeks ago
   Main PID: 14201 (surreal)
      Tasks: 18 (limit: 38292)
     Memory: 284.1M
        CPU: 12h 44min 02.118s

$ uptime
 14:32:18 up 17 days, 6:20, 3 users, load average: 0.42, 0.38, 0.41

Load average of 0.42. The machine is not even trying. Plenty of resources to spare, and the only time it approaches anything like effort is when a full Playwright test suite runs alongside active development sessions.

// the stack

Technology choices follow the same philosophy as the architecture: simplest tool that solves the problem. Do not add anything until there is a concrete reason.

systemd is the orchestrator. Every long-running process is a systemd service with automatic restart, journald logging, and dependency declarations. No Docker needed for process isolation because we do not need process isolation. No Kubernetes because systemd already handles supervision, startup ordering, and health checks. The tools that ship with the operating system are sufficient.

Node.js runs the application layer. MCP servers, Telegram bot, memory engine hooks, cron scripts. Not because Node is the best runtime for every task, but because it is the one we know deeply, it handles concurrent I/O well, and one language across the stack eliminates the cognitive overhead of context-switching between languages.

SurrealDB handles persistence. Multi-model database supporting documents, graphs, and relations in a single engine. Contacts as documents, relationships as graph edges, queryable across both models in one statement. Runs as a single binary with RocksDB storage - no connection pooling, no replica management, no cluster coordination. Start the binary, point it at a data directory, done.

CUPS manages printing. Standard Unix print system, works with the Epson ET-2850 over the network without special drivers. The PA calls lp with the right options and the document appears on paper. Sometimes the simplest interface is the best one.

The entire stack can be understood by one person in an afternoon. No abstraction layers hiding complexity. No framework conventions requiring documentation to decode. You can read every line of code that makes it work.

// why this works

Simplicity. Single server means a single mental model. Debug something? You know where to look. Deploy something? You know where it goes. Understand how two services interact? Read both codebases without switching between repositories, build systems, or deployment pipelines. Minimal cognitive load because the system is minimal.

Observability. Logs in one place. Metrics for one machine. Tail every service simultaneously and see the entire system's behaviour in a single terminal window. No distributed tracing because there is nothing distributed. When the PA receives an email, processes it, and sends a notification, the entire flow is visible in journald on one machine. No correlation IDs, no trace propagation, no sampling decisions.

Speed of iteration. Deploying a change means pushing code and restarting a service. No container build step, no image push, no rolling deployment strategy, no canary analysis. The feedback loop between "I changed something" and "the change is live" is measured in seconds. That speed compounds. A hundred deployments a week at seconds each is fundamentally different from a hundred at minutes each.

Total control. Everything is right there. No third-party managed service sitting between you and your data. No vendor abstraction hiding what is actually happening. When something behaves unexpectedly, the answer is on the machine in front of you. Not in a support ticket. Not behind a cloud console.

The tradeoff is obvious: if the server dies, everything dies. We accept this because the probability is low, recovery is fast (boot the machine, systemd starts everything), and the alternative is a distributed system that fails in distributed ways far harder to diagnose. A single point of failure you understand completely is preferable to a distributed system with failure modes that surprise you.

// the cat metaphor

"If cats looked like frogs we'd realise what nasty, cruel little bastards they are. Style. That's what people remember." - Terry Pratchett, Lords and Ladies

Greebo is named after the cat from Terry Pratchett's Discworld novels. In the books, Greebo is a battle-scarred, one-eyed tomcat who has terrorised the neighbourhood for years. He has fought bears. He has eaten vampires. By any objective measure, a deeply unpleasant animal. But also unkillable, fiercely loyal on his own terms, and impossible to get rid of once you start feeding him.

The name fits. Greebo is not elegant. No beautiful architecture diagram with clean service boundaries and well-defined APIs. A single machine doing too many things at once, held together by systemd unit files and bash scripts. But it works. Has been working for months. Handles everything thrown at it without complaint, and every time we consider replacing it with something "proper," we realise the proper solution would be harder to understand, slower to debug, and more fragile in ways we could not predict.

There is a lesson in the Pratchett cat. Style is what people remember, but effectiveness is what matters. The industry obsesses over architectural style: microservices, event-driven, serverless, cloud-native. All valid for the right context. But for a small team running real products, the right architecture is the one that works, that you understand, and that you can fix at 3am without a war room.

Greebo is that architecture. One server. One cat. Everything runs. We sleep well.

// when to move on

This architecture has a ceiling, and we are honest about where it is. If CoachSync scales to the point where a single database cannot handle the query load, we split the data layer. If the Telegram bot starts processing thousands of messages per minute, it gets its own resources. If the PA grows to handle dozens of email accounts, the I/O profile changes.

Good problems, those. The kind that come from success, and they come with the revenue to fund solutions. The mistake would be solving them now, before they exist, at the cost of simplicity that pays dividends every single day.

For now, load average is 0.42, uptime is measured in weeks, and every service is running exactly where we can find it. Greebo is fed, Greebo is happy, and Greebo is not going anywhere.