fix(web): render operator overview HTML inside welcome-hero footnotes

Restore the original Overview rendering contract: the
`instance.overview` (`AGNES_INSTANCE_OVERVIEW`) HTML body renders
verbatim via `| safe` filter, just inside the welcome hero's
`.home-hero-footnotes` styled block instead of as a standalone
`<section class="home-overview">` between the walkthrough and
surfaces grid. Only the location and styling moved — existing
instances that set the yaml field get the same content in the
new home.

Tests updated accordingly: footnotes render the operator's HTML
marker when the flag is set (mirrors the previous
`test_overview_section_renders_when_yaml_set`), and are absent
when the flag is empty (mirrors `test_overview_section_hidden_when_yaml_empty`).
This commit is contained in:
David Rybar 2026-05-22 11:50:08 +02:00
parent 2db1dceca1
commit 19eef69092
3 changed files with 29 additions and 65 deletions

View file

@ -40,20 +40,15 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
(`Step 1 of N · ~15 min · One-time · Reversible`), a thin progress (`Step 1 of N · ~15 min · One-time · Reversible`), a thin progress
bar, and per-step number badges next to each install block. bar, and per-step number badges next to each install block.
### Changed
- `/home` welcome hero gains a *footnotes* row beneath the four - `/home` welcome hero gains a *footnotes* row beneath the four
pillars: a hairline-separated block carrying the privacy posture pillars: a hairline-separated block rendering operator-authored
(*"What leaves your machine"* — telemetry travels, raw data HTML from `instance.overview` (`AGNES_INSTANCE_OVERVIEW` env
stays local, `/agnes-private` toggles per-session) and the override). This is the same `| safe`-filtered body that used to
workspace-layout convention (*"Get the most out of it"* — work drive the standalone Overview section between the walkthrough
under `~/<workspace_dir>/Projects/`, anything outside the and surfaces grid — the rendering contract is unchanged, only
workspace root is invisible to the platform). Gated on the same the location and styling moved. Empty yaml → footnotes absent
`instance.overview` / `AGNES_INSTANCE_OVERVIEW` flag that used (OSS stays vendor-neutral). Renders for both onboarded and
to drive the standalone Overview section — any non-empty value not-onboarded users.
acts as the feature flag — so the OSS keeps a vendor-neutral
default (empty yaml → footnotes absent) while operators who
flip the flag get a consistent message across instances.
Renders for both onboarded and not-onboarded users.
- Welcome hero's *"AI Chief of Staff"* lede gains a trailing - Welcome hero's *"AI Chief of Staff"* lede gains a trailing
sentence ("*You run all your projects inside and it learns sentence ("*You run all your projects inside and it learns
from it.*") so the workspace-folder framing lands before the from it.*") so the workspace-folder framing lands before the
@ -259,17 +254,14 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
top of `/home` (the in-page anchor it carried — *Setup Agnes in top of `/home` (the in-page anchor it carried — *Setup Agnes in
your Claude Code* / *Go deeper into your AI workspace* — duplicated your Claude Code* / *Go deeper into your AI workspace* — duplicated
links already reachable from the install hero and `/setup-advanced`). links already reachable from the install hero and `/setup-advanced`).
- Operator-owned *Overview* `<section>` on `/home` (rendered the - Operator-owned *Overview* `<section>` on `/home` no longer
`instance.overview` / `AGNES_INSTANCE_OVERVIEW` HTML body between renders as a standalone block between the first-session
the first-session walkthrough and the surfaces grid). The walkthrough and the surfaces grid. The same operator-authored
privacy-posture / workspace-layout copy it carried now ships HTML body (`instance.overview` / `AGNES_INSTANCE_OVERVIEW`) now
inline in the welcome hero footnotes (see *Changed* above). The renders inside the welcome hero footnotes instead (see *Changed*
`get_instance_overview()` helper and yaml field still drive the above) — the rendering contract is unchanged, only the location
feature flag for the new footnotes block, but the raw HTML body and styling moved, so existing instances that set the yaml
the operator stored there is no longer rendered (the static field get the same content in the new home.
product framing replaces it) — operators who relied on injecting
custom Overview HTML should migrate that content to
`instance.custom_scripts` or admin-edited news.
### Removed ### Removed

View file

@ -2308,23 +2308,7 @@
block is opt-in at the operator level (empty yaml → block is opt-in at the operator level (empty yaml →
block absent), which is the right axis of control. #} block absent), which is the right axis of control. #}
{% if config.INSTANCE_OVERVIEW %} {% if config.INSTANCE_OVERVIEW %}
<div class="home-hero-footnotes"> <div class="home-hero-footnotes">{{ config.INSTANCE_OVERVIEW | safe }}</div>
<p>
<strong>What leaves your machine.</strong> Session telemetry &mdash; prompts, tool calls,
and tool responses &mdash; flows back to the central catalog so the team can analyse failure
patterns. Raw data rows you query locally stay on your machine; only the prompt/response
transcript travels. Need a session off the record? Toggle Private in Claude Code to disable
telemetry for that chat by calling command <code>/agnes-private</code> in {{ instance_brand }}
project folder &mdash; nothing from that session reaches the system.
</p>
<p>
<strong>Get the most out of it</strong> by working under <code>~/{{ workspace_dir }}/Projects/</code>.
Create every project there &mdash; existing or new, fresh starts or clones of repos you already
use. The bundled plugin keeps each project in sync with the central catalog (data packages,
plugins, skills, memory) automatically, and the session-analysis loop is scoped to that root.
Anything outside <code>~/{{ workspace_dir }}/</code> is invisible to the platform.
</p>
</div>
{% endif %} {% endif %}
</section> </section>

View file

@ -359,17 +359,15 @@ def test_setup_section_renders_for_not_onboarded(fresh_db):
assert '<div class="setup-section-header"' not in body2 assert '<div class="setup-section-header"' not in body2
def test_overview_section_replaced_by_welcome_footnotes(fresh_db, monkeypatch): def test_welcome_footnotes_render_overview_when_set(fresh_db, monkeypatch):
"""The standalone operator-owned Overview `<section>` was removed """Setting `AGNES_INSTANCE_OVERVIEW` (mirrors `instance.overview`
from `/home`. Its privacy / workspace-layout copy now ships as yaml) injects raw HTML into the welcome-hero footnotes via the
static product framing inside the welcome hero footnotes same `| safe` filter as the previous standalone Overview
(`.home-hero-footnotes`). The `instance.overview` yaml field section. The marker text MUST appear inside
(`AGNES_INSTANCE_OVERVIEW`) keeps its gating role any `.home-hero-footnotes`, and the legacy `<section class="home-overview">`
non-empty value acts as the feature flag but its raw HTML wrapper MUST stay absent the operator-owned body now lives
body is no longer rendered (the static copy replaces it). When inside the welcome card, not as a separate section between the
set: the standalone section MUST stay absent and the walkthrough and surfaces grid."""
footnotes block MUST appear, but the raw yaml HTML body MUST
NOT leak into the page."""
monkeypatch.setenv("AGNES_INSTANCE_OVERVIEW", "<p>OVERVIEW_TEST_MARKER</p>") monkeypatch.setenv("AGNES_INSTANCE_OVERVIEW", "<p>OVERVIEW_TEST_MARKER</p>")
from src.db import get_system_db, close_system_db from src.db import get_system_db, close_system_db
@ -381,19 +379,14 @@ def test_overview_section_replaced_by_welcome_footnotes(fresh_db, monkeypatch):
close_system_db() close_system_db()
body = _client().get("/home", cookies={"access_token": sess}).text body = _client().get("/home", cookies={"access_token": sess}).text
assert '<section class="home-overview">' not in body assert '<section class="home-overview">' not in body
assert "OVERVIEW_TEST_MARKER" not in body
assert '<div class="home-hero-footnotes">' in body assert '<div class="home-hero-footnotes">' in body
# "Get the most out of it" is unique to the footnotes block — the assert "OVERVIEW_TEST_MARKER" in body
# original "What leaves your machine" copy still exists in the
# session-privacy annotation lower on the page (untouched), so we
# can't use it as a footnotes marker.
assert "Get the most out of it" in body
def test_welcome_footnotes_hidden_when_overview_unset(fresh_db, monkeypatch): def test_welcome_footnotes_hidden_when_overview_unset(fresh_db, monkeypatch):
"""Default empty `instance.overview` (no env override) hides the """Default empty `instance.overview` (no env override) hides the
welcome-hero footnotes entirely so the OSS ships without the welcome-hero footnotes entirely so the OSS ships without a
central-catalog privacy framing baked into the welcome card.""" stray empty footnotes block in the welcome card."""
monkeypatch.delenv("AGNES_INSTANCE_OVERVIEW", raising=False) monkeypatch.delenv("AGNES_INSTANCE_OVERVIEW", raising=False)
from src.db import get_system_db, close_system_db from src.db import get_system_db, close_system_db
@ -405,8 +398,3 @@ def test_welcome_footnotes_hidden_when_overview_unset(fresh_db, monkeypatch):
close_system_db() close_system_db()
body = _client().get("/home", cookies={"access_token": sess}).text body = _client().get("/home", cookies={"access_token": sess}).text
assert '<div class="home-hero-footnotes">' not in body assert '<div class="home-hero-footnotes">' not in body
# "Get the most out of it" is the unique footnotes marker — the
# original "What leaves your machine" copy in the session-privacy
# annotation lower on the page always renders, so checking that
# would be a false-positive.
assert "Get the most out of it" not in body