surface
deterministic context gate · engineers + agents

Your codebase changes daily. Your context shouldn’t decay with it.

Stale docs mislead the next engineer — and every agent, on every run. Surface anchors prose to the code it describes and fails the build when that logic changes, so the context everyone reasons from stays true.

no model · no network · no API key in the core

01 the cell nothing owns

A test asserts behavior. Surface asserts prose.

Your tests are green. Your docs can still be stale. The two drift apart the moment someone updates one and forgets the other — and the code that works fine but no longer matches its description is the cell nothing else catches.

Surface owns that cell.

02 how it works, in one breath

Anchor a sentence to the code it’s about. The gate seals its logic.

anchor — a hub, next to the code
# auth/_hub.md
anchors:
  - claim: refresh rotation is single-use;
           reuse triggers global logout
    at: src/auth/refresh.ts > rotateRefreshToken
    hash: 9b1c33a
gate — when the logic moves
$ surf check
DIVERGED  hubs/auth.md
  at  src/auth/refresh.ts > rotateRefreshToken
  stored 9b1c33ade8f1 -> now 4d5e6f2a0b7c
  magnitude: Small
surf check: 1 divergence(s).
  1. 01 Locate. tree-sitter resolves the at: path to an exact node span.
  2. 02 Canonicalize. the syntax tree, not the text — comments & renames drop out.
  3. 03 Hash. SHA-256, truncated. A list anchor is stale if any site changes.
  4. 04 Compare. against the sealed hash. Equal passes; different blocks the merge.
03 quiet on cosmetics, loud on logic
silent — no false alarm
  • - const userId = user.id
    + const uid = user.id

    rename a local · stays silent

  • - sum(a,b,c)
    + sum(a, b, c)

    reformat · stays silent

  • - return base + tax
    + return base + tax // incl. tax

    add a comment · stays silent

fires — the logic moved
  • - return base + tax
    + return base - tax

    flip + to − · fires

  • - if (i < limit)
    + if (i <= limit)

    < to <= · fires

  • - await save(user)
    + save(user)

    drop an await · fires

A tamper-evident seal on the logic of exactly the code your docs claim to describe.

04 is surface for you?

complexity × velocity × (humans + agents)

Honestly? Maybe not. A small, slow, simple codebase doesn’t need this — two well-kept markdown files beat the whole apparatus. Use Surface where rebuilding the mental model from source is expensive and the code moves fast enough to drift.

One multiplier pushes it toward yes: agents. A human onboards once and amortizes over months. An agent re-onboards every session and amortizes nothing — so accurate context isn’t a nicety, it’s the performance budget.

05 start in three lines
surf init      # writes surf.toml, creates hubs/
surf new auth  # scaffold a hub, anchor a claim
surf check     # the gate — block the merge on drift

Govern your context like you govern your code.

Seal a claim once and the gate holds it — no model, no network, nothing to babysit. The drift surfaces in CI before it reaches a reader.