Lcos
Lcos
The command-line interface and local daemon for Life Coach OS. Same daemon-and-CLI blueprint as Mxr and Spotuify, with one honest difference: lcos is a local-first mirror of a cloud backend, not the sole owner of its truth.
Project lives at: ~/code/planetaryescape/life-coach-os/apps/cli/ (a Rust cargo workspace inside the bun/Turborepo monorepo)
Docs: apps/cli/docs/ — philosophy.md, decisions.md, gotchas.md, runbook.md
In one paragraph
lcos is a single Rust binary. lcos daemon runs the long-lived process; every other subcommand auto-spawns it and talks to it over a Unix socket using length-delimited JSON. The daemon owns a local SQLite mirror of the user's health signals and coaching, a Tantivy index rebuildable from it, and a sync engine that reconciles with Convex. The CLI front-end, the MCP server, and any future client are equal peers over one IPC contract. What's different from mxr and spotuify: those daemons own the only copy of the truth. lcos doesn't. Convex is the cloud source of truth and the only place a coaching verdict is produced; the local store is a fast, disposable mirror that lets you query your health data offline and lets an agent speak to it through a shell.
The rules it shares with Mxr and Spotuify
- The daemon is the system; the CLI is one client. The root package is the daemon;
lcos daemonis one match arm. No client gets privileged access. See Client-Agnostic Cores, The Local Daemon Pattern. - Protocol-first, enforced by the build.
lcos-protocoldepends only onlcos-core; clients can't reachstore/sync/convex. The crate graph is the architecture. See The Bezos API Mandate. - Pipeable JSON is a product feature. Table on a terminal, JSON when piped, with a
schemaVersion. The same surface serves a human and an agent. See Agent-Native Interfaces. - Same-code-path dry-run. Writes build a plan once; preview renders it with zero network I/O,
--yesreplays the same body. See Same-Code-Path Preview, Mutations Documented Dry-Run First. - Runtime identity is a data boundary.
lcosvslcos-devresolve first, and the socket, DB, index, keychain, and target Convex deployment all derive from it. See Runtime Identity Is a Data Boundary. - Gate the agent, not the human. One dispatch seam gates
Mcp/Agentorigins behind a profile; the human CLI bypasses it. MCP is a peer, not a bypass. - Readiness is not liveness; hot reads stay hot. The launcher waits on a real ping, and reads serve the cache without triggering a sync. See Daemon Readiness Is Not Process Liveness, Hot Reads Should Not Repair Cold State.
What's genuinely new here (and became its own notes)
Mirroring a managed-auth cloud backend into a Rust daemon produced learnings the email/music daemons never hit:
- Bridge Auth With a Second Provider, Not a Backdoor — Clerk's SDK doesn't exist in Rust, so the web app mints short-lived self-signed JWTs validated by a second Convex provider.
- Mirror on a Server-Stamped Change Cursor, Not Creation Time —
daily_featuresis patched in place, so aderivedAtstamp drives delta sync. - Type the Hot Columns, Pass the Rest Through — the ~110-field feature blob is mirrored by typing the hot columns and flattening the rest.
- Cache the Facts, Not the Verdict — Tier-1 answers facts from the mirror; Tier-2 (
ask --deep) routes judgments to the Convex coach. - Deploy-Time Config Validation Doesn't Skip Dead Branches — the gated provider had to be fed an empty-string env to deploy.
- The Type System Is the Recovery Oracle for a Dead Agent — from recovering a build agent that died mid-write.
Architecture summary
Human / Script Agent / MCP
│ │
└─────────┬─────────┘
│ length-delimited JSON over a Unix socket
▼
lcos daemon
┌─────────┼──────────────┐
▼ ▼ ▼
SQLite Tantivy sync engine ──HTTPS (self-signed JWT)──► Convex
(local (rebuildable (cloud truth +
mirror, from SQLite) coaching authority)
NULL≠0)
The local SQLite mirror answers facts at speed and offline. Convex stays the authority for writes and verdicts. The sync engine drains changed-since by derivedAt on the warm lane; reads never trigger it.
Why it exists
So I can speak to my own health data from a terminal and from an agent, without the round-trip and without the app. The Life Coach OS phone app is the daily surface; lcos is the scriptable one. lcos ask "how's my HRV trending vs last month" answers instantly from the mirror; lcos ask --deep reaches the real coach. An agent can drive the same commands through MCP while I sleep, and it's gated to reads by default.
It also exists because the daemon-and-CLI blueprint keeps earning its keep. Email (Mxr), music (Spotuify), now health. The shape travels.
What it is NOT
- Not a second source of truth. The mirror is disposable; a
CACHE_VERSIONbump drops and re-syncs it. Convex owns the truth. - Not a coach. It reports facts locally and proxies the real verdict; it never invents a judgment from a possibly-stale cache.
- Not the phone app's replacement. It's the scriptable, offline, agent-facing surface alongside it.
- Not multi-user yet (single user today, written multi-user-safe).
Status (2026-06-26)
Built across five workflow-driven phases, 199 tests green, committed to main. The backend changes are deployed; the CLI auth provider ships gated off (empty LCOS_CLI_JWT_ISSUER) until the signing key and issuer are set and apps/web is deployed. Five read commands (journal, checkins, briefing, insights, correlations) are deliberately deferred behind a typed "not implemented" until their backend read-routes exist. Go-live steps live in apps/cli/docs/runbook.md.
Connections
- Life Coach OS — the app lcos mirrors
- Mxr, Spotuify — the same blueprint, other domains
- Building Great CLIs — the philosophy hub all three sit under
- How I Write Software Docs — the discipline
apps/cli/docs/follows