forktex-knowledge
Keep documentation as JSON: typed records, rendered to markdown, retrievable within a token budget.
Markdown is a fine thing to read and a poor thing to maintain once there is structure to keep consistent — a rule needs a severity and something that proves it, a document needs typed links to others, and prose cannot be checked. So the source of truth is JSON validated by Pydantic models, and the markdown is generated from it.
pip install forktex-knowledge
Three moves
1. JSON is the source. One record per file. Each names the model it loads into, so a tree nests however suits the material and nothing infers a type from a directory name:
{
"$model": "Document",
"id": "practice.python",
"title": "Writing Python here",
"updated": "2026-08-24",
"tags": ["python"],
"summary": "...",
"rules": [
{
"id": "python:target-314",
"title": "Target 3.14",
"statement": "...",
"severity": "blocker",
"enforcement": "make lint fails on the wrong target"
}
]
}
id is handcrafted and never derived. Renaming a file or moving it between
folders breaks nothing, because everything cites the id and the filesystem only
groups.
2. Load it through a repository, never by touching files:
from pathlib import Path
from forktex_knowledge import FileRepository
repo = FileRepository(Path("sources"))
doc = repo.read("engineering/python.json").document
docs = [loaded.document for loaded in repo.read_all() if loaded.ok]
3. Export with to_markdown(), inherited from Renderable, so a whole
document and any piece of one render the same way:
doc.to_markdown() # the page
doc.rules[0].to_markdown() # just that rule
The CLI, over a Site
Four verbs are the same for any corpus, so they ship here. What varies is the
Site. Two fields are required — sources and output — and everything else
has a default you can leave alone:
| Field | Default | What it is |
|---|---|---|
banner |
"" |
Comment block stamped on every page. Usually a licence header, which is why the library supplies none. |
generated_note |
a DO-NOT-EDIT line | Marks a page as generated. Must contain {source}. |
build_hint |
"rebuild" |
How to rerun the build, quoted in staleness findings — make build, just build, a script. |
link_pattern |
[[id]] |
The citation syntax. Defaulted because Document renders it. |
index_title / index_name / index_intro |
Knowledge / README.md / a sentence |
The generated index page. |
ungrouped |
"general" |
Index section for a record with no folder above it. |
# main.py
from pathlib import Path
from forktex_knowledge import Site, run
ROOT = Path(__file__).resolve().parent
raise SystemExit(run(Site(
sources=ROOT / "sources",
output=ROOT / "markdown",
banner="<!-- generated; do not edit -->",
)))
python main.py check --strict --drift # validate, and fail on a stale page
python main.py build # render everything
python main.py ask "how do I add a route?"
python main.py ask --rules --tag python
python main.py new my-doc --updated 2026-08-24
check --drift is the load-bearing one: it regenerates every page and byte-diffs
it, so a hand-edited page fails rather than surviving as a second author of the
same fact.
Retrieval
Two questions, and only one needs ranking:
from forktex_knowledge import ground, rules
rules(docs) # every rule, worst severity first
ground(docs, "add a route", budget_tokens=4000)
rules has no ranking on purpose — the whole normative set is usually a few
thousand tokens, and dropping a blocker to save a few hundred is a bad trade.
ground ranks (BM25, length-normalised so the longest document does not win on
volume), injects briefs rather than whole pages, and names what it dropped —
a silently cut context reads exactly like a complete one.
Storage is a port
The core knows nothing about files. Repository is four methods over an opaque
key, so a database or an API adapter needs no change to the models:
class Repository(Protocol):
def keys(self) -> list[str]: ...
def read(self, key: str) -> Loaded: ...
def write(self, key: str, document: Document) -> None: ...
def delete(self, key: str) -> None: ...
FileRepository is the one implementation shipped. An in-memory one is about ten
lines.
Document types
Document is doctrine: rules, worked examples, a principle. Two more ship because
they are shaped differently, and forcing them into Document loses what makes
them worth keeping:
Research— findings true on a date.as_ofis required and renders as a warning above the first figure, because prices and measurements decay.Decision— an ADR.alternativesis the field that earns it its own type: a decision without its rejected options gets re-litigated.
Register your own with @known:
from forktex_knowledge import Document, known
@known
class Runbook(Document):
oncall: str
Licence
Dual-licensed: AGPL-3.0-or-later, or a commercial licence from FORKTEX S.R.L. See LICENSE and NOTICE. For proprietary or SaaS use where the AGPL's obligations cannot be met, contact info@forktex.com.
Metadata
Release files for forktex-knowledge 0.1.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 | Actions |
|---|---|---|---|---|
| forktex_knowledge-0.1.0.tar.gz | 26.3 kB | Without provenance | Details for forktex_knowledge-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| forktex_knowledge-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for forktex_knowledge-0.1.0-py3-none-any.whl |
Total release size: 64.2 kB
Release files / forktex_knowledge-0.1.0.tar.gz
| Download URL | forktex_knowledge-0.1.0.tar.gz |
|---|---|
| Size | 26.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f159440cfdc0994d220e1102e49a78c148018a87cc3988e2b24fc0e14b467728
|
|
BLAKE2b-256 checksum How to use checksums |
ce86b29ed46f86a776ad4bc1518ccabb9892a797e39416ff00ec63eaa9e5fe9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / forktex_knowledge-0.1.0-py3-none-any.whl
| Download URL | forktex_knowledge-0.1.0-py3-none-any.whl |
|---|---|
| Size | 37.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
340dae672b87761b1097c8ed24b7fe19fb7fbc4bf9084f6b5ddc6d2333654351
|
|
BLAKE2b-256 checksum How to use checksums |
8b774f37c90b8f16725a7e507bea30e7a5010fa8cb9c53b0f6fa4bd87b5fd027
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Security for forktex-knowledge 0.1.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.