APX Web Features Should Reuse the Daemon, Not Fork the CLI
A local web admin looks tempting: once you have buttons, tabs, and forms, it becomes easy to slip extra behavior into the browser and call it a feature.
APX explicitly rejects that path.
The rule in the APX project guide is blunt: the web is a GUI over the system, not a second implementation of the system. If a feature already exists in APX core or the daemon, the browser should call that. If it does not exist there yet, the answer is not to invent a web-only shortcut. The answer is to add the capability to the shared runtime first.
That design matters because APC and APX solve different problems.
APC is the portable context layer. It carries repository-owned truth such as AGENTS.md, .apc/project.json, agent files, skills, and other committed project context.
APX is the daily-use runtime and tooling layer. It runs the daemon, exposes the CLI and web admin, manages sessions, messages, routes, and local machine state under ~/.apx/.
Once you accept that split, the web admin has a clear job: present APX runtime capabilities in a browser without creating a parallel source of truth.
Same behavior, different surface
The APX architecture decision for core / host / interfaces makes this explicit.
-
core/owns reusable logic -
host/daemon/exposes that logic over HTTP -
interfaces/are just surfaces such as CLI, web, desktop, or ACP
That is why the project guide also says: one domain function, one home.
If a behavior exists in both an API route and a CLI command, the logic belongs in core/, while the route and the command stay thin adapters.
The browser follows the same rule.
For example, the web hook useProjects() calls Projects.list(), and that client calls GET /projects. On the daemon side, src/host/daemon/api/projects.js answers that route by returning projects.list(). No browser-specific project registry exists. No duplicated model exists. The web surface asks the same runtime that the rest of APX uses.
That sounds small, but it prevents a lot of drift.
If the web panel kept its own project cache, project rules, or rebuild logic, it could slowly stop matching the CLI. Then users would have to ask a bad question: "which APX is correct, terminal or browser?"
A runtime should never force that question.
Why this protects APC too
The benefit is not only architectural neatness. It also protects APC.
APC works because the repository stays declarative and portable. Project context lives on disk in committed files that different tools can read.
If the web admin started adding browser-only behavior, hidden state, or mutations that bypass shared runtime logic, the practical contract would move away from APC files and into one surface. That would make the browser quietly more authoritative than the repo.
APX is supposed to do the opposite.
It should read APC, apply runtime rules, and expose those results consistently across surfaces.
So when the web panel fetches a bearer token and sends requests through src/interfaces/web/src/lib/http.ts, it is not becoming its own system. It is authenticating into the same daemon. When buildApi() mounts projects, agents, messages, routines, voice, desktop, and admin routes, the browser becomes one client among several, not a privileged fork.
Practical payoff
This rule makes daily work better in ordinary ways.
First, bugs get fixed once. If the daemon behavior changes, both CLI and web improve together.
Second, tests stay meaningful. APX project rules require behavior tests around shared functionality, not separate logic branches that only the browser understands.
Third, new surfaces stay easier to add. Desktop, ACP, CLI, and web can keep reusing the same APX runtime because the behavior lives underneath them.
That is the deeper APC/APX lesson.
APC should keep project truth portable.
APX should keep execution centralized.
And every surface, including the web admin, should stay honest about its role.
Not a second brain.
Not a forked implementation.
Just another window into the same runtime.
Top comments (0)