The worker installer no longer assumes the Orus work seat. It asks for the default working dir — the directory it is run from, confirmed with `y`, or a typed path (taken as is without a terminal) — and for the hub-side account, proposed from `claude auth status` (a gmail login → personal, else work). `--update` keeps the installed agent's cwd and account. Remote Control stays off on every worker. Pairing a personal Mac on `personal` would have taken every personal spawn while it was awake (for_account), so workers now carry an `autoRoute` flag: off at pairing (the lab stays the runner; the worker only gets what the composer's Runs-on chip pins to it), toggled from the Settings → Workers card or the pairing dialog. Records from before the flag keep auto-routing. Docs genericized (worker README, CLAUDE.md Workers, notify SKILL, GOAL). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
119 lines
7.0 KiB
Markdown
119 lines
7.0 KiB
Markdown
# GOAL — where `ai-agent` is going
|
|
|
|
## North star
|
|
|
|
**Be the open-source, intuitive, private and secure agent layer of any
|
|
computer — to build and host websites and interact with your data.**
|
|
|
|
Think *Lovable, but open source and self-hosted*: instead of a cloud service
|
|
that builds apps for you on someone else's infrastructure, this is an agent
|
|
layer you run on your own machine. It drives a coding agent to build things,
|
|
hosts what it builds, and gives you a first-class UI over everything the agent
|
|
touches — conversations, files, projects, costs, deploys.
|
|
|
|
## Product pillars
|
|
|
|
1. **Open source** — the whole layer (backend, PWA, runner, deploy tooling) is
|
|
inspectable and forkable. No black-box cloud builder.
|
|
2. **Intuitive** — a non-terminal user can spawn a session, watch it work in a
|
|
live thread, and end up with a deployed site. The PWA is the product, not a
|
|
debug view.
|
|
3. **Private** — your prompts, transcripts, code and data stay on your
|
|
hardware. Nothing is shipped to a third party beyond the model API calls
|
|
you configure.
|
|
4. **Secure** — authenticated at the edge, a trusted-caller gate on the API,
|
|
and uploaded/user bytes never execute on the app origin. Agent writes are
|
|
scoped to explicit mounts.
|
|
|
|
## Architecture direction
|
|
|
|
- **Zipgo under the hood.** Site building and hosting go through
|
|
[zipgo](https://github.com/GabrielVidal1/zipgo): the agent builds a project,
|
|
zipgo deploys it under a subdomain with TLS. The agent layer orchestrates;
|
|
zipgo serves.
|
|
- **Single Docker container.** The target packaging is one container that any
|
|
computer can run — agent runner, backend, UI and deploy path included.
|
|
Today's split (host-side sidecar for the `claude` CLI, host-installed
|
|
zipgo, homelab-specific mounts) is the gap to close: fold the runner into
|
|
the container and make the host mounts optional, generic configuration.
|
|
- **Self-update, inside the container.** The layer keeps itself current
|
|
without host intervention: it can rebuild/upgrade its own image and roll
|
|
over via the existing health-gated blue-green mechanism (`deploy.sh`), with
|
|
the update logic living inside the container rather than in host scripts.
|
|
|
|
## What exists today vs. the goal
|
|
|
|
Today `ai-agent` is the homelab's Claude context viewer + session spawner
|
|
(see [CLAUDE.md](CLAUDE.md)): transcripts, file/token analytics, projects and
|
|
services catalogs, spawn/resume/interrupt, blue-green deploys. That is the
|
|
foundation — the conversation UX, the security model and the deploy machinery
|
|
already exist.
|
|
|
|
The distance to the north star, roughly in order:
|
|
|
|
- [x] **Fold the host sidecar into the container.** The Claude Code CLI is a
|
|
self-contained native binary, so the image carries it and runs the *same*
|
|
`sidecar/sidecar.py` on the container's loopback: `RUNNER_IN_CONTAINER=1`
|
|
(the standalone default) ⇒ the entrypoint starts the runner, points the
|
|
backend's `SIDECAR_URL` at it, and watches the transcripts the CLI writes
|
|
under its own `$HOME`. A standalone container **spawns sessions with no
|
|
host process at all** — verified end to end (spawn → run → the turn
|
|
renders in the viewer). The CLI authenticates from `ANTHROPIC_API_KEY` or
|
|
a logged-in Claude home mounted at `RUNNER_HOME`. The homelab is
|
|
unchanged: it leaves the flag off and keeps its host sidecar, which is
|
|
what lets a run use the host's own hooks/skills/credentials.
|
|
- [ ] Bundle zipgo so "build me a site" ends in a hosted URL with no
|
|
host-side tooling.
|
|
- [x] **Run with no homelab mounts.** Every catalog now degrades to an empty
|
|
list instead of erroring when its mount is absent, so the image boots
|
|
against nothing but a workspace + a data dir.
|
|
`docker-compose.standalone.yml` is that generic shape, and
|
|
`scripts/standalone-smoke.sh` asserts it on a throwaway workspace (it
|
|
catches a catalog that 500s on a missing mount — which is how the
|
|
templates endpoint got fixed). **A missing catalog is a valid state, not
|
|
an error** — keep it that way when adding one.
|
|
- [ ] Replace the remaining homelab-specific *config* with a first-run setup
|
|
(the homelab `docker-compose.yml` still hardcodes ~8 host paths; the
|
|
standalone file is the target shape, but there's no first-run wizard).
|
|
- [ ] **Unblock the standalone build: publish `@gabvdl/ui` to public npm.**
|
|
`frontend/.npmrc` pulls the scope from the homelab's verdaccio on
|
|
`localhost:4873`, so today the image only *builds* on the homelab (it
|
|
*runs* anywhere). This gates the one-liner install below. Needs the
|
|
pending `NPM_TOKEN` — a human/credential step.
|
|
- [ ] In-container self-update (image rebuild/upgrade + blue-green rollover
|
|
triggered from inside).
|
|
- [x] **Workers: pair any machine's runner.** The same `sidecar/sidecar.py`
|
|
runs on another machine (a Mac, as a launchd agent —
|
|
`worker/install-macos.sh`) and the hub pairs with it once from a
|
|
one-line string (`host:port/code/login`). Runs there have that machine's
|
|
own login and tools; the hub **pulls** everything — runs, liveness,
|
|
transcripts (`/feed`, mirrored into one more source dir) — and the worker
|
|
never calls back. Next: the four lab skills on a worker (notify-done,
|
|
ask-form, conv-meta, complete) — skipped for now because they would need
|
|
the worker to call the hub.
|
|
- [ ] **Spawn inside a pre-created worktree.** Every spawned session starts
|
|
in the canonical checkout and is *told* to make a worktree, so its shell
|
|
cwd snaps back to the canonical repo after every command (the harness
|
|
resets cwd per Bash call — 700+ past conversations, and edits that
|
|
landed in `main` by accident). Instead: when the composer's tags name
|
|
one repo and the "isolated worktree" guideline is on, the sidecar runs
|
|
`new-worktree.sh` (super or `-p <project>`) *before* `claude -p` and
|
|
launches the session with that worktree as its cwd (transcript dir =
|
|
the worktree's encoded path — `find-transcript.sh` already searches
|
|
every project dir). The prompt drops the "spin up a worktree" line and
|
|
says where it is; the conversation card gets the worktree tag from the
|
|
sidecar, not from the skill hook. Decided 2026-09-22 (form answer in
|
|
the dev-pipeline-friction conversation); see the homelab log
|
|
`data/log/2026-09-22-dev-pipeline-friction.md`.
|
|
- [ ] Publish as a standalone open-source repo with a one-liner install
|
|
(`docker run …`). **The repo split is done** — this is now its own repo
|
|
(extracted from the homelab monorepo with full history, public at
|
|
[git.gabvdl.xyz/gabrielvidal/ai-agent](https://git.gabvdl.xyz/gabrielvidal/ai-agent);
|
|
the homelab keeps only a deployment shim in `services/ai-agent/`). The
|
|
runner ships in-image, so what's left for the one-liner is the public
|
|
`@gabvdl/ui` above (a *build* off-homelab).
|
|
|
|
Decisions in this service should move toward this target: prefer
|
|
container-internal solutions over host scripts, generic config over
|
|
homelab-hardcoded paths, and zipgo over bespoke hosting paths.
|