Gnosis
Website → clean, provenance-stamped Markdown.
Built for LLM knowledge bases, documentation pipelines, and audit-ready content archives.
Point gnosis at a URL and get clean, LLM-friendly Markdown files with a YAML provenance frontmatter block on every file — recording exactly where the content came from, when it was fetched, and how to verify it. No external bookkeeping, no hidden state. Every file is self-describing.
Table of contents
- Features
- Installation
- Quick start
- Provenance: the contract
- Authenticated fetching
- CLI reference
- Configuration reference
- Exit codes
- How clean is the output?
- Development & testing
- License
Features
| Feature | Description |
|---|---|
| Single page or full site | One URL, or crawl every page under a path with --all |
| Provenance frontmatter | Every file records url, fetched_at (UTC), SHA-256 content_hash, status_code, page metadata (title/author/language), and caching headers when the server sends them |
| Authentication built-in | Bearer tokens, HTTP Basic (Confluence Cloud API tokens), or arbitrary headers — secrets always from environment variables |
| Clean extraction | Main-content detection with ordered selectors, class-word boilerplate stripping (sidebars, breadcrumbs, cookie banners, permalink anchors), and framework-aware fixes for Confluence, Sphinx/RTD, and GitHub-style pages |
| Valid GFM tables | Multi-paragraph cells joined with <br>, pipes escaped, sticky-header clone tables removed — tables survive ingestion |
| Scalable crawling | Configurable concurrent fetches, politeness delay, retries with backoff, robots-aware |
| Scheduler-friendly | Headless CLI, meaningful exit codes, JSON crawl manifest — drops into cron, n8n, Airflow, CI |
| Metadata extraction | Title (entity-unescaped), author, language, description, Open Graph fields |
| Optional QMD integration | Index output into a QMD knowledge base with local-LLM context generation (pip install gnosis[qmd]) |
Installation
Requires Python 3.12+.
git clone https://github.com/SHCV-it/gnosis.git
cd gnosis
python -m venv venv && source venv/bin/activate
pip install -e .
Optional, only if you use --qmd-index (pulls torch + transformers):
pip install -e .[qmd]
Quick start
# One page → one markdown file with provenance
gnosis https://docs.python.org/3/tutorial/
# Crawl an entire section of a docs site
gnosis https://docs.python.org/3/tutorial/ --all -o ./python-docs/
# Preview how many pages would be crawled (no downloads)
gnosis https://docs.python.org/3/tutorial/ --all --dry-run
# Faster crawl with parallel fetches
gnosis https://docs.example.com/ --all --config myconfig.yaml
Provenance: the contract
Every file gnosis writes is self-describing. Default frontmatter:
---
title: Quickstart — Trafilatura 2.2.0 documentation
url: https://trafilatura.readthedocs.io/en/latest/quickstart.html
fetched_at: '2026-08-04T10:24:17Z'
content_hash: 1549512c...16fd
status_code: 200
generator: gnosis/1.1.0
language: en
etag: '"61e917f4cd107c3bce6182b633819fcf"'
last_modified: Fri, 31 Jul 2026 16:07:37 GMT
---
| Field | Required | Description |
|---|---|---|
title |
Always | Page title (from og:title or <title>, HTML entities unescaped) |
url |
Always | Final URL after redirects (requested_url added if it differs) |
fetched_at |
Always | UTC fetch timestamp, ISO 8601 |
content_hash |
Always | SHA-256 of the markdown body — use for dedup/change detection |
status_code |
Always | HTTP status of the final response |
generator |
Always | Gnosis version that produced this file |
language |
If present | From <html lang> or og:locale |
author |
If present | From <meta name=author>, article:author, or dc.creator |
description |
If present | From <meta name=description> or og:description |
site_name |
If present | From og:site_name |
published_time |
If present | From article:published_time |
modified_time |
If present | From article:modified_time |
etag |
If sent | Response ETag header |
last_modified |
If sent | Response Last-Modified header |
requested_url |
If redirected | Original URL before redirects |
Add your own constant fields per run (--frontmatter) or per config
(output.frontmatter_extra) — custom keys never override the core provenance
fields above:
gnosis https://example.com/docs --frontmatter 'tags: [customs, passar]' --frontmatter 'owner: kb-team'
The frontmatter is standard YAML between --- fences: parseable by
python-frontmatter, Jekyll, Hugo, Obsidian, and any downstream knowledge
pipeline.
Opt out per run with --no-frontmatter or globally in config:
output:
frontmatter: false
Authenticated fetching
Secrets are read from environment variables only. They are never passed as plain CLI arguments (which leak into shell history and process tables) and never committed in config files.
Confluence Cloud with a Personal Access Token
# Set up a PAT at https://id.atlassian.com/manage/api-tokens
export CONFLUENCE_PAT="your-api-token"
gnosis "https://your-domain.atlassian.net/wiki/spaces/SPACE/pages/PAGE_ID" \
--basic-user you@example.com \
--basic-token-env CONFLUENCE_PAT
Bearer token (authenticated API docs, internal tools)
export MY_API_TOKEN="..."
gnosis https://internal.example.com/docs --bearer-token-env MY_API_TOKEN
Custom headers
gnosis https://example.com --header "X-API-Key: ${MY_KEY}" --header "X-Team: docs"
Via config file (multi-run / CI)
downloader:
auth:
type: basic # bearer | basic | header
username: "you@example.com"
password: "${CONFLUENCE_PAT}" # ${ENV_VAR} expanded at load time
CLI reference
gnosis URL [OPTIONS]
| Flag | Description |
|---|---|
-a, --all |
Crawl all child pages under the URL path |
-n, --dry-run |
Discover and count pages only (requires --all) |
-o, --output DIR |
Output directory (default: ./) |
-c, --config FILE |
Path to YAML configuration file |
-f, --overwrite |
Overwrite existing output files |
-q, --quiet |
Suppress progress output |
-v, --verbose |
Show detailed conversion diagnostics |
--no-frontmatter |
Write bare markdown without provenance block |
--frontmatter KEY: VALUE |
Extra constant frontmatter field (repeatable) |
--header NAME: VALUE |
Extra request header, ${ENV_VAR} expanded (repeatable) |
--bearer-token-env VAR |
Bearer token from environment variable |
--basic-user USER |
HTTP Basic username (requires --basic-token-env) |
--basic-token-env VAR |
HTTP Basic password/token from environment variable |
--qmd-index |
Index output into QMD (requires [qmd] extra) |
Configuration reference
Copy config/default.yaml and pass it with -c.
Full reference:
# ── Downloader ────────────────────────────
downloader:
timeout: 30 # Request timeout (seconds)
retries: 3 # Retries on 5xx / network errors
user_agent: "Gnosis/1.1" # User-Agent header
rate_limit_ms: 500 # Minimum delay between requests (0 = no limit)
respect_robots: true # Obey robots.txt (future)
headers: {} # Extra HTTP headers (${ENV_VAR} expanded)
auth: # Optional: bearer | basic | header
type: bearer
token: "${MY_API_TOKEN}"
# ── Crawler ───────────────────────────────
crawler:
max_depth: 10 # Crawl depth from seed URL
max_pages: 500 # Stop after this many pages
concurrent_requests: 5 # Parallel fetch batch size (1 = sequential)
# ── Converter ─────────────────────────────
converter:
excluded_tags: [...] # HTML tags stripped before conversion
content_selectors: [...] # Tried in order; first match ≥ 200 chars wins
strip_classes: [...] # Exact class-token matches to remove
strip_class_words: [...] # Word-level matches inside class names
include_images: true # Emit <img> as 
absolute_urls: true # Resolve relative links to absolute URLs
# ── Output ─────────────────────────────────
output:
directory: "./" # Where .md files go
overwrite: false # Skip existing files unless true
extension: ".md" # Output file extension
frontmatter: true # Write YAML provenance block
frontmatter_extra: {} # Constant fields added to every file
# ── QMD (optional) ──────────────────────────
qmd:
enabled: false # Enable QMD knowledge base indexing
llm_model: "Qwen/Qwen3-0.6B" # HuggingFace model for context generation
llm_device: "cpu" # cpu | cuda | auto
Exit codes
| Code | Meaning |
|---|---|
0 |
Success (crawl mode: at least one page saved) |
1 |
Failure — download error, file exists without -f, nothing saved, bad flags |
130 |
Interrupted (Ctrl-C) |
In --all mode a _manifest.json is written to the output directory listing
every page with url, file, content_hash, fetched_at, status_code, and
title — ready for schedulers and downstream audit.
How clean is the output?
Gnosis is opinionated about boilerplate. By default it:
- strips script/style/nav/footer/aside/form/template tags and HTML comments
(including Confluence's
<!-- data-loadable-begin=... -->SSR markers) - removes elements matching exact
strip_classestokens AND boilerplate words (sidebar,toc,breadcrumb,cookie,headerlink,sourcelink, …) inside namespaced class names —bd-sidebar-primaryis gone, butresearch-contentstays - cleans permalink anchors from headings (
# Quickstart#→# Quickstart) - picks the main content by precedence-ordered selectors
(
.markdown-body,.ak-renderer-document,.wiki-content, … beforemain/#content) - converts tables to valid GFM: multi-line cells joined with
<br>,|escaped, duplicate/sticky-header rows removed - resolves relative links to absolute URLs; skips
data:-URI images (spacers/tracking pixels) - unescapes HTML entities in titles (
—→—)
Everything is configurable — see config/default.yaml.
Development & testing
git clone https://github.com/SHCV-it/gnosis.git
cd gnosis
python -m venv venv && source venv/bin/activate
pip install -e . pytest python-frontmatter
# Run the test suite (offline — only localhost fixtures)
python -m pytest tests/ -q -v
Project structure
gnosis/
cli/ Click CLI (single page, crawl, dry-run, manifest)
config/ YAML loading + typed settings dataclass
core/
downloader Async HTTP client, auth, retries, FetchResult
converter HTML → Markdown, boilerplate stripping, metadata extraction
crawler BFS crawler with concurrent batch fetching
provenance Frontmatter generation, content_hash, render_document
integrations/ QMD pipeline (optional, heavy deps)
The test suite covers converter quality (comment/anchor/boilerplate/table handling, shadow-table dedup, metadata), provenance generation (fields, round-trip parsing, extras merging), auth header injection (3 schemes), crawler link resolution, and CLI end-to-end behavior. Runs entirely offline.
Contributing
Contributions are welcome. Please open an issue first to discuss what you'd like to change.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing) - Run the tests (
python -m pytest tests/ -q) - Commit your changes with clear messages
- Push and open a pull request against
main
Related projects
Gnosis is designed to feed documentation pipelines and LLM knowledge bases. Pair it with:
- n8n / cron / Airflow — schedule gnosis runs and pipe results into your downstream pipeline
- QMD — local vector search via the
--qmd-indexflag - Any Markdown-to-anything pipeline — the YAML frontmatter is parseable by python-frontmatter, Jekyll, Hugo, Obsidian, and standard static-site generators
License
MIT — see LICENSE.
Author: Steffen Hoehne, SHCV.IT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gnosis_markdown-1.1.0.tar.gz.
File metadata
- Download URL: gnosis_markdown-1.1.0.tar.gz
- Upload date:
- Size: 49.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef4946659c0e4a8eb496417c0540d7763f31839f44e4cc3deb519fa005ebcbc3
|
|
| MD5 |
a09ca5ac0952a7c433c80ab310ad91ce
|
|
| BLAKE2b-256 |
32fd07fb09ed1ef177017b09867a426fe8bceb356f7dab06f91b33793cb2dc19
|
File details
Details for the file gnosis_markdown-1.1.0-py3-none-any.whl.
File metadata
- Download URL: gnosis_markdown-1.1.0-py3-none-any.whl
- Upload date:
- Size: 39.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d614fc695450f907c2bbb2cf46b9e0d1b7eeec5eeac5f649d427322a892c03e4
|
|
| MD5 |
75034cc741b240e5e750cf40b68de3f6
|
|
| BLAKE2b-256 |
5bbb8d8c027cf93880f1f1b5373460f708807122f07902136780a61d18e8aa34
|