Files
ai-agent/GOAL.md
Gabriel Vidal 2b2ca23ad3 feat(workers): Settings → Workers, composer Runs-on chip, badges, takeover confirm
- lib/workers.tsx: useWorkers (workers SSE), WorkerSelect chip (auto from
  the account, amber when it fell back to the lab), WorkerBadge, StatusDot
- Settings → Workers page + pairing form (one string; account picker only
  when the login matches no account), install instructions
- ResumeBox: static worker badge; terminal_live 409 → confirm → takeover
- home banner for an offline/refused worker; typed worker run errors
- mock: workers seed (online/offline/unauthorized) + /api/workers handlers
- docs: CLAUDE.md Workers section, GOAL item, README box, worker/README.md
- standalone smoke asserts the runner's /feed + /pair routes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-28 14:06:39 +02:00

7.0 KiB

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: 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): 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:

  • 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.
  • 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).
  • Workers: pair any machine's runner. The same sidecar/sidecar.py runs on another machine (the Orus MacBook, 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; 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.