Skip to content

Studio Code: State the active site's WordPress version, block types, and Site Editor copies as facts - #5301

Merged
chubes4 merged 7 commits into
trunkfrom
studio-code/active-site-facts
Oct 23, 2026
Merged

chubes4 merged 7 commits into
trunkfrom
studio-code/active-site-facts

Conversation

@chubes4

@chubes4 chubes4 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Claude (via the Pi coding agent in a Roadie session) wrote the change and the tests, and ran the evaluation below. I reviewed the diff and the eval transcripts.

Proposed Changes

The Active site section now lists facts about a local site, read from its own files and database (site-facts.ts). For the STU-2155 header case it reads:

"Eval Template Override" at /…/eval-template-override (running)
WordPress 7.1.3.
Saved in the Site Editor, which WordPress uses instead of the theme's files: template part header (post 5).

A site with more saved copies gets one grouped line per kind, about 6 tokens per copy:

Saved in the Site Editor, which WordPress uses instead of the theme's files: templates index (post 12), single (13); template part header (post 11). Only in the Site Editor: template page-about (post 14); template part promo (post 15). Global Styles (post 16), applied over theme.json, set color, typography, 2 block styles, and color settings.
  • WordPress version: read from the site's wp-includes/version.php.
  • Copies saved in the Site Editor: the latest published wp_template and wp_template_part post per slug for the active theme, read read-only from the site's SQLite database with Node's built-in node:sqlite. Each copy is grouped by whether it replaces a file in the theme or its parent theme (checked on disk, in the folders WordPress reads them from) or exists only in the Site Editor.
  • Global Styles: the wp_global_styles post, with the areas it sets and a count of per-block styles. The details are in the post.
  • A site without a readable database gets no line.
  • Each line appears only when it applies. The prompt is rebuilt every turn, so a copy saved mid-session shows up on the next turn. WordPress.com sites get no facts.
  • The edit-manage-site sentence that told the agent to look for saved copies with post list is deleted.

Testing Instructions

Trunk (with the sentence) This branch (without it)
Template part (template-part-db-override) 6/6, 223k tokens, 17 calls 6/6, 167k tokens, 13 calls
Global styles (global-styles-db-override) 6/6, 189k tokens 4/4, 87k tokens in 3 runs, 1.4M in one

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

@chubes4
chubes4 marked this pull request as ready for review October 22, 2026 23:33
@wpmobilebot

wpmobilebot commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing b5e5d7e vs trunk

app-size

Metric trunk b5e5d7e Diff Change
App Size (Mac) 940.68 MB 940.68 MB +0.00 MB ⚪ 0.0%

site-editor

Metric trunk b5e5d7e Diff Change
load 1251 ms 1230 ms 21 ms ⚪ 0.0%

site-startup

Metric trunk b5e5d7e Diff Change
siteCreation 7510 ms 7538 ms +28 ms ⚪ 0.0%
siteStartup 4370 ms 4383 ms +13 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

chubes4 added a commit that referenced this pull request Oct 23, 2026
## Related issues

- Found in the STU-2155 header eval (#5092, #5301). An agent ran `post
update 5 --post_content=<site>/tmp/header-new.html`. That saved the path
itself as the template part's content, which wiped the header the site
renders, and the agent reported success.

## How AI was used in this PR

Claude (via the Pi coding agent in a Roadie session) wrote the change
and the tests, and ran the checks below. I reviewed the diff and the
tool output.

## Proposed Changes

WP-CLI's `--post_content` takes the content itself; `post create <file>`
and `post update <id> <file>` read it from a file. When `post create` or
`post update` gets a `--post_content` value that is the path of a file
in the site folder (absolute or relative to it), `wp_cli` now runs the
command with that file as the positional argument, so the post gets the
file's content. The result says so:

> Read the post content from tmp/y.html, the file `--post_content`
named.
> Success: Updated post 6.

- Unquoted content runs to the end of the command, so flags after the
path (`--porcelain`) are split back out and kept.
- Content that only looks like a path is saved as written, as before: a
missing file, a folder, a file outside the site folder, a path inside
text, or anything with markup.
- Only `post create` and `post update` change. Every other command runs
as written.
- Nothing new becomes possible: the rewritten command is one the agent
could already run. WP-CLI's `post update` reads the first non-numeric
argument as the file, so several IDs still work.
- `--post_content=$(cat file)` is still refused: shell syntax doesn't
run, and that's a different mistake.

## Testing Instructions

- `npx vitest run apps/cli/lib/tests/wp-cli-post-content.test.ts
apps/cli/ai` passes (289). New tests cover an absolute path, a relative
path with flags around it, five values that look like paths but aren't
files, files outside the site folder, and other commands.
- Real site. The agent wrote `tmp/x.html` and `tmp/y.html`, then ran:
- `post create --post_type=page --post_title=Probe --post_status=publish
--post_content=<absolute path of x.html> --porcelain`: page 6 created.
  - `post update 6 --post_content=tmp/y.html`: page 6 updated.
- Page 6's content was then `y.html`'s block markup. Without this
change, the first command saves `<path> --porcelain` as the content.
- No telemetry changes: the note goes to the tool result only.

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?
chubes4 added a commit that referenced this pull request Oct 23, 2026
…at show the block (#5307)

## Related issues

- Builds on #5300 (attribute check) and #5301 (Active site facts). Found
while evaluating #5301.

## How AI was used in this PR

Claude (via the Pi coding agent in a Roadie session) read the failing
eval transcripts, wrote the change and its tests, and ran the evals
below. I reviewed the code and the transcripts.

## Proposed Changes

When a tool result shows block markup, Studio Code adds one line for
each core block type in it, listing the settings that block type
declares in the site's own `wp-includes/blocks/<block>/block.json`. For
example:

> `core/navigation settings, declared in
…/wp-includes/blocks/navigation/block.json: ref (number), …,
showSubmenuIcon (boolean, default true), submenuVisibility
("hover"|"click"|"always", default "hover"), overlayMenu (string,
default "mobile"), …`

- Each block type is described once per turn. Attributes read from the
block's HTML (`source`) are content, so they are left out, along with
internal `__unstable`/`__experimental` ones.
- It applies to every Studio tool result, so `wp_cli post get`, `Read`
and `Bash cat` all get it.
- It reads files on disk only. Plugin blocks, remote sites and blocks
without a `block.json` are skipped.

**Why.** In the template-part eval ("Make the header navigation open its
submenus on click instead of on hover"), the failing runs reason
"there's no built-in 'open on click' toggle … this requires custom
JavaScript", then write a script and CSS into the theme, at 1–1.7M
tokens per run. The navigation block declares `submenuVisibility:
"click"`. The model doesn't remember it and has no reason to open
`block.json`. Stating the declared settings where the block appears
means the model reads them while it is looking at the block.

## Testing Instructions

- `npx vitest run apps/cli/ai/tests/block-settings.test.ts`: describes
the core blocks in a header from their `block.json`, describes each one
once, and leaves out content attributes, closing comments and blocks
without a `block.json`.
- **Eval:** `template-part-db-override`, 6 runs per arm, run against
this branch and current trunk (`09253bcef`) at the same time:

| | Pass | JS workaround | Mean tokens | Mean tool calls | Mean time |
|---|---|---|---|---|---|
| This branch | 6/6 | 0 | 223k | 17 | 53s |
| Trunk | 4/5 | 1 | 675k | 32 | 94s |

One trunk run stalled at the 420s timeout after 91k tokens without
reaching an answer. It is left out above as an infrastructure stall.
Counted as a failure, trunk is 4/6.
- Every branch run's session shows the `core/navigation settings` line
in the `post get 5` or `Read parts/header.html` result, and every branch
run set `submenuVisibility` in the saved header. No branch run wrote
JavaScript or read core's `navigation/view.js`. On trunk, one run wrote
a script and another read `view.js` three times before finding the
setting.
- **Regression check:** the three other cases that start on a local
site, 6 runs per arm:

| Case | This branch | Trunk |
|---|---|---|
| `global-styles-db-override` | 6/6, 189k tokens | 5/6, 187k tokens |
| `design-system-annotation` | 6/6, 260k tokens | 5/6, 289k tokens |
| `active-site-reused` | 6/6, 68k tokens | 6/6, 66k tokens |

Both trunk failures are unrelated to this change: one is a port
collision during inspection, the other discarded the saved styles. The
settings line appeared in only 1 of these 18 runs (it passed), because
these tasks rarely read block markup, so this check shows no harm rather
than a gain.
- **Size:** replaying 263 earlier sessions that read block markup, the
added lines come to a median of ~240 tokens per session (p90 ~460, max
~1.8k).
- Six runs per arm can't establish a pass-rate gain, so the claim is
parity or better on accuracy. The fall in tokens and tool calls is large
and consistent across runs.

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?
@chubes4
chubes4 merged commit e32085b into trunk Oct 23, 2026
13 checks passed
@chubes4
chubes4 deleted the studio-code/active-site-facts branch October 23, 2026 04:47
@youknowriad

Copy link
Copy Markdown
Contributor

I don't understand this PR to be honest. the facts about a given sites are infinite and can change over time. While I understand the WordPress version, all the rest feel like useless information in the context most of the time.

@chubes4

chubes4 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

It's a step towards removing skill routing from the system prompt

@youknowriad

Copy link
Copy Markdown
Contributor

How so?

@chubes4

chubes4 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

It's leading towards the goal of reducing non-deterministic behavior and simplifying our system prompts to make the agent more fluid and accurate.

When running evals for #5265, I found that the agent often skipped skills, or would pick edit-manage-site over the more focused skills. My plan is to remove edit-manage-site to unblock this. That means moving more of those skill responsibilities into structure. This should cause the agent to naturally reach for the more focused skills.

You are right that this can be useless context most of the time though. I think a better idea is to move the saved Site Editor copy notice into the tool results similarly to how #5307 handles core block context.

@youknowriad

Copy link
Copy Markdown
Contributor

FYI edit-manage-site is a for the plugins / mcp though. It's a recent addition specifically targeted towards these plugins that expose high level skills.

chubes4 added a commit that referenced this pull request Oct 23, 2026
…all touches the theme file they replace (#5343)

## Related issues

- Follows #5301, addressing the review there: the saved Site Editor
copies were listed in every system prompt, though they matter only when
the agent touches a theme file they replace.
- Builds on #5333's shared result notes, so the notice reaches Studio
Code and `studio mcp` the same way.

## How AI was used in this PR

Claude (via the Pi coding agent in a Roadie session) wrote the change
and the test and ran the evals below. I reviewed the diff and the
results.

## Proposed Changes

When someone saves a template, template part or Global Styles in the
Site Editor, WordPress renders that saved copy instead of the theme
file. An agent that edits `parts/header.html` then changes nothing the
visitor sees. #5092 told the agent this in `edit-manage-site`; #5301
moved it into Active site facts, which listed every saved copy in every
prompt.

- The notice moves into tool results, stated when a call or its result
names a theme file a saved copy replaces, for example:
> WordPress renders the template part header from its copy saved in the
Site Editor (post 12), not from
wp-content/themes/twentytwentyfive/parts/header.html.
- `cli/ai/saved-copies.ts` reads the copies from the site's SQLite
database when a theme file is named, so copies saved earlier in the turn
count. Each copy is stated once per tracker.
- It is registered in `cli/ai/result-notes.ts` (#5333). The notes now
see the call's arguments with its result (a Write names the file in its
arguments), on both surfaces.
- Active site facts keep the WordPress version; saved copies leave them.

Limits:

- MCP clients read and write theme files with their own tools, which
never pass through Studio, so for them the notice fires only when a
Studio tool names the file.
- Like every result note, a notice stated early in a turn can be lost if
the context is compacted later in that turn.

## Testing Instructions

- `npx vitest run apps/cli/ai/tests/saved-copies.test.ts`: a real SQLite
database with a saved template part and Global Styles; notices for the
theme files they replace, none for other files, and each copy once; run
with `wp_` tables and with another prefix, as imported sites can have.
- Eval (`/tmp` override kit, 6 runs per case, Studio's default model): a
site whose header part and Global Styles were saved in the Site Editor;
the task edits the header, then the styles. Scored from the rendered
site.

  | Case | #5301 (facts in prompt) | This PR |
  |---|---|---|
  | Template part saved in the Site Editor | 6/6 | 6/6 |
  | Global Styles saved in the Site Editor | 4/4 | 6/6 |

The notice appeared in all 12 transcripts. An earlier run of this change
scored 5/6 on Global Styles; the miss was broken JSON the agent wrote to
a file and saved with `post update`, which the inline `--post_content`
JSON check (#5310) does not cover.

- Eval on site edits with no saved copies (8 cases from the routing
eval: contact form, carousel, newsletter, heading font, testimonials,
header search block, hero, spacing; each run stops at its first write).
Before #5301, `edit-manage-site` told the agent to check for saved
copies first; #5092's review asked what that costs.

| | Sessions that queried saved copies | Queries | Tool calls before the
first write |
  |---|---|---|---|
  | Before #5301 (Oct 22 runs) | 38/126 | 43 | 14.3 |
  | This PR | 0/32 | 0 | 14.1 |

The queries are gone, but calls before the first write are unchanged:
the agent spends them on other reading. Tokens (median 134k before, 136k
now) and wall time (median 38.6s on trunk, 36.4s now) are at parity too.

## Pre-merge Checklist

- [ ] Have you checked for TypeScript, React or other console errors?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants