Establishes the deploy baseline on main so the admin agent's publish/rollback has a clean starting point. Everything built to date: sumi-e brand system, homepage, projects (DB-driven case studies), resume, about, services + website-design detail, contact form + DB, changelog, favicon + share card. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
6.7 KiB
6.7 KiB
Admin Agent — Plan
Goal: manage the site through an AI agent (headless Claude) — create pages, edit content, upload images — from two surfaces: a full /admin dashboard and an in-page console ("open a page, tell it what to change").
Decisions locked (2026-07-23):
- Full-builder agent — can create pages, edit any file, restructure. Highest ceiling, highest risk; sandboxing is mandatory, not optional.
- Both surfaces — /admin dashboard + in-page console.
- Long-lived token —
claude setup-tokenon the server; agent reuses it.
What already exists (don't rebuild)
app/src/components/DevConsole.astro— the in-page console UI (prompt box, element picker, preview link, Publish). Already on every live page, dormant.astroagent.config.json— engine config: model, tools (Read Write Edit Glob Grep WebSearch), confinedagentUser(carlos-arias-agent), skills (brand,ui-ux,seo), console route/port.api/auth —account.phpsessions +ADMIN_TOKEN.- Structured content already DB-driven and agent-friendly:
cja_projects,cja_changelog,cja_contact, plus the seed scripts that write them. - Server has the
claudeCLI and Node 22. Project is a git repo onmain.
What's missing (the build)
- The runner service the console talks to (
/devconsole/run|publish|...) — frontend exists, backend does not. - Image upload anywhere in the flow.
- Model selector and the structured draft + prompt + images panel.
- The /admin dashboard.
- Media pipeline (
cja_media+ optimisation). - Hardening — the code-writing agent is the highest-risk surface on the site.
Architecture
Browser (you, authed)
├── /admin ................ dashboard SPA: pages, media, agent chat
└── in-page console ........ DevConsole.astro on any page
│ (same-origin fetch, session-authed)
▼
nginx ── /devconsole/* , /admin/* ──► localhost-only runner (Node, :3011)
│ auth gate on every request │
│ ├── headless Claude Code
│ │ (agentUser, confined to repo,
│ │ tools: Read/Write/Edit/Glob/Grep/WebSearch)
│ ├── preview build → public-preview/<jobId>/
│ ├── publish → build public/ + chown + git commit
│ └── media: optimise → app/public/media/ + cja_media
▼
Static site (public/) — unchanged for visitors
Content model — hybrid:
- Freeform pages (
about,services/*) → the agent edits.astrofiles directly. - New pages → the agent writes new
.astrofiles. - Structured content (projects, changelog, services data) → DB, edited via structured tools or the seed JSON/scripts.
- Images →
app/public/media/(survives rebuilds) +cja_mediarows.
Why preview-first matters: the site is static. Every agent run builds to an
isolated public-preview/<jobId>/ you can open and review; nothing goes live
until you press Publish, which rebuilds public/ and commits to git.
Phases
Phase 0 — Foundation & safety (do first, no features yet)
- Commit the current working tree as a clean baseline (75 files) so every future publish is a diff you can roll back.
- Create/confirm the confined
carlos-arias-agentOS user: can write only the repo, no sudo, no interactive shell. Install/pointclaudefor that user. claude setup-tokenon the server → store inagents/.env(git-ignored).- Admin auth: session login (reuse
api/account.phpor a dedicated admin login). - nginx:
/devconsole/*and/admin/*→ localhost runner, auth-gated, never exposed directly. Runner binds127.0.0.1only. - Audit log table (
cja_admin_log): who ran what, when, published or discarded.
Phase 1 — In-page console (finish the astroagent)
- Build the runner service:
run(spawn headless Claude with prompt + page context, stream output),preview,publish,discard,ping,auth,logout. Conversation state so follow-ups work ("now make it bigger"). - Wire
DevConsole.astroto it. Element picker already works. - Publish pipeline: build → verify build passes → chown → git commit.
- Milestone: open /about, "tighten the opening paragraph," preview, publish.
Phase 2 — Media
cja_mediatable +POST /devconsole/upload.- Optimise on upload (resize/compress, like the manual ffmpeg step), write to
app/public/media/, return URL + agent-generated alt text. - Image upload in the console; agent can place uploaded images in a page.
- Milestone: on a project page, "add these three screenshots to the gallery."
Phase 3 — Admin dashboard (/admin)
- Login → dashboard.
- Pages: list (filesystem scan of
app/src/pages+ DB content types), create-page flow ("make a page for my accounting services"), edit (hands off to the console or a structured form). - Media library: browse/upload/reuse.
- Agent panel — your exact spec: model selector · draft-content box · prompt box · image-upload area. Draft + prompt + images post to the same runner.
- Activity log from
cja_admin_log.
Phase 4 — Guardrails & polish
- Feed the agent the brand guide +
brand/ui-ux/seoskills so edits stay on-brand automatically. - "Build passes" gate is required before Publish is offered.
- One-click rollback (git revert the last publish).
- Per-session run/token limits; rate limiting.
Risks & mitigations
- Security is the whole game. A code-writing agent on a public server is the highest-value target here — a breach means full server control. Mitigations: admin auth on every request, runner bound to localhost, confined OS user, audit log, no direct exposure of the agent, rate limits.
- The agent can break the build. → preview-first, build-passes gate, git commit per publish, one-click rollback.
- Unbounded token spend. → per-session limits; the long-lived token is one account we can watch.
- On-brand drift. → brand guide + skills injected into every agent run; preview-before-publish is the human gate.
Not in scope (yet)
- Multi-user / roles (single admin for now).
- Scheduled autonomous edits (the
agents/content pipeline is separate and currently tuned for the old blog — re-tune later if wanted).
To start Phase 0, I need
- Your go-ahead to commit the current tree as the baseline.
- A decision on admin login: reuse the existing account system, or a simple single-user admin password to start.