C.W.K.
Stream
Lesson 01 of 04 · published

One Process Owns It All

~11 min · single-process, launchd, ownership, operations

Level 0Open Gate
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"One process serves the app, runs the schedule, owns the writes, and rotates the backups. When there's one owner, there's never a question of who did what."

Everything under one roof

Keep runs as a single launchd agent. That one process does all of it: serves the API, serves the built PWA (the same process hands out the web app and answers its calls), runs the 06:31 daily loop, owns the SQLite writer, and rotates the backups. There is no separate web server, no separate scheduler, no separate backup daemon. One process, one owner of every moving part. For a single-family, local-first app, this isn't a limitation — it's the deliberate simplicity that makes the whole system reasoning-about-able.

Why one process is the right amount of process

The instinct trained by cloud architecture is to split: a web tier, a worker tier, a cron service, a backup job, each scaling independently. That's correct at scale and wildly over-built for one family on one Mac. Every split you add is a new coordination problem: how do the scheduler and the web server agree on state, how do you make sure only one thing writes the database, what happens when the backup daemon and the daily loop run at once. Keep dissolves all of those questions by never creating them. One process can't disagree with itself about who owns the writer, because it is the writer.

Every process boundary you add is a coordination problem you now own. Splitting into services buys independent scaling and costs you distributed-systems complexity — consensus, ordering, partial failure. Below the scale where you need the scaling, you're paying the cost for nothing. Match the number of processes to the actual operational need, and a single owner is often exactly right.

The single writer, made real by the single process

Remember the single-writer database guarantee from the snapshots track? This is where it becomes physically true. The reason there's exactly one SQLite writer is that there's exactly one process, and that process is the writer. You don't have to enforce single-writer with locks and coordination across services, because the architecture makes multiple writers impossible — there's only one process that could write. The clean data-layer invariant and the clean process model are the same fact seen from two angles.

launchd owns keeping it alive. The one thing outside the process is the supervisor: launchd runs the agent, restarts it if it dies, and starts it at boot. That's the right division — the OS-level supervisor guarantees the process exists, and the process guarantees everything inside it. You don't build your own babysitter; you let the platform's supervisor do the one job it's built for.

Code

One process, every responsibility (illustrative)·text
com.cwk.keep-serve  (one launchd agent)
  ├─ serves the API                (HTTP endpoints)
  ├─ serves the built PWA          (the web app itself)
  ├─ runs the 06:31 daily loop     (in-process scheduler)
  ├─ owns the SQLite writer        (the ONLY writer)
  └─ rotates backups               (crash-safe snapshots)

# No second web server. No second scheduler. No backup daemon.
# 'Who owns the writer?' has one answer because there is one process.
# launchd's only job: keep this single process alive and restart it.

External links

Exercise

Take a small app you've built or imagined and count its processes: web server, worker, scheduler, backup job. For each split, ask 'does this actually need to scale independently, or did I split it out of habit?' Then design the single-process version and list the coordination problems that simply vanish. Finally, name the one thing that genuinely belongs OUTSIDE the process (hint: keeping it alive).
Hint
Most small-app process splits are cargo-culted from cloud diagrams. Collapsing them removes real complexity: no inter-process state sync, no 'who writes the DB' question, no race between the cron and the app. The one thing that should stay outside is the supervisor — you want the OS to restart your process, not your process to restart itself.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.