Track documentation freshness against source code.
Documentation sites go stale when source code changes. docfresh maintains a machine-readable manifest that maps each documentation page to its source-of-truth files, then uses git history to detect when sources have changed since the docs were last verified.
cargo install --path .cd your-docs-site
docfresh init --source-repo ../your-source-repo
docfresh suggest --apply 0.6
docfresh verify --all
docfresh auditinit auto-detects your site framework and source language. suggest cross-references source files against page content to populate the manifest. verify marks pages as current. audit tells you what's gone stale.
Bootstrap a site-manifest.json by scanning your site for pages.
docfresh init --source-repo ../api-serverAuto-detects the site framework from project files (Astro, Next.js, Hugo, Docusaurus, MkDocs, VitePress, Jekyll, mdBook, Sphinx) and the source language (Rust, Go, Python, TypeScript, JavaScript, Java, C#, Ruby, PHP, C++). Override with --site <preset> and --lang <preset>.
docfresh init --list-presets # see all available presets
docfresh init --site hugo --source-repo ../backendScan unmapped source files and recommend which pages they belong to.
docfresh suggest # show all suggestions
docfresh suggest --file src/auth.rs # suggest for one file
docfresh suggest --apply 0.6 # auto-apply above 60% confidence
docfresh suggest --json # machine-readable outputUses three-tier scoring: literal path references in page content, file stem matching, and term overlap from public API symbols and doc comments. Extracts pub fn/pub struct from Rust, exported names from Go, export function from TypeScript, class/def from Python, and so on.
Add a source mapping to a page.
docfresh map /docs/auth src/auth/handler.rs
docfresh map /docs/auth src/auth/middleware.rs --sections "authenticate" "authorize"Check all pages for staleness. Compares each page's verified_at SHA against current source repo HEAD.
docfresh audit # colored terminal output
docfresh audit --tag reference # filter by tag
docfresh audit --json # machine-readable for CIExit code 0 = all current, 1 = stale pages found. Reports which source files changed, the commit log since verification, and transitive warnings for related pages.
Mark pages as verified at the current source HEAD.
docfresh verify /docs/auth # verify one page
docfresh verify --all # verify everything
docfresh verify /docs/auth --sha abc123 # pin to specific SHAShow what changed in a page's sources since it was last verified.
docfresh diff /docs/authShow the status of all pages or a specific page.
docfresh status # summary table
docfresh status /docs/auth # detailed view
docfresh status --json # machine-readable
docfresh status --markdown # for pasting into issuesCompare documented source files against all tracked files in the source repo.
docfresh coverage # text report
docfresh coverage --json # machine-readable
docfresh coverage --scan "tests/**/*.rs" # add extra scan patternsReports undocumented files, orphan pages, and shared sources.
Combined audit + coverage in one output.
docfresh report # text
docfresh report --format markdown # for CI summaries
docfresh report --format json # machine-readablesite-manifest.json lives in the doc site repo root:
{
"version": 1,
"source_repo": {
"path": "../api-server",
"default_branch": "main"
},
"exclude_patterns": [
"src/internal/**",
"src/**/mod.rs"
],
"pages": [
{
"route": "/docs/auth",
"file": "src/pages/docs/auth.astro",
"title": "Authentication",
"tags": ["reference", "security"],
"sources": [
{ "path": "src/auth/handler.rs", "sections": ["authenticate"] },
{ "path": "docs/spec/auth.md" }
],
"related": ["/docs/permissions", "/features/sso"],
"verified_at": {
"sha": "a1b2c3d",
"timestamp": "2025-01-15T10:30:00Z"
},
"status": "current"
}
]
}| Status | Meaning |
|---|---|
current |
Verified, no source changes since |
stale |
Source files changed since verified_at |
unverified |
Never been verified |
outdated |
Manually marked as needing rewrite |
missing |
Planned page, no file yet |
- sources — files in the source repo this page documents.
sectionsis an optional human-readable marker for what part of the file matters. - related — other page routes that reference the same concepts. When a page goes stale, its related pages get a "review recommended" warning.
- exclude_patterns — glob patterns for source files to ignore in
coverageandsuggest. - tags — arbitrary labels for filtering (
docfresh audit --tag reference).
Create .docfresh.toml in your doc site repo to set policy defaults:
[source]
# Extra scan patterns beyond the language preset defaults
scan = ["tests/**/*.rs", "benches/**/*.rs"]
# Exclude internal files from coverage and suggest
exclude = ["src/**/mod.rs", "src/internal/**", "docs/spec/archive/*"]
[ci]
# Maximum stale pages before audit fails (0 = any stale page fails)
max_stale = 0
# Minimum documentation coverage percentage (0 = disabled)
min_coverage = 20
# Fail if any source file is unmapped and not excluded
fail_on_unmapped = true
# Output format for CI: "text", "markdown", "json"
format = "markdown"All settings have CLI flag overrides (--max-stale, --min-coverage, --fail-on-unmapped).
One command for CI pipelines. Runs audit + coverage with threshold enforcement:
docfresh ci # uses .docfresh.toml settings
docfresh ci --max-stale 5 # override: allow up to 5 stale pages
docfresh ci --fail-on-unmapped true # override: fail on unmapped files
docfresh ci --format json # override: JSON outputExit code 0 = all checks passed, 1 = threshold violation.
# .github/workflows/doc-freshness.yml
name: doc-freshness
on:
push:
branches: [main]
schedule:
- cron: '0 9 * * 1'
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: your-org/api-server
path: api-server
- run: cargo install docfresh
- run: docfresh ci
env:
DOCFRESH_SOURCE_REPO: ./api-server
- run: docfresh report --format markdown >> $GITHUB_STEP_SUMMARYWhen a developer adds a new source file, CI can catch it:
# .docfresh.toml
[source]
exclude = ["src/**/mod.rs", "src/util/**"]
[ci]
fail_on_unmapped = true
max_stale = 3 # allow some staleness during active sprintsThe developer either:
- Runs
docfresh map /docs/auth src/auth/new_handler.rsto map it - Adds the file to
excludepatterns if it's internal - Or CI fails with a clear message listing the unmapped files
| Framework | Detected by | Page patterns |
|---|---|---|
| Astro | astro.config.* |
src/pages/**/*.astro |
| Next.js (App Router) | next.config.* + app/ dir |
app/**/page.tsx |
| Next.js (Pages Router) | next.config.* + pages/ dir |
pages/**/*.tsx |
| Hugo | hugo.toml |
content/**/*.md |
| Docusaurus | docusaurus.config.* |
docs/**/*.md |
| MkDocs | mkdocs.yml |
docs/**/*.md |
| VitePress | .vitepress/ dir |
docs/**/*.md |
| Jekyll | _config.yml |
_posts/**/*.md |
| mdBook | book.toml |
src/**/*.md |
| Sphinx | conf.py |
**/*.rst |
| Markdown | fallback | docs/**/*.md |
| Language | Detected by | Public API extraction |
|---|---|---|
| Rust | Cargo.toml |
pub fn/struct/enum/trait, /// docs |
| Go | go.mod |
Exported names (uppercase), // docs |
| Python | pyproject.toml |
def, class, docstrings |
| TypeScript | tsconfig.json |
export function/class/interface/const |
| JavaScript | package.json |
export function/class/const |
| Java | pom.xml / build.gradle |
public class/interface/enum |
| C# | *.csproj / *.sln |
public class/interface, /// XML docs |
| Ruby | Gemfile |
def, class, module |
| PHP | composer.json |
public function, class/interface/trait |
| C++ | CMakeLists.txt |
class/struct/namespace, Doxygen |
MIT OR Apache-2.0