diff --git a/app/web/router.py b/app/web/router.py
index e204d7d..fdae031 100644
--- a/app/web/router.py
+++ b/app/web/router.py
@@ -974,6 +974,7 @@ async def admin_workspace_prompt_page(
):
from src.repositories.claude_md_template import ClaudeMdTemplateRepository
from src.claude_md import compute_default_claude_md
+ from app.api.claude_md import _scan_legacy_strings
row = ClaudeMdTemplateRepository(conn).get()
server_url = str(request.base_url).rstrip("/")
@@ -986,6 +987,7 @@ async def admin_workspace_prompt_page(
updated_at=row["updated_at"],
updated_by=row["updated_by"],
is_override=row["content"] is not None,
+ legacy_strings_detected=_scan_legacy_strings(row["content"] or ""),
)
return templates.TemplateResponse(request, "admin_workspace_prompt.html", ctx)
diff --git a/app/web/templates/admin_workspace_prompt.html b/app/web/templates/admin_workspace_prompt.html
index e8c1d2b..51206be 100644
--- a/app/web/templates/admin_workspace_prompt.html
+++ b/app/web/templates/admin_workspace_prompt.html
@@ -271,6 +271,20 @@
+ {% if legacy_strings_detected %}
+
+
This override references CLI verbs / paths that were renamed:
+
+ {% for hit in legacy_strings_detected %}
+ {{ hit }}
+ {% endfor %}
+
+
Re-author and Save to clear this warning. See CHANGELOG.md for the rename list.
+
+ {% endif %}
+
Editor
diff --git a/tests/test_legacy_strings_scan.py b/tests/test_legacy_strings_scan.py
index 73937b9..4120327 100644
--- a/tests/test_legacy_strings_scan.py
+++ b/tests/test_legacy_strings_scan.py
@@ -121,3 +121,51 @@ def test_admin_get_template_returns_empty_when_clean(web_session):
resp = web_session.get("/api/admin/workspace-prompt-template")
assert resp.status_code == 200, resp.text
assert resp.json()["legacy_strings_detected"] == []
+
+
+# ---------------------------------------------------------------------------
+# HTML banner tests — admin /admin/workspace-prompt page renders a yellow
+# warning banner above the editor when the saved override contains stale
+# CLI verbs / paths.
+# ---------------------------------------------------------------------------
+
+
+def test_admin_workspace_prompt_page_renders_banner_when_legacy_present(web_session):
+ """When the saved override contains legacy strings, the admin UI renders
+ a yellow warning banner above the editor listing the hits."""
+ web_session.put(
+ "/api/admin/workspace-prompt-template",
+ json={"content": "Run `da sync` and check data/parquet/."},
+ )
+ resp = web_session.get("/admin/workspace-prompt")
+ assert resp.status_code == 200
+ text = resp.text
+ # Banner is rendered (id, class, or distinctive styling)
+ assert "legacy-banner" in text or "renamed" in text.lower() or "warning" in text.lower()
+ # Specific hits appear in the banner content
+ assert "da sync" in text
+ assert "data/parquet" in text
+
+
+def test_admin_workspace_prompt_page_no_banner_when_clean(web_session):
+ """When the override has no legacy strings, the banner block is absent
+ (or rendered as empty/hidden)."""
+ web_session.put(
+ "/api/admin/workspace-prompt-template",
+ json={"content": "Use `agnes pull` and `server/parquet/`."},
+ )
+ resp = web_session.get("/admin/workspace-prompt")
+ assert resp.status_code == 200
+ text = resp.text
+ # The banner div should not appear (or its content should not list hits)
+ # Pin to the legacy-banner id; the {% if %} guard means absent when clean
+ assert "legacy-banner" not in text
+
+
+def test_admin_workspace_prompt_page_no_banner_when_no_override(web_session):
+ """No saved override at all → banner absent."""
+ # Reset to default by deleting any existing override
+ web_session.delete("/api/admin/workspace-prompt-template")
+ resp = web_session.get("/admin/workspace-prompt")
+ assert resp.status_code == 200
+ assert "legacy-banner" not in resp.text