seedproject-web/agents/console/SETUP.md
Carlos Arias a2da708418 Phase 2/3: projects media admin (galleries + Instagram)
- /admin/projects list + /admin/projects/edit gallery editor (AdminLayout chrome,
  session-guarded). Upload/replace images per slot, captions, add/remove,
  Instagram reel URL. Save -> cja_projects -> rebuild -> live.
- adminprojects API (list/get/save); media path validation (local paths only).
- runner /rebuild endpoint: build public/ + commit after structured edits.
- Ownership: app/ + public/ now owned by carlos-arias-agent:caweb so the agent
  can rebuild its own output; www serves via the caweb group. Documented in
  SETUP.md — never build as root.

Verified end to end: upload image -> save to gallery -> rebuild -> image live on
the project page and served.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
2026-07-23 22:55:32 +00:00

3.1 KiB

Console — operational setup (server state, not in git)

Records the OS-level setup the admin console depends on. Reproduce this on any new server; none of it lives in the repo.

Agent runtime

  • OS user carlos-arias-agent — system user, /usr/sbin/nologin, no sudo. The headless agent runs as this user. Never as root.
  • HOME /var/lib/carlos-arias-agent (0700). Contains .claude.json with hasTrustDialogAccepted: true for the repo path (headless can't click the trust dialog).
  • Claude binary relocated to /usr/local/bin/claude (self-contained 257M ELF). /root is 0750, so the agent could not reach root's install.
  • Token in agents/.envCLAUDE_CODE_OAUTH_TOKEN (git-ignored, 0600). A claude setup-token value (sk-ant-oat01-…). Rotate it — it passed through a chat transcript during setup.

Permissions model (no chown-to-www needed)

  • Shared group caweb; members: carlos-arias-agent + www.
  • app/, brand/, api/db, api/cli, agents/ → group caweb, g+rwX, setgid on dirs (new files inherit the group).
  • public/ and public-preview/ → group caweb, g+rwX, setgid, world-read. nginx (www) only needs read to serve, so the agent can own build output and nginx still serves it — no privileged chown step.

Build model

  • Isolated preview: PREVIEW_OUT=../public-preview/<jobId> PREVIEW_BASE=/_preview/<jobId> then cd app && npm run build (supported natively by app/astro.config.mjs).
  • Publish: normal build to public/, then git commit (rollback point).

Verified working (2026-07-23)

Confined agent, as carlos-arias-agent with the token: reads the repo, writes source, runs a 24-page isolated preview build (~7.5s), output servable by nginx. Full edit→preview→serve loop proven end to end.

Still to build (Phase 1 remainder)

  • Runner service agents/console/server.mjs (Node, binds 127.0.0.1:3011): run / preview / publish / discard / ping / auth / logout.
  • nginx: /devconsole/* + /admin/*auth_request against a PHP admin-session check → proxy to 127.0.0.1:3011. Runner never exposed directly.
  • Wire DevConsole.astro to the runner.
  • systemd unit to keep the runner alive.

Build ownership (IMPORTANT)

  • app/ and public/ are owned by carlos-arias-agent:caweb. The agent runs all builds and must own its output to overwrite it.
  • Never run npm run build as root — it creates root-owned files the agent then can't overwrite (EPERM in vite prepare-out-dir). If it happens, fix with: chown -R carlos-arias-agent:caweb app public.
  • Rebuild via the runner (POST /devconsole/rebuild) or sudo -u carlos-arias-agent env HOME=/var/lib/carlos-arias-agent … npm run build.
  • www serves public/ via the shared caweb group — no chown-to-www needed.

Phase 2/3 delivered

  • Media upload: POST /api/media/upload (GD/ffmpeg optimise → app/public/media).
  • Projects admin: /admin/projects (list) + /admin/projects/edit?slug= (gallery upload/replace + Instagram URL). Saves to cja_projects, then rebuilds.
  • POST /devconsole/rebuild regenerates the live site after structured edits.