Skip to content
Start

Editing a theme

The person says: “Make the hero blue on the venue site, but make sure it works on phones.”

To change a theme’s code, start empress.theme_session_start through Empress:site_call, then Empress:theme_stage with that session — never a local checkout. Theme code changes in an edit session: a private branch of the theme’s code, edited file by file through Empress:site_call. The platform builds and checks the session, stages it next to live, and renders the stage. Nothing reaches visitors until the promote, and the session becomes the theme only after the promoted pages pass their check.

Ask which layer the request is in: Empress:site_call with tool: "empress.change_classify" and the person’s sentence as args.intent. A data answer is not theme work at all — follow its next (a content, menu or composition edit in a change set, previewed in seconds). A code answer names the files, and the loop below is the way. An engine answer is a clear no with the nearest thing offered; say so, offer the nearest, and stop.

Read the site’s theme brief, skill://theme-brief/<site> (its address is in Empress:site_status’s theme section): its routes, collections, design rules and gotchas are current for this session.

  1. Empress:whoami — the site’s slug.
  2. Empress:site_status — what is live, whether something is already staged, and the theme brief’s address.
  3. Empress:site_call empress.theme_session_start — with a short name for the change. Starting again with the same name returns the same session.
  4. Empress:site_call empress.theme_file_read — an empty path lists the root; then read the file to change. To find where something is used, empress.theme_file_search answers every path:line in one call (glob narrows it to *.astro or src/**/*.css); to see what the session has changed so far, empress.theme_diff answers the unified diff per file, and with a path, that file’s commits on the session.
  5. Empress:site_call empress.theme_file_patch — files, each with a path and either edits (each quoting text that appears exactly once, anchor, and its replace), create for a new file, or delete. One call is one commit by the person, so put a whole change (layout, components, tests) in one call; a wrong anchor in any file saves nothing. For a single file, path with the same field works too.
  6. Empress:site_call empress.theme_check — kind: "build", which also typechecks: a type error fails the build with its file and line (add "test" when the theme has tests). A run longer than about a minute answers “running”: follow it with Empress:work_status and its buildId as taskId (its phase and its last lines), then call empress.theme_check again with the same arguments for the verdict. A build that failed is read with empress.build_log and its buildId.
  7. Empress:site_preview — target: "session" and session set to the branch, the default three widths, and probes: { layoutShift: true } for a layout change. A passed build is deployed as the session’s own Preview on the site (the check’s answer says preview), so the session is drawn on the site’s own data before anything is staged. If it answers that the Preview is still being deployed, call it again in a few seconds. A pooled site has no Preview: skip to step 8.
  8. Empress:theme_stage — with session set to the session.
  9. Empress:site_preview — target: "stage", the default three widths, and probes: { layoutShift: true } for a layout change; fullPage: true with the path of a long page, or selector for just the section being changed; probes: { tokens: true, layout: true } to list, once per cause with its count and first three elements (detail: true for every one), what is off the theme’s scale and what overflows, clips, stretches or reads faint; compare: "live" (or "reference" during a migration, { "asset": "<media id>" } against a design frame) to have what changed boxed and named.
  10. Empress:theme_promote — only when every width rendered and the person agreed; confirm: true.
  11. Empress:site_status — in a minute: whether the pages passed and the session became the theme, or were put back and the session stayed a branch to fix.

A branch pushed from the CLI stages the same way: skip to step 8 with its name as session (it has no session Preview until a build of it has been checked with empress.theme_check). A discarded or merged session takes its Preview with it. A release staged by ref (a branch tip or a commit ahead of the theme) becomes the theme’s main branch too, once its pages pass, when it builds on main. When it does not, Empress:theme_promote refuses before anything changes, in one sentence, and next names a fresh empress.theme_session_start: a session starts from what is live, so make the change again on top of it. Empress:site_status says “The live commit is not main” in its theme section whenever the two differ.

One change is one call. Moving the hero into its own component, with its test, and retiring the old partial is a single Empress:site_call with tool: "empress.theme_file_patch" and args: { "session": "hero", "message": "Move the hero into its own component", "files": [ { "path": "src/layouts/Base.astro", "edits": [ { "anchor": "<Header />", "replace": "<Header />\n<Hero />" } ] }, { "path": "src/components/Hero.astro", "create": "<h1 class=\"hero\">…</h1>\n" }, { "path": "tests/hero.test.ts", "create": "…" }, { "path": "src/partials/hero.html", "delete": true } ] }. A wrong anchor in the layout saves none of the four. A call saves up to 1 MB in all; a bigger change is several calls.

  • Clone when a patch is the wrong tool. If you have a shell and the change is a refactor across many files, a dependency or lockfile change, or something you want to run locally (the theme’s own tests), call Empress:site_call empress.theme_session_clone with the session, git clone --branch <session> the address it answers, commit, and push that branch only (never main), then empress.theme_check and Empress:theme_stage as usual. The address is a credential that works for an hour and can write the whole theme repository, so keep it out of logs and messages; for a change to a few files, patch.
  • A failed check stops the loop. The answer’s first line says what is wrong; patch, check again. A session whose build or typecheck failed is not staged (a failed test stops a stage only if it passes on the theme’s main), so “it is done” is never said of a session that does not build.
  • An anchor that misses or matches twice saves nothing and answers the file as it is: copy the anchor from that content, adding a neighbouring line until it is unique.
  • A 500 at any width stops the loop. Fix the session, check it, stage it again, render it again. Never promote “except for the phone”.
  • Same session, same stage. Staging again after a fix replaces the stage; there is no need to clear it.
  • A stage that says “Before promoting: …” is a warning, not a refusal. Today’s one: the theme adds a route (say /events) that a redirect kept in the site’s own admin sends elsewhere, so visitors never reach it though the stage preview shows it. Read the site’s redirects with Empress:site_call empress.site_redirects, then have the person remove or change that one in the site’s admin (or drop the route), and stage again.
  • Main moved since the session started? Empress:site_call empress.theme_session_update merges main into the session. On a clean merge, the session tip advances and the answer names the files main brought in. On a conflict, nothing is committed: the answer carries each conflicted file’s content from the session (ours), from main (theirs) and from their common ancestor (base); patch each file to resolve, then call empress.theme_session_update again with resolved: true to commit the merge.
  • Live moved since the stage? Empress:site_status says so; stage again on top of what is live rather than forcing.
  • A poor layout shift at a width is a finding to show the person, not a blocker to hide.
  • A theme too big for a session (pictures and fonts past the session’s limit) is refused with the way through: push a branch with the CLI and stage it.
  • A session nobody wants is thrown away with empress.theme_session_discard; the theme and the site are untouched.
  • A theme change that comes with copy or menu changes goes in a change set: pass its id to theme_stage and promote the set instead (see composing-a-change-set).