Giving the system a vocabulary

A system that has been evolving for weeks starts to repeat itself. The same refactor pattern shows up in three different apps. The same question comes up in three different sessions. The same rule gets re-explained to a future self. Today was mostly about noticing those repetitions and turning them into vocabulary — shared primitives, shared skills, shared concepts — so the next session wouldn't have to invent them again.

The biggest of these moves was the wheel as a design lens. An earlier pass had added an explicit 8-dimension selector to the habits UI and a "wellbeing signals" strip to the journal page. It worked, but it felt wrong — you don't want the user to think in terms of the rubric; you want the rubric to shape what the system thinks. So we tore the explicit UI out and rewrote the plan as an invisible lens. Rule 16 landed in CLAUDE.md: the 8 dimensions are a silent rubric applied in reasoning, never a feature added to UIs. An SDK module (emptyos/sdk/dimensions.py) canonicalised the 8 names and their aliases, with extract(text) and infer(app_id, text) helpers. A new integrity dimension (P14 Wellbeing Balance) observes behavioural signals — journal entries, captures, habit logs over a 30-day window — and scores imbalance without ever asking the user to tag anything. And a steering layer feeds thin-dimension hints into briefing and assistant system prompts so the LLM can translate "you've been light on rest" into a concrete suggestion without ever naming the wheel. The principle is that the lens belongs in the system's eye, not the user's.

Alongside the philosophical move, a concrete shell. scripts/eos-agent.py grew a REPL mode and a web mode over the course of the day. The REPL is an interactive shell with thirteen slash commands (/mode, /provider, /context, /save, /sessions, …), multi-line input, persisted session JSON under ~/.eos-agent/sessions/, and approval gates for destructive tools (y/n/a/s) bypassable with --yolo for heavier tasks. The web mode is a FastAPI + WebSocket chat UI on port 8765 with a shared-token auth and a mobile-friendly layout, so the same conversation mode that runs in a terminal runs on a phone over Tailscale. A slash-command picker in the web client does keyboard-navigated filtering. Vault auto-detection reads emptyos.toml [notes.path] so the agent knows where to search without being told. The practical upshot: conversation mode is no longer just "open your editor and type into Claude Code"; it has a dedicated shell and a remote surface.

The next move was a skills suite. Six new slash-invoked skills landed under .claude/skills/: eos-simplify (pre-commit convention review), eos-new-app (ten-step scaffolder wiring capabilities + shared UI + tests + release tier + vault map), eos-new-plugin (nine-step service/enhancer scaffolder with headless launch + graceful-fallback registration), eos-vault-migration (seven-phase legacy→VaultIndex migration with a reconcile-readiness gate), eos-sdk-extract (seven-phase shared-code extraction with a two-callers floor and a zero-orphan grep), and eos-release (nine-phase tier-scoped distribution cut orchestrating the existing safety checks). Each skill cites the specific CLAUDE.md rule it encodes — so when the rule changes, you know which skill needs updating. These aren't automations; they're named workflows. The recurring pattern-heavy activities that were being reinvented session-to-session now have entry points.

Shared UI primitives got pulled out in parallel. EOS_UI.settingsPanel({id, title, fields}) and EOS_UI.hashRoute({onShow, onHide}) landed in eos-components.js, along with .eos-settings-panel + .btn-settings CSS. Adding a compliant settings slide-out now takes ~10 lines in a new app. Deep-linkable detail views are three lines. Two CLAUDE.md rules were updated to point at these helpers — one promoted from "use this CSS" to "use EOS_UI.settingsPanel", the other a new "Deep-linking Detail Views" rule mandating hashRoute for any app with a showDetail(id) flow. Along with it, the publish app finally got real draft visibility — filter pills, dashed borders, quick-publish checkmark, draft-aware writer loading — so working-in-progress posts stop being invisible after save.

One infrastructural quiet win: hierarchical tag matching in VaultIndex. The index now treats a query for tag="people" as matching notes tagged people/friend or people/colleague, matching the nested-tag semantics common to markdown vault formats. This unblocked two apps that had been silently returning empty (39 people-tagged notes, 12 place-tagged notes were invisible to their respective apps because those apps were querying the bare tag). VaultLibrary got a small dedup fix in the same pass — if an app declared extra_tags=["people"] alongside its primary tag, entries matching both were being counted twice. Fixed by path-keyed dedup in list() and _find_file().

Two smaller but visible things. The favicon got a contrast pass — the dark purple ring at 16px was unreadable on dark browser chrome — and landed as a transparent-bg ensō with a brighter #7c5cff stroke. And the service worker cache name bumped to v2 after a stale eos-components.js caused one app to go blank after the shared-helpers refactor (EOS_UI.hashRoute is not a function). Worth remembering: bump CACHE_NAME whenever the asset list changes.

Left for later: the wheel has four layers now (philosophy, observation, review, steering) but no "clustering tie-break" for situations where two signals compete in the home-screen ranking — deferred deliberately until the philosophy layer alone proves insufficient. The eos-agent web UI still lacks streaming responses and approval-in-web (destructive tool approvals need to bounce back to the REPL). And we noticed four pre-existing safety violations in various scratch files; they're flagged but unfixed — worth a sweep before the next release cut.

The shape of the day: three things that used to be implicit are now named (wheel as a lens, new-app ritual, draft-vs-published), three things that used to be scattered are now shared (settings panel, hash routing, conversation shell). Vocabulary compounds. Next week's sessions will lean on all of it without thinking.

Related Posts

← Back to posts