APX Works Best When the Bridge Stays Thin
I kept trying to make APX do more than it should.
That is the honest version.
At first I wanted APX to feel like a single control surface for everything: project rules, runtime choice, agent identity, session history, message logs, and whatever else a tool might need to feel "smart". The problem was not that the features were wrong. The problem was that I kept asking the bridge to become the house.
That is where the work got messy.
The part that finally clicked for me is simple: APX works best when the bridge stays thin. APC should hold the project contract. APX should handle the moving parts. If the runtime starts carrying project meaning that should live in the repo, or if the repo starts carrying machine-specific behavior, the boundary blurs and the system becomes harder to trust.
That sounds abstract until you look at the actual code.
What the bridge really does
In APX, the bridge is not a giant translation layer. It is a small set of decisions that let a runtime do useful work without pretending to own the project.
The README already says the split plainly: APX is a daemon plus CLI, it manages projects, agents, sessions, and logs, and the local state lives under ~/.apx/. That part matters because it tells you what APX is for: live work, not durable project meaning.
The runtime bridge tests pushed me toward the same conclusion. buildApfHint() is intentionally slim. It substitutes the placeholders the runtime needs, and nothing more. The test even guards against leftover template markers. That sounds minor, but it is the right instinct: the hint should be enough for the runtime to know where it is, not a second copy of the entire APC story.
That is the boundary I want everywhere in APX.
Identity is not the same as context
Another thing I had to stop mixing up: identity and project context are related, but they are not the same problem.
buildIdentityBlock() injects the agent name, personality, owner, owner context, and language into the super-agent prompt. The tests make that explicit. If identity is missing, the prompt becomes vague. If language is wrong, the whole experience feels off even when the logic is correct.
So APX needs to be opinionated about identity.
But it still should not become the source of truth for the project itself.
Identity is runtime behavior. It tells the agent how to speak, who owns it, and which language to use. APC is still where the project rules live. That separation is what keeps the tool from drifting into a pile of hidden defaults.
I used to think more data in the prompt would solve this. It does not. It just creates a bigger prompt with more chances to go stale. A thinner bridge with explicit identity is easier to debug than a fat prompt that tries to impersonate the whole repo.
Setup is not initialization
The distinction between apx init and apx setup is one of the cleanest examples of the split.
apx init is project work. It scaffolds APC into a repo and points you at the durable files.
apx setup is machine work. It is the interactive first-run wizard that asks about provider, model, channels, and language. It also starts the daemon and wires in the local runtime choices that do not belong in a repo.
That separation helped me stop asking one command to do two jobs.
If I blur them, I end up with a setup flow that leaks machine preference into the project. If I keep them separate, the repo stays portable and the machine stays configurable. The user sees a cleaner model: project first, runtime second.
That split also makes failure easier to reason about. If a project is wrong, I fix APC. If a machine is wrong, I fix APX. I do not have to guess whether the bug is in a repo artifact or in the local daemon state.
What changed for me
The biggest practical change was not a new feature. It was a new discipline.
I stopped trying to make every layer remember everything.
Now I want each layer to remember only what it owns:
- APC remembers the project contract
- APX remembers runtime state, sessions, and machine-local behavior
- identity is injected when the runtime needs to speak
- logs and session metadata stay local, where they can be inspected without polluting the repo
That shift matters because the system became easier to debug.
When a session goes wrong, I no longer wonder whether the agent lost the project rules or whether the runtime picked a weird local state. I can look at the boundary. I can inspect the APX session frontmatter, the runtime bridge, or the APC files in the repo and see which side is responsible.
That is the real benefit of a thin bridge: less mystery, less duplication, fewer places for truth to split.
Why I still like the split
I still think APX is the right place for the messy parts.
It bridges Claude Code, Codex, OpenCode, and Aider. It handles local sessions. It owns the daemon. It keeps the runtime state where it belongs. That is a lot of responsibility, but it is the right kind of responsibility because it is machine-shaped.
APC stays simpler because of that. It does not have to know how every runtime behaves. It just has to describe the project clearly enough that any compatible tool can enter the repo and understand what it is looking at.
That is the part I care about most now: APC should be portable, APX should be local, and the bridge between them should stay narrow enough to trust.
If I get greedy and push more meaning into APX, I usually regret it later. If I keep the bridge thin, the whole stack becomes easier to maintain, easier to explain, and easier to reuse the next time I need another tool to join the project.
That is the rule I am keeping.
And it is the one that finally made APX feel like a runtime instead of a second copy of the project.
Source notes
The concrete parts behind this lesson are already in the repo:
- APX README: daemon + CLI, local state under
~/.apx/, runtimes, engines, and plugins. -
runtime-bridge.test.js: the runtime hint stays slim and placeholder-driven. -
identity-injection.test.js: identity andconfig.user.languagemust be injected into the super-agent prompt. -
setup.js: provider, model, channels, and language belong to machine setup.
That is enough structure for me. Anything thicker starts to look like a second project.
Top comments (1)
Thin bridges age better. Once the bridge starts owning too much interpretation, every external runtime has to debug both the original tool and the bridge's private model of that tool.