| name | _ctx-surface-audit |
| description | ctx-repo-internal (note the _ prefix; sibling of _ctx-command-audit / _ctx-audit). Out-of-band audit: scan a git ref range for ctx user-facing surfaces — new ctx subcommands, flags, behavior — that landed without matching SKILL.md, recipe, or docs/cli updates. Run from a SEPARATE Claude Code session, not the one that wrote the code. Drops a report at .context/audit/surface.md for the ctxctl audit-relay hook to relay verbatim. |
| allowed-tools | Bash(git:*), Bash(rg:*), Bash(grep:*), Bash(find:*), Read, Glob, Grep, Write |
You are the surface audit: an out-of-band reviewer that
catches user-facing changes landing without matching agent
SKILL.md, recipe, or docs/cli updates.
This skill is internal to the ctx repository (the _
prefix marks it as repo-only dev tooling, like
_ctx-command-audit and _ctx-audit; it is not bundled into
end-user installs). It hard-codes ctx's own directory layout
(internal/cli/, internal/assets/commands/,
internal/config/embed/, docs/recipes/). It is the
reference producer for the generic audit channel
(ctxctl audit + ctxctl audit-relay), which lives in the
maintainer-only ctxctl binary (not the shipped ctx
binary); a downstream project that wants the pattern writes
its own audit skill targeting its own conventions and drops
reports into the same .context/audit/ channel.
The whole point of this skill is fresh-context judgment.
The agent that just shipped a feature has tunnel vision; you
do not. You read the diff cold and ask: "if a user runs ctx help or asks /ctx-<area> to do this new thing today, will
the help text / skill / recipe match what the code does?"
Trust Boundary (Refuse Loudly)
Before reading anything, run git status --porcelain and git diff --stat. If the working tree is not clean for the
audit target range, refuse:
Run this audit from a separate Claude Code session. The
current worktree has uncommitted changes to the range I am
being asked to audit. The implementer cannot grade their
own homework. Commit or stash here first, then re-invoke
me in another session.
This is non-negotiable. The channel exists because in-band
judgment fails; running the audit inside the implementing
session defeats the design.
Inputs
- Target range: defaults to
main..HEAD. User may pass a
different ref pair as a positional argument.
- Repository state: assumed clean per the Trust Boundary
check.
What to Scan
For the diff git diff --name-status <range>:
- New
ctx subcommands: look for new entries in
internal/assets/commands/commands.yaml, new files under
internal/cli/*/cmd/<name>/, new Use* and DescKey*
constants in internal/config/embed/cmd/.
- New flags: new entries in
internal/assets/commands/flags.yaml, new DescKey*Flag
constants in internal/config/embed/flag/, new
flagbind.*Flag calls in subcommand cmd.go files.
- New behavior on existing commands: changed RunE
bodies, new branches in existing flag handling, new
output strings in
internal/write/<area>/.
- New skill triggers: changes to existing
SKILL.md files that name new user-typed phrases (the
inverse direction — code change came first, skill row may
need to follow).
- New i18n keys: new entries in
internal/assets/commands/text/*.yaml indicating new
user-visible strings.
Coverage Checks per Surface
For each surface you find, check each location in order. Stop
at the first miss and record it; do not assume later
locations are correct.
A. SKILL.md command-mapping table
For a new subcommand or flag in area <X>, the canonical skill
is at internal/assets/claude/skills/ctx-<X>/SKILL.md. Inside
it, the "Command Mapping" table (a table headed | User intent | Command |) must list the new surface with at least one
natural-language trigger phrase.
- If the file exists and the row is present: PASS.
- If the file exists and the row is missing: FAIL — record
the surface, the file path, and the missing row shape.
- If the file does not exist: FAIL — note that the skill
area has no SKILL.md at all (much larger gap).
B. Recipe coverage
For a new subcommand or flag, scan docs/recipes/*.md for any
recipe whose title or "Commands and Skills Used" table
mentions the parent command. If any do, that recipe must
mention the new surface (in the commands table or in a
walked-through step).
- If recipes mention the parent command and one of them now
references the new surface: PASS.
- If recipes mention the parent command but none reference
the new surface: FAIL — list the affected recipes.
- If no recipes mention the parent command and the surface
is a NEW workflow shape (e.g. a new subsystem), recommend a
new recipe under
docs/recipes/<area>-<workflow>.md.
C. docs/cli/<command>.md
If a per-command page exists at docs/cli/<command>.md, it
must mention the new subcommand or flag.
- Page exists and updated: PASS.
- Page exists and stale: FAIL — name the page.
- Page does not exist: not a hard fail (per-command pages
are optional in this repo), but note as INFO.
D. Integrations parallel-skill (copilot-cli etc.)
If internal/assets/integrations/copilot-cli/skills/ctx-<X>/
exists, the same SKILL.md row must appear there too.
- Updated: PASS.
- Missing row: FAIL — record the file path.
- Directory does not exist: skip (no parallel skill).
Report Format
Write the report to .context/audit/surface.md. Overwrite if
present (one report per kind; history lives in the dismissal
ledger).
Exact shape — frontmatter delimited by ---, fields in order
listed:
---
kind: surface
status: <findings|clean>
commit-range: <ref-from>..<ref-to>
generated-at: <RFC3339 UTC, e.g. 2026-05-24T14:30:12Z>
generator: /ctx-surface-audit
digest: <short opaque digest of the findings body>
---
<verbatim body suitable for direct relay>
Body shape — status: findings
Commit <SHA-or-range> added user-facing surface without docs:
• New subcommand `ctx <command>`
- SKILL.md: <path> command-mapping table is missing the row
- Recipe: <path> mentions `ctx <command>` but not the new subcommand
• New flag `--<flag>` on `ctx <existing-command>`
- SKILL.md: <path> Execution section omits this flag
Fix:
- edit <path-1>
- edit <path-2>
- consider adding a new recipe at docs/recipes/<suggested-slug>.md
Keep wording concrete. Prefer file paths over abstract names.
Body shape — status: clean
No surface drift detected in <ref-from>..<ref-to>.
Surfaces scanned: <N>
Coverage checked: SKILL.md, recipes, docs/cli, integrations
A clean report is still useful — ctxctl audit list shows
it with a timestamp, so the user knows the audit ran.
Digest
Compute a short opaque digest of the findings body (say, first
7 hex chars of SHA-256 of the body bytes). Used by the
dismissal ledger to detect "fresh findings" — a re-audit that
produces the same digest stays dismissed; new findings clear
the dismissal.
Execution Steps
- Run the dirty-tree guard. Refuse if non-clean.
- Compute the target range (default
main..HEAD).
- Run
git diff --name-status <range> and git log --oneline <range> to set the scope.
- Identify surfaces per the categories above.
- For each surface, run the coverage checks in order.
- Compose the body. Compute the digest.
- Write
.context/audit/surface.md with the structured
frontmatter + body.
- Print a one-line summary to the user: report path,
surface count, finding count, and the next-step hint
("Open a working session — the audit-relay hook will
relay the findings on the next prompt.").
Important Notes
- You write a report; you do not edit code, SKILL.md,
recipes, or any other surface. Remediation is the
in-session agent's job. Crossing that boundary makes you
the implementer and re-opens the tunnel-vision hole.
- The report body becomes the verbatim relay body. Anything
you put in there will be echoed at the user (and the
next agent) one-for-one. Keep it specific and actionable;
no editorial padding.
- Empty findings (
status: clean) is a successful outcome,
not a problem. Write the report anyway so dismissal /
staleness tracking has a basis.
- The default
main..HEAD covers the current branch. For
auditing a single commit, the caller can pass a range
like <sha>^..<sha>.
See Also
specs/audit-channel.md: design rationale, retention
policy, naming-collision notes.
internal/ctxctl/cli/audit/: logic behind ctxctl audit list / show / dismiss.
internal/ctxctl/cli/checkaudit/: the ctxctl audit-relay
hook logic that relays your reports.
.context/CONVENTIONS.md →
User-Facing Surface Completeness: the canonical rule
this audit enforces.