- 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.
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 acja_projectsrow.
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(exportsmanifest+register), is enabled via theastroagent.config.jsonroster, and exposeshost.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.
buildDesignPromptinstructs the agent, after finishing, to add one entry toapi/cli/seed-changelog.phpvia thechangelogskill, attributed toWebsite Designer Agent, with the current timestamp (injected by the runner vianowStamp()— a headless agent can't read the clock). Because the confined agent has no shell, the runner reseedscja_changelog(php api/cli/seed-changelog.php) when that file changed, before the build, so the entry goes live. Changelog entries carry aby/actorfield (migration 012): agents name themselves; human/CLI edits default toCarlos Arias. - Fed by the QA agent. QA findings become Web Designer tasks — auto-queued for safe
categories, or dispatched from the
/admin/qainstructions box. A QA-origin task is just a normalcja_tasksrow, 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 frombrand/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 genericapp/.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-publishgit addwould sweep unrelated WIP into the task's commit. Uploaded assets underapp/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 commits —
git addnever touches secrets/config, onlyapp 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
busylock, 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
buildPrompt — hardcode "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
- Sign in to the admin (secret link), open /admin/designer.
- Submit a brief: pick a page (or "New page"), write instructions, optionally a draft, upload images, paste short-video links → Add to queue & run.
- The queue drains automatically; each row shows
queued → running… → published(with a live link + commit) orfailed(with the reason). - Undo any task with
git revert <commit>onmain, then rebuild.