feat(web): welcome hero footnotes + drop operator Overview section

Welcome hero on /home gains a hairline-separated footnotes row below
the four pillars carrying the privacy posture (telemetry travels,
raw data stays local, /agnes-private toggles per-session) and the
workspace-layout convention (work under ~/<workspace_dir>/Projects/,
anything outside is invisible to the platform). Renders for both
onboarded and not-onboarded users.

Lede 2 gains a trailing sentence so the workspace-folder framing
lands before the reader scrolls past.

The operator-owned <section class="home-overview"> is removed — its
privacy / workspace-layout copy now ships inline in the welcome
footnotes, so a separate operator surface for the same content is
redundant. The get_instance_overview() helper and instance.overview
yaml field remain (harmless if set; just not rendered) so existing
instances that override them don't trip on a removed config key.
This commit is contained in:
David Rybar 2026-05-22 11:20:49 +02:00
parent eb75c8d204
commit 61262e2bbb
3 changed files with 76 additions and 49 deletions

View file

@ -41,6 +41,19 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
bar, and per-step number badges next to each install block. bar, and per-step number badges next to each install block.
### Changed ### Changed
- `/home` welcome hero gains a *footnotes* row beneath the four
pillars: a hairline-separated block carrying the privacy posture
(*"What leaves your machine"* — telemetry travels, raw data
stays local, `/agnes-private` toggles per-session) and the
workspace-layout convention (*"Get the most out of it"* — work
under `~/<workspace_dir>/Projects/`, anything outside the
workspace root is invisible to the platform). Renders for both
onboarded and not-onboarded users so the operating model is
visible on every visit.
- Welcome hero's *"AI Chief of Staff"* lede gains a trailing
sentence ("*You run all your projects inside and it learns
from it.*") so the workspace-folder framing lands before the
reader scrolls past.
- Default `instance.theme` flipped from `navy` to `blue`. The brand-blue - Default `instance.theme` flipped from `navy` to `blue`. The brand-blue
palette is now the out-of-the-box look; `navy` (dark hero + mint-green palette is now the out-of-the-box look; `navy` (dark hero + mint-green
CTAs) is the opt-in via `AGNES_INSTANCE_THEME` / `instance.theme` CTAs) is the opt-in via `AGNES_INSTANCE_THEME` / `instance.theme`
@ -242,6 +255,15 @@ 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
`instance.overview` / `AGNES_INSTANCE_OVERVIEW` HTML body between
the first-session walkthrough and the surfaces grid). The
privacy-posture / workspace-layout copy it carried now ships
inline in the welcome hero footnotes, so a separate operator
surface for the same content is no longer needed. The
`get_instance_overview()` helper and yaml field remain (harmless
if set; just not rendered) so existing instances that override
it don't trip on a removed config key.
### Removed ### Removed

View file

@ -1103,6 +1103,34 @@
line-height: 1.55; line-height: 1.55;
margin: 0; margin: 0;
} }
/* Hero footnotes — two short paragraphs about telemetry + workspace layout,
rendered below the pillars row inside the same dark navy hero. Same
hairline separator pattern as `.home-hero-pillars` so the section
reads as a continuation of the welcome card. */
.home-mock .home-hero-footnotes {
margin-top: 26px;
padding-top: 26px;
border-top: 1px solid rgba(255, 255, 255, 0.12);
position: relative;
}
.home-mock .home-hero-footnotes p {
font-size: 13.5px;
color: rgba(255, 255, 255, 0.78);
line-height: 1.6;
margin: 0 0 12px;
max-width: 860px;
}
.home-mock .home-hero-footnotes p:last-child { margin-bottom: 0; }
.home-mock .home-hero-footnotes strong { color: #ffffff; font-weight: 600; }
.home-mock .home-hero-footnotes code {
background: rgba(15, 23, 42, 0.55);
color: #FBBF24;
border: 1px solid rgba(251, 191, 36, 0.30);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--ds-font-mono);
font-size: 11.5px;
}
@media (max-width: 880px) { @media (max-width: 880px) {
.home-mock .home-hero-intro { padding: 32px 24px 28px; } .home-mock .home-hero-intro { padding: 32px 24px 28px; }
.home-mock .home-hero-intro h1 { font-size: 26px; } .home-mock .home-hero-intro h1 { font-size: 26px; }
@ -2235,7 +2263,7 @@
<p class="lede"> <p class="lede">
Think of it as your <em>AI Chief of Staff</em> &mdash; it lives in a folder on your computer, Think of it as your <em>AI Chief of Staff</em> &mdash; it lives in a folder on your computer,
gives you access to company data and curated skills, and lets you share your own skills gives you access to company data and curated skills, and lets you share your own skills
and plugins back to the team. and plugins back to the team. You run all your projects inside and it learns from it.
</p> </p>
<div class="home-hero-cta"> <div class="home-hero-cta">
{% if not onboarded %} {% if not onboarded %}
@ -2261,6 +2289,23 @@
<p>Shared analyst knowledge and prior solutions, fed back into Claude's context on demand.</p> <p>Shared analyst knowledge and prior solutions, fed back into Claude's context on demand.</p>
</div> </div>
</div> </div>
<div class="home-hero-footnotes">
<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>
</section> </section>
{# Homepage status frame — five counters with 24h/7d toggle. {# Homepage status frame — five counters with 24h/7d toggle.
@ -2771,24 +2816,6 @@ Want me to draft a 1-page brief, or dig into one of these?
</div> </div>
</section> </section>
{# Overview section — operator-owned, opt-in. Body comes from the
`instance.overview` yaml field via get_instance_overview()
(`AGNES_INSTANCE_OVERVIEW` env override). Empty value hides the
whole section, keeping the OSS vendor-neutral. #}
{# Overview is operator-owned reference content, not per-user
chrome — no dismiss button on purpose. A one-time per-device
hide would mean returning users who wanted to re-read the
privacy posture / telemetry policy can't get back to it
without clearing localStorage. The whole section is opt-in at
the operator level (empty yaml → section absent), which is
the right axis of control. #}
{% if config.INSTANCE_OVERVIEW %}
<section class="home-overview">
<h2>Overview</h2>
<div class="home-overview-body">{{ config.INSTANCE_OVERVIEW | safe }}</div>
</section>
{% endif %}
{# Surfaces — four places to use {{ instance_brand }}. Mirrors the {# Surfaces — four places to use {{ instance_brand }}. Mirrors the
design spec's "Where you can use it" section: VS Code (RECOMMENDED), design spec's "Where you can use it" section: VS Code (RECOMMENDED),
Terminal, Claude Desktop, Cowork (claude.ai). Each card carries Terminal, Claude Desktop, Cowork (claude.ai). Each card carries

View file

@ -359,39 +359,16 @@ 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_renders_when_yaml_set(fresh_db, monkeypatch): def test_overview_section_never_renders(fresh_db, monkeypatch):
"""Setting `AGNES_INSTANCE_OVERVIEW` env (mirrors """The operator-owned Overview `<section>` was removed from
instance.overview yaml) injects raw HTML into the Overview section `/home` its privacy / workspace-layout copy now ships inline
via the same `| safe` filter as news_intro. The marker text must in the welcome hero footnotes. The `get_instance_overview()`
appear inside the rendered section wrapper. Overview deliberately helper and `instance.overview` yaml field still exist (to avoid
has NO dismiss button it's operator-owned reference content breaking instances that override them), but the rendered
(privacy posture, telemetry policy, product framing), and a section MUST NOT appear regardless of the env value."""
per-device hide would leave returning users unable to re-read
it without clearing localStorage."""
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
conn = get_system_db()
try:
_, sess = _make_user_and_session(conn)
finally:
conn.close()
close_system_db()
body = _client().get("/home", cookies={"access_token": sess}).text
assert '<section class="home-overview">' in body
assert "OVERVIEW_TEST_MARKER" in body
# Overview must NOT carry a dismiss key — content stays
# reachable on every visit so users can re-read it.
assert 'data-dismiss-key="agnes_home_overview_dismissed"' not in body
def test_overview_section_hidden_when_yaml_empty(fresh_db, monkeypatch):
"""Default empty `instance.overview` (no env override) hides the
section entirely so the OSS ships without a stray empty
Overview placeholder."""
monkeypatch.delenv("AGNES_INSTANCE_OVERVIEW", raising=False)
from src.db import get_system_db, close_system_db
conn = get_system_db() conn = get_system_db()
try: try:
_, sess = _make_user_and_session(conn) _, sess = _make_user_and_session(conn)
@ -400,3 +377,4 @@ def test_overview_section_hidden_when_yaml_empty(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