A live demo or admin page shipped with every feature whose results the user would otherwise not see. Use when adding a backend endpoint or feature with no UI to see it, when output only shows in logs, the DB, or an agent run, or when the user asks 'how do I test this'.
Installs into .claude/skills of the current project.
Are you the author of Feature Visibility Surface?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/armanisadeghi-feature-visibility-surface)
---
name: feature-visibility-surface
description: "A live demo or admin page shipped with every feature whose results the user would otherwise not see. Use when adding a backend endpoint or feature with no UI to see it, when output only shows in logs, the DB, or an agent run, or when the user asks 'how do I test this'."
---
# Ship a visibility surface with every feature (frontend recipe)
> **A feature the user can't open and watch work is a feature you'll both burn turns
> guessing about.** Build the page in the SAME change — it's the next file, not a ticket.
## Demo page or admin page?
- **No privileges to view** → **demo**: `(dev)/demos/<name>/page.dev.tsx` (auth shell) or
`(public-demos)/demos/public/<name>/page.tsx` (no auth). Auto-listed at `/demos`. Use the
`new-route-scaffold` skill to place it.
- **Needs privileged / cross-user / admin data or actions** → **admin**:
`(admin)/administration/<name>/page.tsx` (super-admin gated at the layout; lower with an
in-page `selectIsAdmin` seam if org-admins should reach it later).
Prefer the lower bar (demo) when unsure.
## The recipe (self-contained `features/<name>/`)
- **Read the live backend, never hardcode the URL.** Resolve the base from
`selectResolvedBaseUrl` (`apiConfigSlice`) — the same value every backend call uses, so
the admin server toggle routes it. Runtime-guard the JSON (untrusted). For authed
POST/execute calls use the canonical backend client (`lib/api/backend-client.ts` →
`createAuthenticatedClient`), not a hand-rolled fetch.
- **Make it a test bench, not just a viewer.** A few `Select`/inputs to drive the feature;
show the REAL result (and, for actions, the receipt). Reuse existing renderers — e.g. the
`features/matrx-envelope` block renderer for live reference chips — never fork one.
- **Real states + real-time.** Component-library loading/empty/error states (never plain
"Loading…"), a manual Refresh + light polling so it mirrors the live server with no
redeploy.
- **Standards.** Semantic tokens only, Lucide icons, no emojis, dense + scannable for an
admin surface (see `ui-dense` / `data-dense-panels`). No new barrels; import from source.
## Reuse, never fork
Base URL resolver, backend client, component library, admin gate, envelope renderer — all
exist. If you're writing a second fetch layer or a second renderer, stop.
## Worked example (copy its shape)
`features/directive-catalog/` → `/administration/directive-catalog`: a live grid of every
capability (read from `GET /directives/catalog`) + a dropdown builder that runs one and shows
the receipt (`POST /directives/execute`). That's the bar.
## Done means
The page opens, reads the **live** backend, shows the real output, lets the user
trigger/test the meaningful path, is reachable (feature admin map / `/demos` index), and you
told the user the exact URL + what they'll see in your turn summary.