I Stopped Treating the Web Admin as a Separate Product
I used to think the browser UI was the polished layer and the CLI was the serious layer.
That split felt natural for a while. The CLI was where I trusted the work. The web view was where I expected convenience, maybe better visibility, maybe a nicer way to poke around when the terminal got crowded. But while building APX, that mental model kept producing one annoying symptom: drift.
The browser could show something useful, but if it did anything more than mirror the same state and actions as the daemon, it started to become its own little product. Then the CLI and the web panel slowly stopped agreeing on what mattered, or how to name it, or which path owned the truth.
That is the part I finally stopped tolerating.
My current thesis is simple: the APX web admin only works when it stays a thin surface over the same daemon, the same repo-owned project state, and the same local runtime rules. If the browser invents a second version of the system, the convenience is fake. If it reads and writes the same core state, it becomes genuinely useful.
What APX actually is
The APX README says the system in plain words: APX is a daemon plus CLI. The daemon is a local HTTP server that manages projects, agents, sessions, and message logs. The web admin is a browser UI served by that daemon. It is not a separate backend. It is the same runtime seen through another surface.
That distinction matters more than it sounds.
If the browser talks to a different store, or keeps its own state, or re-implements a business rule just to feel faster, then I am no longer using one system. I am using two systems that happen to share a logo.
APX is opinionated about storage for the same reason. The repo owns project definitions and curated memory. Runtime noise lives under ~/.apx/ and stays local. That split already tells me where the web UI should stand. It should render the same project contract, not create a separate one.
Where the drift showed up
I started noticing the problem in small ways.
A task would look right in the browser, but the command-line flow would still expose the older shape.
A project setting would be easy to edit in one place, but the other surface would lag behind or use a slightly different name.
A session history view would be handy, but the action behind it would not map cleanly to the same daemon call the CLI used.
None of those bugs were dramatic by themselves. The real damage was cumulative. Every time I let one surface improvise, I created another place where I had to remember what the system was supposed to mean.
That is a bad trade.
I do not want my own tooling to depend on me carrying parallel mental models. I want one model, many views.
The browser is good at browsing
The browser is still valuable. I am not arguing against it. I am arguing for a narrower job.
A browser is good at:
- scanning lots of state quickly
- comparing several things side by side
- editing structured data without leaving the machine
- showing relationships that are annoying in a terminal
- making the daemon feel inspectable instead of hidden
That is already enough.
In APX, the web admin covers the right kind of surfaces for that job: projects, chat, tasks, routines, MCPs, memories, skills, docs, files, and the rest of the local control plane. The browser should help me see what is going on, not redefine what is going on.
That is why I like the docs phrase that the web admin is the same runtime in the browser. That is the right mental frame. Same runtime, different interface. Not same brand, different truth.
What I changed in practice
Once I accepted that, the implementation discipline got simpler.
The daemon became the place where the real work lives. The web panel became a client of the daemon. The CLI stayed a second client of the same daemon. Both surfaces can be opinionated about presentation. Neither surface should own the domain rules on its own.
That gives me a clean test for every feature:
- If the behavior matters to the product, it belongs in the daemon or core.
- If the behavior is only about how a surface presents that state, it belongs in the surface.
- If a feature cannot be expressed cleanly in both CLI and web, the design is probably too surface-specific.
That test has saved me from building UI-only logic that felt nice in the moment and then turned into maintenance debt later.
The other thing that changed is how I think about authentication and locality. The web panel runs on 127.0.0.1:7430 and uses the daemon over HTTP. It does not need a public server to feel modern. If I want another device on the same LAN to join, APX has an explicit pairing path. That is a better shape than quietly opening the door and hoping nobody notices.
Local-first is not a marketing slogan here. It is what keeps the browser honest.
The real lesson
The web admin taught me something that the CLI alone did not make obvious.
A tool can feel unified from the terminal and still be split in practice if the surfaces each accumulate their own ideas.
That is the trap I keep watching for now. The browser UI is tempting because it is easy to add just one more convenience: a cached view, a special action, a shortcut that skips the core path. Each one looks harmless. Together they turn one system into a fork.
So I am trying to stay strict about the boundary.
APC holds the project contract in the repo.
APX owns the local runtime, daemon, and local state.
The web admin is only a view over that same runtime.
When I keep those layers separate, the whole thing gets easier to understand, easier to debug, and easier to trust. When I blur them, I spend more time explaining my own tool than using it.
That is why I stopped treating the web admin as a separate product.
It is not a second product. It is a second angle on the same machine.
Source notes
The concrete pieces behind this are already in the repo and docs:
- APX README: daemon + CLI, browser UI, and local state split.
- APX docs on the daemon: every surface talks to the same host layer.
- APX docs on the web panel: browser UI over HTTP, no public server by default.
- APX docs on projects and memory: repo-owned project context, local runtime state.
That is the boundary I want to keep. The browser can be friendly. It does not need to become independent.
Top comments (1)
This is a strong product lesson. Admin surfaces are not secondary when they control the system's real behavior.
A weak admin panel creates operational bugs: unclear state, risky actions, missing audit trails, and support teams guessing what happened. Treating it as part of the product forces better permissions, better workflows, and better recovery paths.
Internal users still deserve good UX.