seedproject-web/.memory/webdesigner.md
Carlos Arias 6fec3498f2 framework(core): clone tooling + docs (Phase 4)
- FRAMEWORK.md: the host + pluggable-agent contract, the roster, and the
  clone+assign flow
- configure.mjs: ensure a default agents roster on a fresh clone
- .memory/{qa-agent,webdesigner}.md: framework notes pointing at the module layout
Verified: a scratch clone with a different site.config.json yields a different
identity + roster from identical core code.
2026-07-24 08:05:38 -04:00

8.6 KiB

The Web Designer — a core Astroagent console update

Status: Implemented · Date: 2026-07-24 Related: qa-agent.md · ../agents/console/PLAN.md · ../agents/console/SETUP.md · ../brand/BRAND.md · ../.claude/skills/brand/SKILL.md · ../.claude/skills/changelog/SKILL.md


What it is

The Web Designer is a new capability of the astroagent console — the base's in-site authoring engine (agents/console/server.mjs). It is not a separate OS agent; it is a new mode of the existing confined runner (carlos-arias-agent), reached through the already-gated /devconsole/ nginx prefix.

You hand it a brief for any page — a prompt/instructions, a draft, uploaded images, and links to short videos — and it does real design work (edit a section, restyle a component, lay out a new page) and publishes. Briefs are queued; the agent drains the queue one task at a time.

This is a core engine change, not site content — a fresh SeedProject clone that runs the migration + configure.mjs inherits the whole thing. (See the site-coupling caveat below for the one thing that is not yet fully clone-clean.)

It coexists with two sibling surfaces built earlier in the same arc:

  • the in-page console (the ▲ handle) — freeform, contextual, preview→publish by hand;
  • the project builder (/admin/projects/new/devconsole/build-project) — the structured path that writes a cja_projects row.

The Web Designer is the freeform, queued path for everything else.

Framework note (2026-07-24): the console runner was refactored into a generic host + pluggable agent modules (FRAMEWORK.md). The Web Designer now lives in agents/console/agents/web-designer.mjs (exports manifest + register), is enabled via the astroagent.config.json roster, and exposes host.drainTasks (QA autofix kicks it). Logic unchanged from below.

Added after first write (2026-07-24)

Two capabilities were added to the Web Designer after this doc's first version:

  • Self-logs every change to the changelog. buildDesignPrompt instructs the agent, after finishing, to add one entry to api/cli/seed-changelog.php via the changelog skill, attributed to Website Designer Agent, with the current timestamp (injected by the runner via nowStamp() — a headless agent can't read the clock). Because the confined agent has no shell, the runner reseeds cja_changelog (php api/cli/seed-changelog.php) when that file changed, before the build, so the entry goes live. Changelog entries carry a by/actor field (migration 012): agents name themselves; human/CLI edits default to Carlos Arias.
  • Fed by the QA agent. QA findings become Web Designer tasks — auto-queued for safe categories, or dispatched from the /admin/qa instructions box. A QA-origin task is just a normal cja_tasks row, so it fixes, publishes, and self-logs like any other. See qa-agent.md for the closed loop.

Timezone note: nowStamp() uses the runner's system timezone, set to America/New_York on 2026-07-24 (was UTC, which mis-stamped early agent entries).

Architecture

/admin/designer  ──create task──▶  cja_tasks (queued)     [PHP: admintasks controller]
      │  poll status                       ▲
      └──kick──▶ /devconsole/tasks/run ──  drainTasks() loop   [Node runner]
                                            │  claim next   (php api/cli/tasks-next.php)
                                            │  run design agent: claude -p (skills + brief, Write/Edit)
                                            │  build → git commit LIVE   (auto-publish)
                                            │  mark finished (php api/cli/tasks-finish.php)
                                            └─ next task …

The Node runner is deliberately dependency-free (no DB driver), so it reads/updates the queue by shelling out to small PHP CLI helpers — keeping MariaDB behind the single PHP data layer. The design work itself is a claude -p spawn, the same harness as the in-page console.

Locked decisions

Question Decision
Scope of the agent Full builder — may edit any page and create new pages (updating the nav in Header.astro + Footer.astro).
Publish model Auto-publish & continue. Each task builds, commits live, and the queue advances hands-off. Safety net = git history (one revert per task) + a build-must-pass gate.
Skills CLI-native. Skills live under .claude/skills/ so claude auto-discovers them; the persona also reads them explicitly for headless reliability.
Queue store DB table cja_tasks (durable, survives restart), not the in-memory jobs Map.
Runner ↔ DB PHP CLI bridge (tasks-next.php / tasks-finish.php); the runner stays dependency-free.
Progress UX Polling admintasks/list, not SSE — sidesteps the drifted server/DevConsole event contract.

Skills (the CLI-native design brain)

.claude/skills/ is new and is what makes the agent design rather than merely edit:

  • brand/SKILL.md — the sumi-e brand system distilled from brand/BRAND.md (the seal rule, palette tokens, type scale, radii, do/don'ts). This file is the site-specific piece — a clone swaps its contents.
  • ui-ux/ — a symlink to the existing generic app/.astroagent/skills/ui-ux (reusable).

Before my change the console passed no skill wiring at all; the skills array in astroagent.config.json was inert. The runner still passes no --skill flag — discovery is by location (.claude/skills/) plus an explicit "read these SKILL.md files" instruction in the design persona.

Safety model

  • Clean-tree guard. A task refuses to run if the git scope (app brand api/db api/cli) is dirty — otherwise the auto-publish git add would sweep unrelated WIP into the task's commit. Uploaded assets under app/public/media/ are exempt (they are the task's images and get committed with it). This guard exists because exactly that hazard bit during the build: an uncommitted file was swept into a task commit and a revert then deleted it.
  • Build-must-pass gate before any commit; a failing task reverts its own edits (git checkout + clean) and the queue continues.
  • Scoped commitsgit add never touches secrets/config, only app brand api/db api/cli (+ media). The agent runs confined, Write/Edit within the repo only.
  • Single-flight — the queue shares the runner's global busy lock, so a draining queue and the in-page console can never run at once (the console returns 429 while draining).

Files

File Role Core / site
agents/console/server.mjs buildDesignPrompt, runDesignTask, drainTasks, POST /devconsole/tasks/run core
api/db/migrations/011_create_cja_tasks.sql queue table core
api/public/controllers/admintasks.php create / list / get / cancel core
api/cli/tasks-next.php atomic claim (queued → running) core
api/cli/tasks-finish.php mark published / failed + result core
app/src/pages/admin/designer.astro submit brief + poll the queue core
app/src/layouts/AdminLayout.astro "Web Designer" nav link core
.claude/skills/ui-ux (symlink) generic design skill core
.claude/skills/brand/SKILL.md this site's brand site-specific

Site-coupling caveat (not yet clone-clean)

The prompt-builders in server.mjs — both the new buildDesignPrompt and the pre-existing buildPrompthardcode "the Carlos Arias website" and "sumi-e" directly in the engine. This site identity was already baked into the console before this change; the Web Designer matches that pattern rather than adding new debt. For a truly clone-clean base, those strings should be sourced from site.config.json / astroagent.config.json + the brand skill, leaving the runner site-agnostic. Deferred — flagged, not done.

How to run it

  1. Sign in to the admin (secret link), open /admin/designer.
  2. Submit a brief: pick a page (or "New page"), write instructions, optionally a draft, upload images, paste short-video links → Add to queue & run.
  3. The queue drains automatically; each row shows queued → running… → published (with a live link + commit) or failed (with the reason).
  4. Undo any task with git revert <commit> on main, then rebuild.