text-forge
Text Forge is a toolkit for working with long-form Markdown as a living text: a website, a book, an editable workspace, an AI-readable corpus, and a source model for agent memory and future meaning graphs.
It grew out of the whattodo / WTD approach — Жизнь как Текст (“Life as Text”): important thinking should remain plain, readable, public, versioned, and useful to both humans and agents. Markdown stays the roots. Everything else is a projection.
The idea
A meaningful text is not only a page to publish. It is also:
- a book to read offline;
- a website with stable public addresses;
- an editor for continuous work;
- a corpus for search, review, and AI feedback;
- a memory substrate for agents;
- a future graph of sections, concepts, references, aliases, and changes.
Text Forge keeps these roles connected through one source of truth:
plain Markdown + MkDocs navigation + Git history
↓
Text Forge source model
↓
website / EPUB / editor / AI-readable export
↓
inventory → memory projections → meaning graph projections
The key principle is: do not pollute the source text with infrastructure concerns. Keep Markdown readable. Put publication, memory, graph, and agent mechanics into generated layers.
Life as Text
The WTD approach treats life, work, product thinking, references, doubts, and decisions as a text that can be revised, linked, published, questioned, and remembered.
That creates a different kind of tooling requirement:
- chapters can be published or still in draft, but both may be useful for feedback;
- explicit anchors are public addresses for ideas, not just HTML implementation details;
- source history matters because meanings evolve;
- agents should cite sections, not vaguely “remember something”;
- future tools should map meanings without forcing technical IDs into the Markdown.
Text Forge is the infrastructure layer for that workflow.
What Text Forge does today
Publish a MkDocs text as a website
Text Forge extends MkDocs Material with:
- theme overrides;
- custom partials and assets;
- source links;
- editor/download/header integrations;
- custom content blocks used by long-form text projects.
Build an EPUB
The same source can become an EPUB:
- chapters are combined from
mkdocs.ymlnavigation; - PyMdown syntax is normalized for Pandoc;
- assets are bundled;
- metadata can include Git-derived dates/versioning;
- output is compatible with normal e-readers.
Edit text in the browser
The live editor supports:
- browser-based Markdown editing;
- real-time preview through Pyodide + PyMdown Extensions;
- local save during
mkdocs serve; - GitHub API commits in production;
- split-pane interface with synchronized scrolling;
- Russian translations.
Export for AI and agents
Text Forge can generate AI-readable material:
- combined Markdown export;
- normalized anchors and links;
- privacy-first behavior: AI-readable export is opt-in.
Generate a source inventory
The next layer is a deterministic inventory of the text:
Markdown files + mkdocs.yml + Git metadata
↓
chapters, sections, anchors, line ranges, URLs, draft/published status
This inventory is the common input for downstream tools. They should not reimplement MkDocs parsing.
Current building block:
scripts/wtd-inventory.py
Despite the name, it is the first implementation of a broader pattern: derive a stable source model from a MkDocs text project.
Project text into agent memory
Text Forge also includes a public Hindsight adapter:
scripts/hindsight-ingest.py
It consumes inventory JSON and writes citable documents into Hindsight. This makes a text available to agents as structured memory while preserving public URLs, GitHub source links, chapter/section identity, and tags.
Recommended ownership framing for retain quality and attribution stability:
- context should explicitly state ownership, for example:
WTD roots corpus authored by User; Assistant is reader. - metadata should keep machine-readable provenance fields:
text_author=User,reader=Assistant.
The public adapter is intentionally infrastructure-neutral. Private paths, hostnames, bank names, backups, and operational rituals belong in local Hermes skills or wrappers.
See:
docs/hindsight-memory.md— reference for the Hindsight projection shape;docs/hindsight-memory/SKILL.md— example Hermes skill workflow using Text Forge scripts.
The architecture
Text Forge is not meant to become a monolith. It should be the reusable source-model layer.
┌────────────────────┐
│ plain Markdown text │
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ MkDocs + Git roots │
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ Text Forge model │
└─────────┬──────────┘
│
┌───────────────────┼────────────────────┐
│ │ │
┌───────▼────────┐ ┌───────▼────────┐ ┌────────▼─────────┐
│ Website / EPUB │ │ Agent memory │ │ Meaning graph │
│ Editor / AI md │ │ Hindsight etc. │ │ future layer │
└────────────────┘ └────────────────┘ └──────────────────┘
For WTD specifically:
WTD roots
= source Markdown, anchors, references, Git history
WTD Hindsight corpus
= agent-memory projection of those roots
WTD graph
= future meaning representation: concepts, mappings, aliases, splits, merges, evolution
The graph can eventually preserve anchor renames and section mappings without adding hidden metadata comments to the Markdown.
Drafts and public addresses
Text Forge distinguishes:
- published chapters — included in
mkdocs.ymlnavigation and released in the table of contents; - draft chapters — Markdown files under
docs_dirbut not in navigation yet.
Draft does not mean useless or private. A draft page may still have a stable preview/public URL and can be used for feedback, review, and memory. It is simply not part of the released table of contents.
Explicit heading anchors are treated as public addresses for ideas:
## Form of the Book {#book_form}
A chapter with no anchored headings still has a chapter-level address:
https://example.org/chapter-slug/
This is enough for the source. More complex identity mapping belongs in a generated graph layer, not in the Markdown.
Installation
Python package
pip install sg-text-forge
GitHub Action
# .github/workflows/publish.yml
- uses: shared-goals/text-forge@main
with:
mkdocs_config: mkdocs.yml
docs_dir: text/ru
site_dir: public/ru
Quick start
Peer layout for local content repos
When using a local content repo such as whattodo, the default convention is to keep it as a peer directory:
work/
text-forge/
whattodo/
whattodo/Makefile uses:
TEXT_FORGE_DIR ?= ../text-forge
So local script routes resolve from the content repo to this toolkit repo without hardcoded machine-specific paths.
Add the plugin to mkdocs.yml:
plugins:
- text-forge:
editor_enabled: true
nobr_emoticons_enabled: true
downloads_enabled: false
ai_readable_enabled: false
epub_title: "My Book"
epub_author: "Author Name"
Build EPUB:
text-forge epub --config=mkdocs.yml --build-dir=build
Build complete site:
text-forge build --config=mkdocs.yml --build-dir=build
Generate inventory:
python scripts/wtd-inventory.py --config mkdocs.yml --include-drafts --format json
Dry-run a Hindsight memory projection:
python scripts/wtd-inventory.py --config mkdocs.yml --include-drafts --format json \
| python scripts/hindsight-ingest.py \
--api-url http://localhost:8889 \
--bank hermes \
--strategy wtd-primary \
--dry-run
CLI commands
text-forge epub
Build EPUB from a MkDocs project.
text-forge epub [OPTIONS]
Options:
--config PATH Path to mkdocs.yml (default: mkdocs.yml)
--build-dir PATH Build output directory (default: build)
text-forge build
Build complete site: EPUB + MkDocs site.
text-forge build [OPTIONS]
Options:
--config PATH Path to mkdocs.yml (default: mkdocs.yml)
--build-dir PATH Build directory (default: build)
--site-dir PATH MkDocs output (default: from mkdocs.yml)
--strict/--no-strict Fail on warnings (default: true)
--copy-artifacts/--no-copy-artifacts
Copy EPUB to site root (default: true)
--create-404-redirect/--no-create-404-redirect
Create 404.html for /ru/* redirects (default: true)
Plugin configuration
plugins:
- text-forge:
# Editor
editor_enabled: true
nobr_emoticons_enabled: true
# Downloads and AI-readable export
downloads_enabled: false
ai_readable_enabled: false
# EPUB metadata
epub_title: ""
epub_subtitle: ""
epub_author: ""
epub_identifier: ""
epub_publisher: ""
epub_rights: ""
# UI labels
source_file_published_title: "Published"
# Theme integration
auto_configure_theme: true
Repository map
text-forge/
├── text_forge/ # Python package
│ ├── plugin.py # MkDocs plugin
│ ├── build.py # Build pipeline
│ ├── cli.py # CLI commands
│ └── obsidian/ # Obsidian-related templates/helpers
├── scripts/
│ ├── mkdocs-combine.py # Chapter combiner / AI-readable export helper
│ ├── mkdocs_common.py # Shared MkDocs helpers for scripts
│ ├── wtd-inventory.py # Source inventory generator
│ ├── hindsight-ingest.py # Public Hindsight adapter
│ ├── pymdown-pandoc.lua # Pandoc Lua filter
│ └── process-epub-meta.py # EPUB metadata processor
├── docs/
│ └── hindsight-memory/ # Example Hermes skill for memory projection
├── mkdocs/
│ ├── overrides/ # Material theme overrides
│ └── hooks/ # MkDocs hooks
├── epub/ # EPUB templates and styles
└── tests/ # Pytest tests
Example projects
Development
git clone https://github.com/shared-goals/text-forge.git
cd text-forge
make install
make test
Useful commands:
make format # Run Ruff check --fix and Ruff format
make test # Run i18n check and tests with pytest
make check-i18n # Validate translation keys
make release # Interactive release: bump version, tag, push
Requirements
- Python ≥ 3.11
- Pandoc, for EPUB generation
- MkDocs Material
- Git, for version/date/source metadata
License
MIT License — see LICENSE.
Contributing
Contributions welcome. Please open issues or pull requests at github.com/shared-goals/text-forge.
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 sg_text_forge-0.1.16.tar.gz.
File metadata
- Download URL: sg_text_forge-0.1.16.tar.gz
- Upload date:
- Size: 111.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19e07982a2d6d16b0eb9bb466a57610dc472f44ff1fd313ae7c28db842e23b06
|
|
| MD5 |
ff4bea857d981633255a6ad813becbd0
|
|
| BLAKE2b-256 |
e9f6d4eb907ac0e3c323dd0cae4cbbe7616202acf9f35c550f6d1ea157fb6d6a
|
Provenance
The following attestation bundles were made for sg_text_forge-0.1.16.tar.gz:
Publisher:
publish-pypi.yml on shared-goals/text-forge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sg_text_forge-0.1.16.tar.gz -
Subject digest:
19e07982a2d6d16b0eb9bb466a57610dc472f44ff1fd313ae7c28db842e23b06 - Sigstore transparency entry: 2365058420
- Sigstore integration time:
-
Permalink:
shared-goals/text-forge@f5e36ded70c27b9063a381fd40cce31984b2f75b -
Branch / Tag:
refs/tags/v0.1.16 - Owner: https://github.com/shared-goals
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@f5e36ded70c27b9063a381fd40cce31984b2f75b -
Trigger Event:
push
-
Statement type:
File details
Details for the file sg_text_forge-0.1.16-py3-none-any.whl.
File metadata
- Download URL: sg_text_forge-0.1.16-py3-none-any.whl
- Upload date:
- Size: 78.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86cd024fadca3426f2a53ea2ad5d3bf685bf08abdf8d7143d89fca7a538aeb75
|
|
| MD5 |
1cbbfc6536b7f7aa0fa0c5d0d11be49c
|
|
| BLAKE2b-256 |
4caab577934c461362927649cefb88a0fa8e1aae175c29a43dffbe8092bee0f6
|
Provenance
The following attestation bundles were made for sg_text_forge-0.1.16-py3-none-any.whl:
Publisher:
publish-pypi.yml on shared-goals/text-forge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sg_text_forge-0.1.16-py3-none-any.whl -
Subject digest:
86cd024fadca3426f2a53ea2ad5d3bf685bf08abdf8d7143d89fca7a538aeb75 - Sigstore transparency entry: 2365058537
- Sigstore integration time:
-
Permalink:
shared-goals/text-forge@f5e36ded70c27b9063a381fd40cce31984b2f75b -
Branch / Tag:
refs/tags/v0.1.16 - Owner: https://github.com/shared-goals
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@f5e36ded70c27b9063a381fd40cce31984b2f75b -
Trigger Event:
push
-
Statement type: