DocSentinel
DocSentinel is a deterministic-first documentation quality assurance and static analysis framework for Markdown repositories and Python docstrings. It validates document integrity, cross-references, text quality, and docstring synchronization without sending sensitive document content across networks.
All three initial milestones are complete, providing a fully working command-line tool and Python library:
fastdefault profile: Sub-second structural and reference checks; all 16 rules use only the Python standard library at scan time. Note:pyproject.tomllistsspacyas a core runtime dependency (so every installation includes spaCy), butimport docsentinelno longer imports spaCy at module load and fast and standard profile scans never call any spaCy API. Whether to remove spaCy from the core dependencies is an open product decision; it does not affect scan correctness or the fast-profile runtime guarantee.DS101dangling links/anchorsDS102stray HTML commentsDS103unresolvable path-like code spansDS104conflicting heading and explicit anchorsDS105heading hierarchy and section levelsDS106empty or contentless sectionsDS108reference-style link definition integrity (undefined or duplicated reference labels)DS109malformed or unclosed fenced code blocksDS110missing language labels on code fences (opt-in; off unlessrequire_fence_languagesis enabled)DS112declared documentation navigation integrity: within the Markdown indexes named bynavigation_indexes, a navigation target linked more than once (navigation_unique_targets), a navigation link whose local destination does not exist (navigation_check_missing), a target that escapes the scan root, and anavigation_requireddocument that no navigation link points at (warning severity; opt-in, off unlessnavigation_indexesis set). A missing or unreadable configured index is a fail-closed readiness error (exit 2)DS113missing local media and document assets: Markdown images, HTML<img>/<source>src/srcset, HTML<a href>, and used reference-definition targets whose local file does not exist as a regular file inside the scan root (error severity). Images are checked regardless of extension;asset_extensionsgates link-shaped references, thecheck_*toggles enable each reference kind, andmissing_asset_policy(off/warn/error) downgrades or silences it. External URLs,data:URIs, templates, and root escapes (DS116's concern) are skippedDS114duplicate stable document identifiers: two documents that declare the same stable frontmatter identity withindocument_id_scope(corpus/directory), reading only the configureddocument_id_field(defaultid); values are normalized to Unicode NFC with whitespace collapsed, and case-folded whendocument_id_case_sensitiveis false, whiledocument_id_requiredadditionally flags each document lacking an identity (error severity). Malformed metadata (an unterminated block or duplicate id key) is left to metadata validation and stays silent, but an unsupported value shape of the configured field yields one explicit findingDS115deprecated names and migrated references: in-scope textual occurrences of names explicitly mapped as deprecated in the TOML mapping named bydeprecated_references_file, with the suggested replacement and the mapping provenance (warning severity; opt-in, off unlessdeprecated_references_fileis set).proseandidentifiermatches (over prose and inline code) are gated bydeprecated_check_prose,linkmatches (over local link targets, lexical only — existence stays DS101's concern) bydeprecated_check_links, anddeprecated_case_sensitivegoverns case; fenced code and an explicitscopeexemption keep historical examples clean. A missing, out-of-root, or schema-invalid mapping (including a conflicting duplicate entry) is a fail-closed readiness error (exit 2)DS116references that escape the documentation root, such as parent-directory traversal, percent-encoded escapes, and Windows drive, UNC, or backslash paths (error severity). Links, images, reference definitions, and HTMLhref/src/srcsetare checked at full strictness; inline code spans are documentation, so there DS116 reports only genuine traversal (a root escape or an in-root symlink pointing outside), leaving drive, UNC, backslash, and regex or escape snippets to DS103DS117malformed GFM pipe-table structureDS118documentation file and directory naming policy: discovered document paths whose components do not match the portable-ASCII style named bydocumentation_naming(kebab/snake), with a deterministic suggested rename (warning severity; opt-in, off unlessdocumentation_namingselects a style).documentation_naming_allow(defaultREADME.md/index.md) anddocumentation_naming_prefix_patterns(numeric ADR prefixes and similar) exempt conventional names, anddocumentation_naming_directoriesscopes whether directory components are checked. It is a pure path-string policy: it reads no document content, touches no filesystem, and never renames a file
standardprofile: Corpus-level statistics and docstring synchronization viadocsentinel[standard]DS201prose readability complexityDS202paragraph duplicationDS203low-information contentDS204Python docstring-to-code signature mismatch)
deepprofile: Semantic NLP contradiction candidate analysis viadocsentinel[deep]. Gated by explicit opt-in confirmation with advisory-only exit codes.DS301fact-contradiction candidates across documents
Requirements and Installation
Requires Python 3.12+ and uv (or standard pip).
# Core installation (fast profile)
pip install docsentinel
# or with uv
uv add docsentinel
# Standard profile (corpus stats & docstrings)
pip install "docsentinel[standard]"
# or with uv
uv add --extra standard docsentinel
# Deep profile (semantic contradiction detection)
pip install "docsentinel[deep]"
python -m spacy download en_core_web_sm
Command-Line Usage
# Initialize starter doc_sentinel.toml configuration
uv run docsentinel init
# Run deterministic fast-profile scan on the current repository
uv run docsentinel scan
# Scan specific directories or files
uv run docsentinel scan docs/
uv run docsentinel scan docs/README.md
# Scan with standard or deep profile
uv run docsentinel scan --profile standard
uv run docsentinel scan --profile deep --i-understand-deep-is-heuristic
# Output formats: text (default), json, or github annotations
uv run docsentinel scan --format json
uv run docsentinel scan --format github
# Strict mode: fail on warnings as well as errors
uv run docsentinel scan --strict
# Baseline legacy findings to prevent build regressions
uv run docsentinel baseline . --output .docsentinel-baseline.json
uv run docsentinel scan --baseline .docsentinel-baseline.json
# Inspect active detection rules and diagnostic environment readiness
uv run docsentinel rules
uv run docsentinel doctor
Exit Codes Contract
0— Scan completed with no blocking findings (or advisory-only deep candidates).1— Scan found blocking errors (or warnings when--strictis enabled).2— Configuration error, invalid arguments, or filesystem scan failure.
Configuration
DocSentinel loads configuration from doc_sentinel.toml at the scan root, or from the [tool.doc_sentinel] table in pyproject.toml:
# doc_sentinel.toml: keys at the top level, no table header.
# In pyproject.toml put the same keys under a [tool.doc_sentinel] table instead.
profile = "fast"
include = ["*.md", "**/*.md"]
exclude = [".git", ".venv", "node_modules", "dist"]
select = []
ignore = []
baseline = ".docsentinel-baseline.json"
# Standard profile thresholds (optional)
max_grade_level = 14.0 # DS201: flag prose above this readability grade
duplicate_similarity = 0.85 # DS202: flag paragraph pairs at/above this cosine similarity
min_information_score = 0.15 # DS203: flag paragraphs scoring below this information score
docsig_paths = ["src"] # DS204: Python source roots checked against docstrings
# Standard profile statistical size limits (optional)
min_document_words = 50 # DS201: skip documents with fewer prose words
min_paragraph_words = 5 # DS202/DS203: skip paragraphs with fewer words
min_paragraph_chars = 30 # DS202/DS203: skip paragraphs shorter than this
# Deep profile opt-in confirmation (optional)
deep_confirm = false
Patterns match relative paths; exclude patterns also match directory names. Symlinked files are skipped for safety. Output order and document inventory are stable and deterministic.
Python Library
The CLI and Python API share the same engine and frozen data models:
from pathlib import Path
from docsentinel import Config, load_config, scan
# Quick scan with default settings
result = scan(".")
print(f"Profile: {result.profile}")
print(f"Documents scanned: {len(result.documents)}")
print(f"Findings: {len(result.findings)}")
for finding in result.findings:
print(f"[{finding.severity.upper()}] {finding.rule} in {finding.path}:{finding.line} - {finding.message}")
# Programmatic scan with explicit configuration
config = Config(
profile="standard",
select=("DS201", "DS204"),
docsig_paths=("src",),
)
result = scan(".", config=config)
Pytest Integration
DocSentinel includes an opt-in pytest plugin exposing the docsentinel_scan fixture:
uv run pytest -p docsentinel.pytest_plugin
def test_documentation_integrity(docsentinel_scan):
result = docsentinel_scan(".")
assert not [f for f in result.findings if f.severity == "error"]
Pre-commit Integration
DocSentinel provides pre-commit hooks in .pre-commit-hooks.yaml:
docsentinel-fast: Runs fast structural checks on every commit (fast rules use stdlib only at run time;pyproject.tomllistsspacyas a core dependency but spaCy is not imported during fast or standard scans — see the dependency note in the tutorial).docsentinel-standard: Manual on-demand hook for standard corpus and signature analysis.
Documentation and Resources
- User Tutorial — Comprehensive guide for CLI and Python library consumers.
- Statistical Checks Reference — Full reference for the six standard-profile threshold keys (DS201–DS203).
- Configuration Reference — All fast-profile policy options for DS104–DS118, with defaults and valid values.
- Architecture — Architectural design, profile boundaries, and data contracts.
- Markdown Scanner Guide — Developer guide for adding rules, resolver ownership, and the security checklist.
- Roadmap — Detailed milestone, story, and task specifications.
- Contributing — Development guidelines and validation commands.
Metadata
Release files for docsentinel 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| docsentinel-1.0.0.tar.gz | 1.3 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| docsentinel-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.5 MB
Release files / docsentinel-1.0.0.tar.gz
| Download URL | docsentinel-1.0.0.tar.gz |
|---|---|
| Size | 1.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
77f9fd05cb3f4d2caaee65a6cb58b6879c73755e4a3c82628008071a93ea042b
|
|
BLAKE2b-256 checksum How to use checksums |
912f8375c8f40efe2e082ae9dc438dfcbf6d9272a76afbe1a28b4be0f4018bea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / docsentinel-1.0.0-py3-none-any.whl
| Download URL | docsentinel-1.0.0-py3-none-any.whl |
|---|---|
| Size | 167.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
14678df574973c02ee0af00dfc01f3726395ae4b115efaadfa8adecd1f15ad58
|
|
BLAKE2b-256 checksum How to use checksums |
68866a8802c9bc41e471c6a247a81ae1a09727d28723ca788279054eafa21dc2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Security for docsentinel 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.