Skip to main content

surf

Extract one section of a markdown, TeX, or PDF file by its heading. The rest of the file never loads.

uv tool install surf-cli
cd plugins/surf/skills/surf/references

A file with no heading named returns the map, frontmatter and then headings, and none of the body:

$ surf about.md
---
metadata:
  author:
    name: Alexander R. Saint Croix
    github_username: saintx
    email: alex@saintx.us
    twitter: alexsaintx
  surf-version: "0.7.0"
---

- Surf — About
  - Overview
  - When to use

A heading returns that section and stops at the next heading of the same or higher level:

$ surf about.md "When to use"
## When to use

Invoke when skimming markdown, TeX, or PDF files, checking what a file contains,
listing structure, extracting a named address, or batch-scanning metadata across
a directory. See `surf --help` for CLI flags. Skip when the full body is already
needed. ...

The same two commands work on TeX, addressed by sectioning commands and the abstract environment, and on PDF, addressed by outline bookmarks. The whitepaper in this directory ships in both forms and lists the same tree from either:

$ surf surf.tex --list
- abstract
- Background
- A Thin Index Shaped by Intent
- Agentic Context Composition
- Skills You Can Check
- Indexes over Indexes
- Markdown, TeX, and PDF
- This Paper

$ surf surf.pdf "Skills You Can Check"

surf exists so that agent skills can be thin. The SKILL.md beside these files is a table of intents, each resolving to surf path "Heading", over reference material the agent never reads whole. surf.pdf explains why the tool was built and what that pattern makes possible.

Addressing

surf --list file.md is the heading tree without YAML. surf -f file.md is YAML only. Nested paths (Overview#Usage) select a child when the same name appears under different parents.

A heading is an address: ATX display text on markdown, brace title on TeX, the TeX abstract environment (addressed as abstract), or an outline bookmark title on PDF. On markdown and TeX the return value is that section through the next heading of the same or higher level. On PDF it is dest-to-next-dest page text; when the next dest is on the same page, that dest page is included.

--level is 1 at the top of the heading tree. On markdown that is #. On TeX it is the shallowest command in the file, so --level 1 is \section in an article. On PDF it is the outline's native rank. Listing with --level N includes ranks 1 through N. Named extract uses N as an exact match.

TeX \input and \include of .tex files are expanded relative to the file you name. Graphics, comments, shell pipes, and macro-constructed paths are not.

If the file has no headings, or a PDF has no outline, surf prints that it has no structural index, with line and byte counts on markdown and TeX, or page and byte counts on PDF. It does not dump the body.

Python 3.12+. pypdf is the runtime dependency for PDF outline addressing.

Agent skill

plugins/surf packages the skill for agents. It carries a Claude Code manifest, an Agent Plugins 1.0.0 manifest, and the skill itself at plugins/surf/skills/surf, in the Agent Skills format that Claude Code, Codex, Gemini CLI, Cursor, and Grok Build read.

Claude Code installs it from the marketplace in this repo:

claude plugin marketplace add saintx/surf-cli
claude plugin install surf@surf-cli

Any harness that reads a skills directory takes a copy of the skill:

cp -R plugins/surf/skills/surf ~/.agents/skills/surf

The repo also carries .agents/skills/surf, .claude/skills/surf, and .grok/skills/surf as symlinks into the plugin, so an agent working in this checkout has the skill available.

Install

The distribution name is surf-cli. The command is surf. Python 3.12+.

uv tool install surf-cli
surf --version
pipx install surf-cli
surf --version
pip install surf-cli

Nix

From a local clone, install the flake into the nix profile:

nix profile install "git+file://${PWD}"
surf --version

Pin a tagged release with ?ref=X.Y.Z. If surf is already in the profile under a different flake URL, remove it first:

nix profile remove surf
nix profile install "git+file://${PWD}?ref=X.Y.Z"

scripts/deploy.sh syncs, tests, and retargets the profile at the latest local semver tag.

Releasing

Version locations, the bump checklist, tagging, and nix profile deployment are in RELEASING.md.

Development

nix develop

Tests

scripts/test.sh    # uv run pytest src/surf

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

surf_cli-0.7.0.tar.gz (329.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

surf_cli-0.7.0-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

Details for the file surf_cli-0.7.0.tar.gz.

File metadata

  • Download URL: surf_cli-0.7.0.tar.gz
  • Upload date:
  • Size: 329.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for surf_cli-0.7.0.tar.gz
Algorithm Hash digest
SHA256 1fc5e0473cd7c26ddf855d960e24fef30d471761553c8808982cd70daa4e49f8
MD5 f4423274ea47c83b43b68d32a9ed03e4
BLAKE2b-256 09f0e5a57d7c41684441cf2111b08571856696d792478a2c4edffe740d4ace46

See more details on using hashes here.

Provenance

The following attestation bundles were made for surf_cli-0.7.0.tar.gz:

Publisher: publish.yml on saintx/surf-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file surf_cli-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: surf_cli-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 15.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for surf_cli-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b581277b3cc890580b9fcbc877b6c79e046358941b2665b5614c6dba46a7013f
MD5 4673900d8fb19a0fb6bf0219333ebf50
BLAKE2b-256 23e6d0ca87a291c55c55db26486522f5bf8c2aae1cf75817f2f8f8ea58fffe2b

See more details on using hashes here.

Provenance

The following attestation bundles were made for surf_cli-0.7.0-py3-none-any.whl:

Publisher: publish.yml on saintx/surf-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page