/configure:surface
Scaffold and harden Surface — a deterministic
"documentation governed like code" gate. Surface anchors prose claims to code symbols, stores an
AST-normalized logic fingerprint per symbol, and blocks CI/commits when the fingerprint drifts
until a human re-runs surf verify. It ignores cosmetic edits and catches flipped operators,
relaxed comparisons, and dropped await.
⚠️ Experimental — adopt defensively. As of 2026-06 Surface is a young, single-maintainer project (no crates.io publish, bus-factor 1). The engine and release hygiene vetted well, but treat it as a pinned, optional gate — never an unpinned dependency. This skill defaults to SHA-pinned installs and fail-closed checksum verification.
When to Use This Skill
| Use this skill when... | Use another approach when... |
|---|---|
| Adding a deterministic doc↔code drift gate to CI/pre-commit | Enforcing same-commit doc discipline by convention (blueprint:blueprint-docs-currency) |
| You want specific prose claims pinned to specific functions | Detecting stale generated content (blueprint:blueprint-sync) |
| You want an offline, no-LLM gate that fails the build on logic drift | You want semantic "is the doc still true?" judgment (code-quality:code-review) |
| Hardening an existing Surface setup (pin by SHA, verify checksums) | Generating docs from code (documentation:docs-generate) |
Context
- surf.toml: !
find . -maxdepth 2 -name 'surf.toml' - Hubs dir: !
find . -maxdepth 2 -type d -name 'hubs' - Pre-commit config: !
find . -maxdepth 1 -name '.pre-commit-config.yaml' - Workflows: !
find . -path '*/.github/workflows/*' -maxdepth 3 -name '*.yml' - Language markers: !
find . -maxdepth 1 \( -name 'Cargo.toml' -o -name 'package.json' -o -name 'pyproject.toml' -o -name 'go.mod' \)
Parameters
Parse from $ARGUMENTS:
--check-only: Report Surface adoption status and pin hygiene; make no changes (CI mode).--fix: Apply scaffolding and hardening without prompting.--pin <tag>: Release tag to install/pin (default: latest stable; resolve its commit SHA before writing anyuses:ref).
Execution
Execute this Surface configuration workflow:
Step 1: Detect current state
From Context, classify the repo:
| Signal | Meaning |
|---|---|
surf.toml present |
Surface already initialised — go to hardening (Step 5) |
Hubs dir present, no surf.toml |
Partial setup — repair |
| Neither | Greenfield — full scaffold |
| Language marker | Surface supports Rust, TypeScript/JS (TSX grammar), Python, Go. Warn if none match — anchors only resolve in supported languages. |
If --check-only, report the table and the pin audit from Step 5, then stop.
Step 2: Confirm the maturity trade-off
Before writing files, surface the experimental posture (the blockquote above) and confirm with
AskUserQuestion unless --fix is set: adopt as a pinned optional gate (recommended) or skip.
Record the chosen pin tag.
Step 3: Resolve the pinned ref
Resolve the chosen tag to the commit SHA it points at so every uses: and rev: is
reproducible — a release tag can be re-pointed to a different commit after the fact, so the SHA the
tag resolved to (with the tag kept in a trailing comment) is the real immutable anchor:
git ls-remote https://github.com/Connorrmcd6/surface refs/tags/<tag>
Land the Action ref as Connorrmcd6/surface@<sha> # <tag> and the pre-commit rev: as <tag>
(github-tags datasource — Renovate manages both; see .claude/rules/version-pinning.md). Do not
hand-transcribe a SHA from memory.
Carry the same tag into the Action step's version: input (Step 5) — the ref pins the action,
not the binary it installs.
Step 4: Scaffold (greenfield)
- Create
surf.toml:hubs = ["hubs/*.md"] - Create
hubs/with one starter hub anchoring a real, stable symbol the team relies on. Hub shape:--- summary: One-line description of what this hub governs. anchors: - claim: > The prose claim about behaviour that must stay true. at: src/path/file.ts > symbolName hash: "" # surf verify seals this after you confirm the prose refs: [] --- # Title Longer explanation a reviewer reads when the gate flags drift. - Run
surf lint(every anchor resolves to exactly one symbol), thensurf verifyto seal hashes.
Step 5: Wire + harden the gates
Pre-commit — add to .pre-commit-config.yaml (requires surf on PATH; pair with
/configure:web-session to install it in Claude Code web sessions):
- repo: https://github.com/Connorrmcd6/surface
rev: v0.8.0 # --pin tag; Renovate-managed (github-tags)
hooks:
- id: surf-lint # anchors resolve
- id: surf-check # the gate — blocks on drift
GitHub Action — scaffold .github/workflows/ with a SHA-pinned ref and an explicit
version::
name: "Docs: Surface drift gate"
on: [pull_request]
jobs:
surface:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: Connorrmcd6/surface@091b937ae34ac81a02386604fed977dd24f1f0cf # v0.8.0
with:
version: v0.8.0 # pins the BINARY; the input defaults to floating `latest`
args: check
Two pins, not one. The
@<sha> # vX.Y.Zref pins the composite action and its bundledinstall.sh;version:pins the binary that installer downloads. Omit it andaction.yml's own default (latest) resolvesreleases/latestover the API on every run — a new upstream release then changes gate behaviour with no local change, landing as a red merge gate nobody can attribute to an edit. Checksum verification does not close this: it proves the download matches its own published hash, not that it is the version you pinned. Keep the two values equal; Renovate bumps the ref, so updateversion:to match in the same PR.The historical installer-pin gap (
action.ymlpipinginstall.shfrom mutablemain) is fixed and shipped — v0.8.0 runssh "${{ github.action_path }}/install.sh". Pinning v0.6.2 or earlier still carries that gap; vendorinstall.shat that ref if you must stay there.
Step 6: Document the JSON → reviewer handoff
Surface keeps semantic judgment out of its deterministic core and emits JSON for reviewer plugins
(surf check --format json). Note in the repo (e.g. CONTRIBUTING or the workflow) that a drift
verdict can be handed to code-quality:code-review / verify to judge whether the claim is still
true before a human runs surf verify. That is the division of labour Surface is designed for and
where our skills add the most value.
Step 7: Report
Print: scaffold actions taken, the resolved pin (<sha> # <tag>), the version: input value, the
pre-commit + Action wiring status, and the hardening checklist below with each item ✓/✗.
Hardening checklist
| Control | Target state |
|---|---|
| Action ref | SHA-pinned with # <tag> comment, not a floating major |
| Binary version | Pinned via version: <tag> in with:, not left at the floating latest default |
| Installer | Checksum-verified (default) or vendored at the pinned ref |
| Pin freshness | rev: / uses: Renovate-visible (github-tags shape) |
| Gate scope | surf check --base <ref> to diff-scope to changed files in CI |
| Fallback | macOS Intel / Windows unsupported — document cargo install --git source fallback |
Agentic Optimizations
| Context | Command |
|---|---|
| Status + pin audit | /configure:surface --check-only |
| Scaffold + harden | /configure:surface --fix --pin v0.8.0 |
| The gate (CI) | surf check |
| Scope to changed files | surf check --base origin/main |
| Machine-readable verdict | surf check --format json |
| Re-seal after human review | surf verify |
| Anchors resolve | surf lint |
Flags
| Flag | Description |
|---|---|
--check-only |
Report adoption + pin hygiene without modifying files |
--fix |
Apply scaffolding and hardening without prompting |
--pin <tag> |
Release tag to install/pin (resolved to a SHA before writing refs) |
Upstream contributions
- Installer pin — reported, merged, shipped:
action.ymlnow runs the bundled${{ github.action_path }}/install.sh, so a SHA-pinneduses:also pins the installer. Released; the caveat in Step 5 applies only to v0.6.2 and earlier. - Floating
version:default — reported, open (Connorrmcd6/surface#169): proposes the default itself stop beinglatest, so the SHA pin becomes transitive. Independent of the fix here — setversion:explicitly regardless, since anyone pinning an older release needs it.
See Also
/configure:web-session— installsurfin Claude Code web sessions/configure:pre-commit— pre-commit framework setup this plugs intoblueprint:blueprint-docs-currency— same-commit doc discipline (the convention-level complement)blueprint:blueprint-sync— drift detection for generated contentcode-quality:code-review— the semantic reviewer for Surface's JSON verdicts- Surface docs: https://surface.gradientdev.xyz/ · License: Apache-2.0