Skip to content
Changelog
On this page

#Changelog

#0.42.1

The assembly refreshes every page's sibling-projects block from the current roster on each deploy, so retiring or adding a project no longer leaves stale links that refuse every following deploy.

#Fixes

  • A retired or newly added project no longer leaves every other project's page listing the wrong tools. The "More tools from this site" section each assembled page ends with was rendered once, when that project last deployed, and nothing refreshed it afterwards: a project joining the site reached nobody else's pages, and retiring one left its address linked from every other project's -- an address the site no longer serves, which made every following deploy fail verification. Every deploy now regenerates the section on every page in the tree.

#0.42.0

Every selfdoc-owned directory lives under .stricttools/ with a manifest.toml per directory, moved by a dry-run-capable script; titles compose written values only; topology.projects, legacy_blog_host and the Pages worker are gone; the lint table renders from the registry; check resolves generated pages through both docs roots.

#Breaking

  • Breaking. Every directory selfdoc owns in a repository moved under one hidden directory, .stricttools/: the handwritten pages at .stricttools/docs/, the generated pages and the manifests, hash baselines and revisions at .stricttools/docs-state/, the build output and version cache at .stricttools/docs-cache/, the posts at .stricttools/posts/, and the vocabulary at .stricttools/vocabulary/. A repository still carrying .selfdoc/ or declaring a docs, output or posts path outside the layout is refused by every command, with scripts/move-to-stricttools-layout.py named. Writing into any of those directories needs that directory's own manifest.toml -- one line, owner = "selfdoc" -- which selfdoc never writes itself and refuses without, printing the file and the line to create.
  • Page titles are written text. A page's <title> is now composed of written values only -- the page's own title, the project's name, and the name of the assembled site -- joined with -, with an empty or repeated name left out so no title renders X - X. A project's index page names no project, so a standalone build's front page carries its written title alone; it no longer draws on the project description, and the SEO016 lint that asked that description to carry a that clause is gone. og:title and twitter:title carry the same string the title element does.
  • **topology.projects is refused.** A cross-project link now resolves to <topology.docs_base>/<slug>/ for any slug, so the hand-typed slug-to-URL map is gone from the schema and from the URL builder. A selfdoc.json still carrying topology.projects is refused by name, saying what replaced it.
  • No redirect worker is emitted. The assembly no longer generates a Cloudflare Pages _worker.js: host redirects belong to the DNS zone and a retired path shape answers with the site's 404. --legacy-blog-host is removed from assembly init, generate-shared, integrate and preview, and a selfdoc.json carrying topology.legacy_blog_host is refused by name. A tree still holding a worker from an earlier deploy is refused by assembly verify and deleted by the next integration.

#Features

  • New commands. selfdoc layout dump prints selfdoc's layout declaration as JSON -- every directory it claims under .stricttools/, whether the directory is handwritten or generated, whether the repository commits it, the manifest.toml that grants it and the exact line that file must hold, and the paths it replaced -- and selfdoc layout validate checks one repository against it: every directory carries a manifest naming a tool the machine has, every directory selfdoc claims names selfdoc, each holds only what its side allows, nothing inside starts with a dot except the derived .gitignore, and that file carries what the commitment declarations render.
  • New script. scripts/move-to-stricttools-layout.py moves one repository onto the .stricttools/ layout: dry-run capable, it moves every tracked file with safegit mv as one commit, rewrites the paths the moved content names as a second commit, and refuses to finish unless the build that follows publishes the identical URL set.
  • New page. The documentation now carries a page on the .stricttools/ layout: the directories selfdoc claims with their sides and commitments, the per-directory manifest.toml that grants each one, the derived ignore file, the two docs roots and the addresses they share, selfdoc layout dump and selfdoc layout validate, and the move script.
  • Ownership is a manifest inside each directory. A directory under .stricttools/ declares its owner in its own manifest.toml -- one line, owner = "<tool>", validated against a schema so an unknown key is refused -- and that file is the permission to write into it. selfdoc never writes one, refuses a directory that carries none with the exact file and line to create, and treats a manifest naming another tool as that tool's. selfdoc layout validate holds every directory under the root to a manifest whose owner is a tool the machine has, and scripts/move-to-stricttools-layout.py writes the manifests of the directories it moves content into as part of the move commit.

#Fixes

  • The project description says what selfdoc is. selfdoc.json, the README's opening paragraph and the command's doc comment now carry one written line -- a static site generator that builds a project's documentation site directly from its source code, with SEO/AEO, a first-class blog, search and cross-project linking -- instead of three paraphrases of it.
  • **selfdoc check no longer reports generated CLI pages missing.** A strictcli project's CLI reference pages are generated into selfdoc's own generated docs root, but the check looked for them only in the handwritten root, so every command's page was reported missing with CLI001. The check now resolves pages across both roots, the way the build does.
  • **New directive list-lints, and the check guide's lint table is now generated.** The page listed every lint code, its severity and what it checks by hand, so a code added or changed in severity left the documentation stating the old thing. The table is now rendered from selfdoc's own lint registry, and any project's page can render it with :-: list-lints.

#0.41.0

Frontmatter is TOML between +++ fences with a declared key registry, converted by a dry-run-capable script; social titles match the document title; the title-length check measures the rendered title; selfdoc check reports broken links again; assembly verification walks links from the arrival pages instead of demanding a complete front page or listing.

#Breaking

  • Frontmatter is TOML. Every page and post now carries TOML frontmatter between +++ fences, validated against a declared key registry: an undeclared key is refused rather than ignored, values carry their declared types (dates as TOML local dates, tags as arrays, switches as booleans), and a post's required keys come from the schema. A --- block is refused by name, with the converter that rewrites it. order collapses into nav_order, and project is refused.

#Features

  • Frontmatter converter. scripts/convert-frontmatter-to-toml.py rewrites a project's pages and posts from the retired --- frontmatter block to the TOML block between +++ fences. It is dry-run capable, asserts how many files it changes, and refuses -- naming the file and the line -- any value it cannot spell with certainty.
  • Frontmatter guide. A new documentation page carries the whole frontmatter key registry -- every key, its type, whether a post must carry it, and what it declares -- alongside the fenced block, the reader-supplied keys, and how to convert a retired block.
  • The frontmatter converter can convert generated pages too. --include-generated converts pages marked generated (lifting and restoring their write protection), which a project needs once before the first selfdoc gen that writes TOML, because gen keeps a generated page's handwritten description by reading the page.

#Fixes

  • Assembly verification no longer refuses a site whose curated front page or listing omits a project. The reachability check now fails only when neither the site root nor the project listing links a project; the sibling block every assembled page carries makes the root name them all.

#0.40.0

Pages describe their project to search and answer engines: index titles name what the project is, social titles match, the assembled site links every project from every page and its listing pages carry descriptions and structured data, robots.txt allows Claude-SearchBot, and the crawler list, description lints, Go synopsis extraction and stale-build link reporting are corrected.

#Features

  • **robots.txt now allows Claude-SearchBot.** Anthropic's indexing crawler for Claude's search is named explicitly alongside the other AI crawlers, so generated sites are indexable by it.
  • The assembled site's listing pages are now legible to search engines. /projects/ and /blog/ carry a meta description and CollectionPage structured data with breadcrumbs, and the 404 page asks not to be indexed.
  • Every page on the assembled site now links the site's other projects. A "More tools from this site" section at the end of each page names each one with its one-line description; a project deployed on its own emits nothing.
  • Assembly verification now refuses a site where a project is unreachable. A deploy fails if the site root or the /projects/ listing does not link a declared project's index page.

#Fixes

  • A project's index page title now says what the project is. A page titled with the project name rendered name - name, which no search or answer engine can use. It now renders the project name followed by the thing the description in selfdoc.json names (the part before its that clause), trimmed at a word boundary to at most 70 characters; a description with no such clause leaves the project name alone, and selfdoc check reports the new SEO016 warning.
  • Meta description warnings now use a 110-160 character band. selfdoc check warned about any description under 120 characters (SEO009) or over 155 (SEO010); the band is now 110-160, which matches what a search result actually renders. Nothing truncates a description, so what you write is what the page publishes.
  • **A generated file's DO NOT EDIT banner no longer becomes a Go package's description.** selfdoc gen read any comment above a package clause, including one separated from it by a blank line, so a package containing a generated file got a page described as "Code generated by ...". Only a comment adjacent to the package clause counts now, which is the rule go doc applies.
  • **The site-wide llms.txt marks a project with no description.** An entry whose manifest states none now reads (no description) instead of stopping after the link, so the gap is visible.
  • **selfdoc check no longer reports links from an out-of-date build.** After a source doc comment changed, check kept reporting the link the previously built page carried (LINK001) until selfdoc build was re-run, an error no source edit could clear. A reference inside a page's content region that the page's current source no longer carries is now skipped.
  • The sibling-projects section is styled. The "More tools from this site" block every assembled page ends with now renders as a compact grid of project links with muted one-line descriptions, separated from the article by a border, instead of a bare heading over a bulleted list.
  • The llms.txt guide lists the crawlers your build actually allows. The "AI Crawler Access" section now renders the user agents straight from the crawler policy robots.txt is generated from, via a new list-crawlers directive, instead of a hand-written copy that could fall out of step with the file.
  • The project describes itself with a defining first sentence, and its docs base is the unified-site address. The README opened with a fragment and the declared docs base was the retired per-project host.
  • Social titles no longer repeat the project name. A page titled with the project name -- the home page -- published og:title and twitter:title as <name> - <name>; both now carry the same title the page's <title> element shows.
  • **selfdoc check reports a broken link again.** The stale-build filter compared a built page's href (../missing/) against the page's Markdown ([Guide](missing.md)) -- two spellings that never match -- so LINK001 was suppressed on links the source really does write. The filter now compares against the hrefs the current source would emit.
  • The title-length check now measures the title a page really renders, and the cap is 60 everywhere. SEO004 modelled every title as <page title> - <project name>, so on the home page -- whose title is the project name -- it reported a length no page carried, and no edit could clear it. It now measures the rendered document title, and the derived home-page title is cut to 60 characters rather than 70, matching the check's own threshold.

#0.39.7

Site assembly repairs absolute links to the site blog across the whole assembled tree, so deploys pass verification again.

#Fixes

  • **selfdoc baseline accept works in the unified site's home project.** It registered none of the site-level directives (projects-cards, blog-highlights) that check resolves, so it refused every home page as carrying an unknown directive.
  • Site assembly repairs absolute links to the site blog on every page. Pages an older toolchain wrote into the assembled tree addressed the blog as https://<site>/blog/..., and the assembled-tree verification refuses that on every deploy, because a clicked link must stay inside whatever mount the site is served from. assembly integrate now rewrites such links document-relatively across the whole tree, so deploys pass verification again without republishing every project.

#0.39.6

A home project's check stops reporting the assembled site's links

Context

The previous release let a home project's site-level directives resolve, which made its check reach the links those regions render -- links into other projects' subtrees that only the assembled site holds. The resolution check now takes the elements a build does not answer for, so a project exempts its regions and the assembly, where those links must resolve, exempts nothing.

#Fixes

  • A home project's own check stops reporting the assembled site's links. The links a site-level directive's region renders address other projects' subtrees and the site-level blog, which the project carrying the region never writes; selfdoc check reported every one of them as unresolvable. They are left to the assembly's own pass over the whole tree, which is where they resolve.

#0.39.5

Home projects publish and unversioned projects dispatch

Context

Both defects were inherited from the Python version and only surface on the unified site's home project: the publish and the check never read the assembly's roster, so they never knew the project they were looking at was home, and a project with no public version had no version string to dispatch under.

#Fixes

  • The unified site's home project publishes again. selfdoc blog publish-docs and selfdoc check build a home project with its site-level directives (projects-cards, blog-highlights) resolved against the assembly's manifests, instead of refusing the directive as unknown.
  • **selfdoc assembly push dispatches an unversioned project.** A project declaring unversioned: true is dispatched at its current branch and recorded as unversioned; before, the push refused it for having no versions.

#0.39.4

Install with go install github.com/smm-h/selfdoc@v0

Context

The binary's package main moved from cmd/selfdoc to the module root, so the install line loses its trailing path segment and the binary still takes its name from the module's last element. Nothing under internal/ can import a root package main, so the version is handed down from the entry point instead: internal/cli takes it on Options.Version, and the selfdoc toolchain pin a generated assembly deploy workflow installs is now a required input rather than a value the assembly package reads for itself. This release also carries the already-committed test-speed work, which builds the suites' fake external tools once instead of re-running the race binary for every invocation.

#Breaking

  • **Install with go install github.com/smm-h/selfdoc@v0.** The entry point moved to the module root, so the former .../cmd/selfdoc path no longer exists.

#0.39.3

The assembly commands name the branch they read and write

Context

Four call sites passed an empty branch into the GitHub Git Data API helpers, which renders "/repos//git/ref/heads/" and is answered 404. It surfaced on 0.39.2's own post-release hook: the fix that made the hook pin the deploy workflow to the released version could not take effect, because the command doing the pinning never reached the assembly at all. The helpers now refuse an empty branch by name, so the path can no longer be rendered.

#Fixes

  • The assembly commands reach the assembly again. assembly sync-workflow, assembly retire and post publish named no branch when they read or wrote the assembly repository, so each failed with get HEAD ref: gh: Not Found (HTTP 404) -- a missing argument reported as a missing repository. This is what stopped 0.39.2's post-release hook from pinning the deploy workflow to the version it had just released.

#0.39.2

Latest strictcli, strictspec and go-toml-edit; the deploy workflow pins the released version

Context

go-toml-edit was held at 0.3.0 only because the published strictcli/go and strictspec/go did not compile against 0.4.0; both now do, so all three move together. internal/util's TOML decode no longer walks the AST to work around the 0.3.0 decoder dropping an array of tables nested inside another one -- the 0.4.0 read-layer answers that shape correctly, and only document key order, which is a question about how the file was written, still comes off the AST.

The post-release hook's missing pin was found on the 0.39.1 release: it wrote an assembly deploy workflow pinned to 0.39.0 because the selfdoc on PATH at hook time predated the version bump.

#Fixes

  • TOML parse errors are reworded. Configuration and data documents (docs/cv.toml, docs/projects.toml, the assembly roster) are decoded by go-toml-edit 0.4.0, which phrases a syntax error differently: 1:18: expected a value, got end of input in place of line 1, column 18: expected value, got EOF. The <file> is not valid TOML: sentence around it is unchanged.
  • The assembly deploy workflow is pinned to the version just released. The post-release hook passed no pin, so the regenerated workflow named the version of the binary on PATH -- built before the release's own version bump -- and could name a version the Go module proxy did not serve.

#0.39.1

The Go module is fetchable again

Context

0.39.0 is tagged and has a GitHub Release, but the Go module proxy refuses to build its module zip because one source file was named aux.go, and aux is reserved as a path component on Windows -- so go install github.com/smm-h/selfdoc/cmd/selfdoc@v0 failed for that version. A retraction cannot make a published version fetchable, so this patch renames the file to auxiliary.go. A guard test walks every path in the module and fails on any component whose name is one of the names Go refuses (CON, PRN, AUX, NUL, COM1-COM9, LPT1-LPT9), so the module can never again be published unfetchable.

#Fixes

  • **go install github.com/smm-h/selfdoc/cmd/selfdoc@v0 works again.** 0.39.0 could not be fetched from the Go module proxy because one source file carried a Windows-reserved name; the file is renamed and a test refuses any such path.

#0.39.0

Rewritten in Go as one binary; the selfblog command folds into selfdoc

Context

selfdoc, selfdoc-core and selfblog were three Python packages that had to be installed and upgraded together, and the two command-line tools refused each other's projects even though they built the same pages out of the same engine. This release replaces all three with one Go module, github.com/smm-h/selfdoc, and one binary, selfdoc, that carries the engine, the blog, the assembly and the editor. Every line of Python in the repository is deleted, and the repository itself stops being a single-member workspace and becomes an ordinary standalone rlsbl project. The only interpreter the binary ever starts is python3, and only for a project's own custom directives: Python source is parsed in process now, so documenting a Python project needs no interpreter on the machine.

The port was verified by building every consumer in the fleet twice -- once with the released Python tools, once with the new binary -- and diffing the output trees. The output is byte-identical everywhere except where a library was deliberately swapped: chroma replaces pygments for syntax highlighting and emits its own token class names, and Open Graph cards are the basic generated PNG now that the rich pre-drawn path is gone.

Distribution is the Go binary alone. go install github.com/smm-h/selfdoc/cmd/selfdoc@v0 installs it directly, and every release publishes prebuilt archives for Linux, macOS and Windows on amd64 and arm64 for a machine with no Go toolchain. The npm and PyPI launcher packages this repository used to publish are gone and stop receiving updates.

What consumers have to change: a post-release hook that runs selfblog assembly push becomes selfdoc assembly push, and every other selfblog X invocation becomes selfdoc X. Writing commands sit under one blog group, so selfdoc post X is selfdoc blog post X, selfdoc editor X is selfdoc blog editor X, and selfdoc docs publish is selfdoc blog publish-docs. Custom CSS written against pygments highlight classes must be re-pointed at chroma's. An assembly's deploy workflow is regenerated with selfdoc assembly sync-workflow, which now installs the Go binary and pins one version.

#Breaking

  • [root] **selfdoc is one Go binary now, and the selfblog command is gone.** Install it with go install github.com/smm-h/selfdoc/cmd/selfdoc@v0, or download the archive for your platform from the GitHub Release; every selfblog X invocation is now selfdoc X, so a post-release hook running selfblog assembly push must be changed to selfdoc assembly push.
  • [root] **One build builds every kind of site and one check checks every kind of project.** build --target site|posts|unified|home selects what to build, and check validates whichever kind of project it is pointed at, so the refusals each of the two former CLIs raised against the other kind of project are gone.
  • [root] **Custom directives run out of process through python3.** The resolve(attrs, config, body) contract is unchanged, so existing scripts keep working, but a script that fails or that defines no resolve is now a hard error that stops the build instead of an inline note left in the page.
  • [root] Syntax highlighting comes from chroma, whose token class names differ from pygments. Highlighted code carries chroma class names, so custom CSS written against the old pygments classes must be re-pointed; the stylesheet selfdoc generates follows the new names by itself.
  • [root] Open Graph cards are the basic generated PNG only. Every page still gets an OG image, drawn by the built-in generator; the richer pre-drawn card path is gone.
  • [root] The assembly deploy workflow installs the Go binary and pins one version. The generated workflow runs go install instead of installing two Python packages, and assembly sync-workflow takes --pin-selfdoc and --pin-pagefind to choose the versions it writes; regenerate the workflow with selfdoc assembly sync-workflow after upgrading.
  • [root] **Home-project pages wrap site-level directive output in <selfdoc-region> instead of <selfblog-region>.** The unified assembly refreshes only regions carrying the new tag, so redeploy the home project once after upgrading (selfdoc blog publish-docs from the home checkout, or its next release); until then its project cards and newest-post block stay as last published.
  • [root] **The editor reads its repository list from ~/Projects/ark/selfdoc-registry.toml by default.** Move an existing selfblog-registry.toml to the new name, or pass --registry with the old path.
  • **The blog commands moved under one blog group.** selfdoc post X is now selfdoc blog post X, selfdoc editor X is now selfdoc blog editor X, and selfdoc docs publish is now selfdoc blog publish-docs; change any hook, script or alias that spells an old path.
  • Go is the only distribution channel. The selfdocumenting npm and PyPI packages are gone and stop receiving updates: install with go install github.com/smm-h/selfdoc/cmd/selfdoc@v0, or, on a machine with no Go toolchain, download the archive for your platform from the GitHub Release and put selfdoc on your PATH.

#Features

  • [root] **python3 is needed only for custom directives.** The build, the blog, the assembly and every language extractor -- Python included -- run inside the one binary, so a project that declares no custom directive script needs no interpreter at all.
  • [root] The Python-only dependencies are gone. Installing selfdoc no longer pulls a Python dependency set along with it: the themes, browser scripts, word list and document validators are compiled into the binary.
  • [root] Documenting Python no longer needs a Python interpreter. selfdoc reads Python source itself, so gen, build and check work on a machine with no python3 installed -- reference pages, signatures and field tables render exactly as before.

#Fixes

  • [root] A Go package reads its documentation from a fixed file. Package documentation no longer depends on which file the source walk reached first, so rebuilding a Go project's reference pages gives the same package text every time.
  • [root] The check report keeps a directive's attributes in the order the template wrote them. A directive line in selfdoc check output reads back the way it was written instead of in a reordered form.

#0.38.1

Fixes the CLI reference pages selfdoc generates failing selfdoc's own spell check: the entity indent on a scoped flag row and the 'Clearable' heading of a sparse update.

Context

selfdoc renders a strictcli app's schema into reference pages and then spell-checks those pages, so every fixed word and every markup construct the renderer emits is judged by SPELL001 in the consumer's project. Two of them were not words the engine knew: the ' ' entity that indents a scoped flag's row under the member it belongs to, and the '- Clearable:' heading a sparse update publishes its unset tokens under. The first project to render a member-spelled selector and an update command with a nullable property got 37 error-severity lints for text it did not write and could not edit.

Both are fixed in the engine (selfdoc-core 0.10.1), each at the layer it belongs to: entity references are markup and are blanked like tags before a line is scanned, and the fixed vocabulary selfdoc's own renderers emit is carried by the engine and accepted everywhere, because the accept list belongs to one machine while a rendered page ships to all of them. A rendered-page test renders a schema exercising every construct the renderer has prose for, so a new fixed word cannot reach a consumer unaccepted.

#Fixes

  • [selfdoc] **selfdoc check no longer fails on the CLI reference pages selfdoc itself generates.** A command declaring a member-spelled selector rendered its scoped flags behind &nbsp; indents, and a sparse update rendered a Clearable heading; the spell checker read both as English, so a project that regenerated its CLI reference got error-severity lints for text it did not write and could not edit.

#0.38.0

CLI reference pages read strictcli schema version 2, and selfdoc's own CLI declares its presence

Context

strictcli 0.41.0 turned a set of previously-inferred facts into mandatory declarations, every one of them a registration-time hard error, and it publishes the result at schema_version 2. Both halves reach selfdoc.

Its own CLI could not start under 0.41 until every flag and argument declared its presence, which is what makes selfdoc runnable at all for a fleet already on the new floor -- selfdoc gen and selfdoc check are steps in every project's release, so nothing downstream could release until this shipped.

Its reader of other projects' schemas was worse than broken: it read a type key v2 deleted and a required key an earlier round deleted, and both reads had a fallback, so every page claimed every flag was a string and every positional argument required, silently and successfully. The reader is now v2-only and refuses any other version rather than guessing, and it renders the constructs v2 adds -- presence, choices records, selectors and their scopes, constraints, update declarations -- instead of flattening them away.

#Breaking

  • [selfdoc] **Breaking: machine output is now the strictcli envelope, entered with --json.** selfdoc check, selfdoc spell-corpus and selfdoc quality no longer take --format text|json; each writes exactly one document to stdout under --json — the framework envelope, whose payload member is the report. Each command declares its payload's JSON Schema, which the framework validates before writing and --dump-schema publishes, so schemas/check-output.schema.json is gone: the declaration is the artifact to generate against.
  • [selfdoc] Generated CLI reference pages now require strictcli schema version 2. selfdoc reads .strictcli/schema.json at schema_version: 2 only, and refuses any other version with a message naming the regeneration command. v2 is not a superset of v1 -- it deletes keys the old reader read -- so there is no dual path: regenerate the schema with a strictcli 0.41.0 or newer (<app> --dump-schema).

#Features

  • [selfdoc] A guide for the new blog-post editor. docs/editor-guide.md documents the authoring app: the registry file's format and every shape it refuses, the two commands and their flags, where the editor's front-end assets come from, and what the preview is -- the publish render of an unsaved buffer, and why that means it writes nothing.
  • [selfdoc] The editor guide covers the assistance lanes, cross-project links and publishing. New sections describe the spelling and lint marks and where their engines come from, the ]( completion and the addresses it inserts, and the publish consent dialog -- including that it publishes the whole repository and that consent is never remembered.
  • [selfdoc] Glossary guide covers every declaration form. The guide now documents Markdown definition lists alongside <dfn> tags and the list-glossary directive, states that prose is never read as a declaration, and describes the term-<slug> anchors and the link from a definition site back to its glossary entry.
  • [selfdoc] The blog guide covers the local assembly preview. A new section documents the command surface, the pipeline table naming which production function runs at each step, that verification reports rather than blocks, what the server does about directory addresses and 404s, and why the output directory is refused inside a checkout.
  • [selfdoc] selfdoc build --theme <name> renders the site under a named theme for that build only, overriding what selfdoc.json declares and writing nothing back. An unknown name is refused against the theme registry.
  • [selfdoc] The theming guide describes the tinymoon theme as it now is. It said the theme carries its own base64 faces and defines its own palette; it now covers the framework composition, the variable bridge, the CSS-only three-state resolution and the css/ + fonts/ layout.
  • [selfdoc] Documented which pages print their frontmatter description above the H1. The getting-started guide now states the rule: the home page and posts drop the summary block, every other page keeps it.
  • [selfdoc] CLI reference pages render the constructs strictcli schema v2 publishes. A value flag's choices appear with their per-entry help. A selector renders as the construct it is: a member-spelled one's own name is never printed as a flag, because it is never typed -- each member becomes its own row, with the flags that exist only while it is elected indented beneath it, to any depth, each naming its scope. Constraints render as the rule each one states. An update command states its resource, its write mode, what an unsupplied property means, that at least one property is required, and the --unset-<property> spellings a nullable property mints. A negatable bool shows --no-<flag> beside its own name, and flag sets and the app's config and env-prefix declarations reach the page too.
  • [selfdoc] selfdoc requires strictcli 0.41.0 or newer, and its own CLI is declared on the new terms. Every flag and positional argument declares its presence, so --help states which of required, optional or a declared default each one is. What you type is unchanged: an omitted --auto-commit still commits, an omitted --port still binds 8000, and each such flag now names its fallback in its own help text.

#Fixes

  • [selfdoc] **selfdoc init no longer invents a version.** A codeless project gets "unversioned": true instead of a placeholder 0.1.0 that was rendered as a topbar badge and offered as a search filter; a project with code whose manifest states no version is refused rather than given a made-up number.
  • [selfdoc] **selfdoc check reports a visible link that names the site's own base.** An <a href> written absolutely against the configured base resolves on the deployed host and nowhere else, so it works on a preview by leaving the preview -- the file-existence half of LINK001 could never see it, because the page it names really is there. It is now reported beside the origin-absolute rule. A project the site mounts under a slug passes that mount to the check, so its subtree is not asked to resolve references into the site around it.
  • [selfdoc] **Fixed: selfdoc quality no longer reports a silent zero when the source-line scan fails.** It read dirstat's output inside a bare except that returned zero LOC on any failure, which graded every project an A on an infinite documentation ratio. A scan that cannot be run, times out, or answers in an unreadable shape is now a hard error naming the cause — submodule subtractions included.
  • [selfdoc] CLI reference pages stop calling every flag a string and every positional argument required. The reader was looking up a type key schema v2 deleted and falling back to str, and a required key an earlier strictcli deleted and falling back to true, so a page could label an int flag str and an optional argument required without anything failing. Both now come from the declaration: value_schema gives the type word (str, bool, int, float, list[T], dict[str, T]) and presence gives a Presence column stating exactly one of required, optional or a default value.

#0.37.2

Dead links between a project's pages and its posts on the unified site

Context

The live deploy refused the assembled tree: a pgdesign documentation page linked its own post at an address inside the project's subtree, and the post linked back at an address at the site root. Both named files no build writes. The engine floor moves to selfdoc-core 0.9.2, which writes each of those references against the root that serves the target.

#Fixes

  • [selfdoc] Documentation built for the unified site no longer carries dead links between a project's pages and its posts. The engine floor moves to selfdoc-core 0.9.2, which addresses a reference crossing the site mount against the root that actually serves it.

#0.37.1

Repairs the unified-site deploy: mounted projects address their posts where the site serves them and stop shipping an unreachable 404, generated reference pages mark extracted code as code and renest doc-comment headings, and the wheel declares its dependency floors.

#Fixes

  • [selfdoc] Declared dependency floors. The published wheel now requires selfdoc-core>=0.9.0 and strictcli>=0.36.0. The 0.37.0 wheel declared a bare selfdoc-core, so a fresh install could resolve a pre-0.9.0 engine that no longer carries the symbols selfdoc imports, and fail at startup.
  • [selfdoc] A mounted project's posts are addressed where the site serves them. A project declaring topology.docs_base and topology.slug is served under its slug, but the assembly serves every project's posts from one shared blog/ at the site root. The build addressed them under the slug anyway, so a post's canonical, its sitemap and feed entries, and every project-page link to it named an address the site does not serve. A project with no mount keeps a self-contained blog, and a posts-only build now renders a post byte-identically to the full build.
  • [selfdoc] A mounted build writes no 404 page. A hosting provider answers an unmatched address from the root of what it serves, so a 404.html buried under a project's slug is never reached. Every mounted project shipped one anyway, and it was an unreachable page that still had to satisfy every assertion made about a page -- it had no canonical, and that blocked the whole site's deploy. A standalone project, whose output root is the served root, still writes its own.
  • [selfdoc] An acronym-prefixed identifier is no longer reported as a misspelling. SPELL001 skips a name with an internal case change, but it recognized only a capital following a lowercase letter -- so TextResponse passed while JSONResponse and HTMLResponse were flagged. A run of capitals meeting a capitalized word is now recognized too.
  • [selfdoc] A code span written with two or more backticks renders as one span. The RST-style x form -- also the form CommonMark requires when the code itself contains a backtick -- was split on single backticks and came out as two empty <code> pairs with the text loose between them. The renderer now shares the pattern the directive scanner and the spell mask already used.
  • [selfdoc] Generated reference pages say which of their text came from code, and a doc comment's headings no longer break the page. Symbol names, module paths, Go flag types and defaults, and SQL object and type labels were emitted as plain prose, so the spell checker read them as English and reported identifiers like JSONResponse and returncode as misspellings an author had no way to fix; they are code spans now, in headings and inline alike. Separately, Go's doc convention writes section titles as # Usage and any language's doc comment can carry markdown headings -- emitted verbatim onto a reference page they became a second H1, which the build refuses, so one such package was enough to stop a project's docs build. Every extractor now renests extracted headings beneath the heading they were emitted under. Docstring prose is unchanged: an identifier written into a sentence is still the author's to backtick.

#0.37.0

check lints posts, spell-checks prose and resolves every link the build emits; init requires the base URL and the author; lint suppression is validated against the registry and reaches warnings only.

Context

One program across all three packages: the site's addressing, the assembly that serves it, and the authoring checks that keep it honest.

Addressing changed first. A page's current version now lives at a stable, unversioned address and superseded versions are archives under v/, declared as such in canonicals, sitemaps and feeds. Posts moved to one site-level blog/ namespace shared by every project. Every link, canonical and sitemap entry the build emits is now resolved against the files it actually wrote (LINK001), and the assembly worker carries a redirect map generated from the manifests, so the retired address schemes still land somewhere real in a single hop.

The assembly stopped being CI shell. The deploy body is a command (assembly integrate), the workflow that calls it is a thin generated artifact whose tool pins are rewritten and checked against PyPI on every sync, and the assembled tree is verified before anything is pushed. Membership is a declared roster with a required home project served at the site root, documentation can be published without a release, and a project can be retired.

The authoring checks grew a spine: every emittable lint code is declared in a registry with its severity, suppression is validated against that registry and can no longer silence an error, posts are linted like pages, and prose is spell-checked -- including the prose a directive renders out of an authored document.

Search switched to Pagefind and the builtin engine was deleted, so search_engine is required and names the one valid value. The author block is required too: one Person is built from it rather than an Organization invented from a directory name.

Breaking changes are minor bumps under the pre-1.0 convention; each is a breaking-type entry in the changelog.

#Breaking

  • [selfdoc] **selfdoc init requires --base-url.** The site's own address cannot be inferred and every canonical link, sitemap entry and feed URL is built from it, so init now takes it explicitly.
  • [selfdoc] Lint severities come from the registry. selfdoc.check.LintResult is the registry's type: it takes no severity argument and refuses a code that is not declared in selfdoc-core's lint registry.
  • [selfdoc] SEO007 holds every page type to one word band. Generated cli-* pages were exempt from the paragraph-length rule entirely; they are now checked like every other page, so a project with generated CLI reference pages will see new SEO007 warnings until their lead-in paragraphs reach 30 words. Only the structural suppressions remain (a heading or short lead-in followed by a directive that supplies the content). The message also names the 30-80 band the rule enforces instead of an unrelated 40-60.
  • [selfdoc] **selfdoc check --ignore refuses a code the lint registry does not carry.** A mistyped code silently suppressed nothing; the flag is now validated against the registry before the check runs, and an unknown code aborts with the list of known codes.
  • [selfdoc] **selfdoc check --ignore and lint_ignore refuse error-severity lint codes.** Suppression reaches warning-severity codes only: naming an error code is a hard error that names the code and its severity, at config load and at flag parse, and the run stops before any checking happens.
  • [selfdoc] **selfdoc init requires --author-name and --author-url.** The scaffolded config declares the author alongside the base URL, because nothing about a person is inferable from a directory.
  • [selfdoc] **Pagefind is the search engine, and search_engine must declare it.** The key is required in selfdoc.json with no default and one valid value, "pagefind"; a config that omits it is refused at load, naming the key. The builtin, Fuse.js and MiniSearch engines are gone, along with the search-index.json file, the search.js bundle and the CDN script tags -- the build runs Pagefind over the finished HTML instead, and Pagefind writes both the index and the search UI into pagefind/. Install it with uv add 'pagefind[bin]'; SEARCH001 now reports a missing indexer on every project.

#Features

  • [selfdoc] **selfdoc init works on projects with no code, and emits a config that builds.** Language detection failing is no longer a refusal: a codeless project gets a config with no source key and a starter page with no extraction directive. Every field load and build require -- base URL, versions, locales -- is written into the file, so the generated configuration needs no hand-editing.
  • [selfdoc] The lint-rule table documents every rule. The Check Guide's table listed only the SEO, staleness, CLI, example and version rules; it is now generated from the lint registry and covers all 42 codes, including the description-quality, cross-reference, parameter, post and unified-site rules.
  • [selfdoc] The blog guide covers publishing without a release, the assembly roster, and retiring a project. New sections explain what a build owns and therefore what it may remove, how roster.toml declares membership, and how a project is unpublished.
  • [selfdoc] **selfdoc init no longer writes the retired indexed key, and selfdoc check runs the new LINK001 resolution check over the built site.** An emitted link, canonical, sitemap entry or feed link that names a file the build did not write is a check error.
  • [selfdoc] The blog guide documents the verification every assembly deploy has to pass. What each assertion checks, what a failure means, how to run the same assertions by hand against a checkout, and how outbound link checking is declared.
  • [selfdoc] **selfdoc check reports the post directive declaration.** A post with no directives declaration is POST006, and a post declaring false that carries a marker is POST007, naming the marker and the line of the post file it sits on.
  • [selfdoc] **selfdoc check lints blog posts.** No path linted them before: check never injected posts into the docs tree, and the build lint pass runs after the injected files are removed, so a post could carry any defect and both surfaces reported nothing. Posts are now held to every page rule, reported at the post file own path and its own line numbers. Drafts and the generated listing page are excluded, matching what the build publishes.
  • [selfdoc] **selfdoc check spell-checks documentation pages and posts.** Every page and every published post is now read for misspellings and reports them as SPELL001 errors naming the file, line and column. Genuine terms -- project names, tool names, technical vocabulary -- go on a shared accept list at ~/Projects/ark/spelling-accept.txt; a missing list simply accepts nothing yet. The new selfdoc spell-corpus command runs the same engine, read-only, over every selfdoc project sitting beside this one, so one sweep surfaces the vocabulary a whole machine uses.
  • [selfdoc] Search ships on every page, with seven filters. The Pagefind dialog opens on Cmd/Ctrl+K from any generated page -- project docs, posts, the blog index, the project listing and the site 404 -- and loads its assets from the index the build wrote, never a CDN. Every page carries filter attributes for version, locale, nav group, page type, deploy target, project and tags, so the dialog offers each as a filter group; tags are emitted one per value, so a page with several appears under all of them.
  • [selfdoc] **The directives reference documents the cv directive**, including the shape of the CV document and every field it validates.
  • [selfdoc] Content a directive renders is spell-checked. A page whose body is a directive -- the CV, the curated project listing -- had none of the text a reader sees scanned, because the source file holds a marker rather than the prose. Live CVs shipped with misspellings nothing reported. Findings now name the document the word was written in (docs/cv.toml, docs/projects.toml) with its line and column there, plus the page it renders into. Names extracted from source code are not reported -- an identifier is not prose.

#Fixes

  • [selfdoc] Assembly deploy documentation matches the deploy. The blog guide now describes selfblog assembly integrate (the deploy body) and selfblog assembly sync-workflow (which regenerates the deployed workflow and its selfblog pin) instead of the retired embedded-shell workflow.
  • [selfdoc] SEO008 stops counting version strings and years as statistics. The numeric-density rule counted any token with a digit, so a page whose only numbers were 0.36.0 and 2026 looked data-rich and the rule stayed silent. Version-shaped tokens (0.36.0, v2, 1.0.0-alpha.1) and bare calendar years no longer count; genuine quantities (42, 3.5, 87%) still do.
  • [selfdoc] Generated index pages and the documentation corpus link pages at the address the site serves them from. The auto-generated API and CLI reference indexes still linked siblings as <page>.html, the form pages took before directory-index URLs, so every link off those two pages resolved inside the index page's own directory and 404'd.
  • [selfdoc] The blog guide gives the address a post is actually served at. It documented /<project-slug>/posts/<post-slug>/, which no build has emitted since posts became site-level: a post is at /blog/<post-slug>/, under no project slug, in one slug namespace every project on the assembled site shares. The published-file record example was stale in the same way.
  • [selfdoc] **selfdoc build prints a message instead of a traceback when the config is invalid.** A present-but-unusable selfdoc.json -- no versions, no locales -- ended the process on an uncaught error; it now reports the problem and exits 1.
  • [selfdoc] SEO doc: no SearchAction. The structured-data list says the homepage WebSite node carries no SearchAction and why.
  • [selfdoc] The documentation site is canonical on the apex. Every other hostname the site is bound to 301s onto it, and the assembly guide documents the routing and the four machine-readable files at the site root.
  • [selfdoc] The configuration reference states the search engine rule. Its table described the three deleted engines and marked search_engine optional.
  • [selfdoc] The contrast check measures the stylesheet the site actually ships. selfdoc check read a packaged copy of the theme CSS that had drifted 58 lines behind the one the build emits, so SEO012 scored colors no page used. It now reads the emitted stylesheet, and the stale copy is gone from the wheel.
  • [selfdoc] **A bad config or an unknown directive stops selfdoc check with a message, not a traceback.** check read selfdoc.json with no handler, so a file build refused cleanly crashed it -- as did a suppression list naming an unknown or unsuppressable lint code, and a page carrying a directive nothing answers. All of them now print one Error: line and exit 1.

#0.36.0

Generated CLI reference pages carry effects metadata, and selfdoc check executes validate-marked examples instead of merely parsing them.

Context

Two gaps closed in the same visit.

Generated cli-*.md pages threw away every effects field the strictcli schema carries. A reader of the published docs could not learn that a command was consequential, what it would refuse to do under --dry-run, or which dangerous steps it had authored grant reasons for -- the first notice was a CI job dying on a confirmation prompt. The pages now render the effect classification, the consequential badge with --approve-consequential, the dry-run-unsupported reason and the grants table, and the index gains global flags, the reserved framework-flag quartet, infrastructure and deprecated sections.

Separately, code blocks in documentation were only ever parsed for syntax, so an example that parsed but could not run shipped looking correct. A block marked validate is now assembled and executed through the validator its language declares under the new examples config key; a failing run is EXAMPLE002 with the validator's output, and a validate marker with no configured command is EXAMPLE003 rather than a silent skip. Unmarked blocks are unaffected and are never executed.

Also: schemas/check-output.schema.json now enumerates every lint code selfdoc check emits and declares the two coverage fields it was omitting, so consumers validating or generating types from the JSON output stop losing data.

#Features

  • [selfdoc] Effects metadata in CLI reference pages. Generated cli-*.md pages now show each command's strictcli effect classification, a consequential badge naming --approve-consequential, a dry-run-unsupported note with its reason, and a Grants table. The CLI index gains Global flags, Framework flags (the reserved --dry-run/--approve-consequential/--quiet/--verbose quartet), Infrastructure and Deprecated sections.
  • [selfdoc] Examples are executed, not just parsed (EXAMPLE002/EXAMPLE003). selfdoc check now runs every code block marked validate through the validator configured for its language under examples, reporting a failing exit as EXAMPLE002 with the validator's output tail. A marker with no configured command is EXAMPLE003 rather than a silent skip. Unmarked blocks keep the syntax-only EXAMPLE001 behavior and are never executed.
  • [selfdoc] Documented the portfolio canonical. The blog guide gains a section explaining why an assembly's portfolio page names the apex rather than topology.docs_base as its canonical, and how assembly.portfolio_canonical reaches the generated deploy workflow.

#Fixes

  • [selfdoc] JSON output schema accepts all current lint codes. schemas/check-output.schema.json enumerated only the SEO and STALE001 codes, so consumers validating selfdoc check --format json rejected output containing EXAMPLE, DQ, PARAM001, RETURN001, DRIFT001 and other current codes. The enum now covers every emitted code.
  • [selfdoc] JSON output schema declares all coverage fields. schemas/check-output.schema.json omitted the documented and documented_symbols fields that selfdoc check --format json emits, so consumers generating types from the schema silently lost both.

#0.35.0

selfdoc adopts strictcli's effects regime: every command is classified, --dry-run previews instead of executing, deploy asks before it runs, and --yes is replaced by --approve-consequential

Context

selfdoc's dry-run used to be a per-command courtesy: some commands honoured it, some quietly ignored it, and nothing in the code stopped a handler from shelling out anyway. This release moves that guarantee into the framework. Every command now declares whether it is read-only or mutating, and every subprocess launch and filesystem write goes through a single chokepoint, so --dry-run records a numbered would-do log instead of performing the work -- a dry deploy names the Cloudflare project it would push to rather than pushing to it.

The confirmation story changed with it, and it is worth explaining why the flag is new. strictcli originally inferred "prompt the user" from "this command mutates something", which turned out to catch about two thirds of every CLI in the fleet -- including commands nobody wants to confirm. A prompt that fires on two thirds of invocations trains people to dismiss it, which is exactly the reflex a confirmation is supposed to prevent. So consequence is now declared per command rather than inferred, and only the commands that earn it prompt. In selfdoc that is exactly one: deploy, the only command whose effects leave the machine and land on a live public site.

--yes is gone rather than deprecated. yes is now a banned flag name framework-wide, so selfdoc <cmd> --yes is a hard "unknown flag" error instead of a silent no-op. The replacement is --approve-consequential, deliberately unwieldy so it cannot decay into muscle memory the way -y did, and self-documenting wherever it appears in a script. The practical migration is smaller than it sounds: the mutating commands that used to demand --yes from every non-interactive caller now need no flag at all.

#Breaking

  • [selfdoc] **Every command is classified, and --dry-run now previews instead of executing.** selfdoc rides strictcli's effects regime: each command declares itself read_only or mutating, and every subprocess launch and filesystem write routes through a single effects chokepoint. selfdoc <cmd> --dry-run records what the command would do and prints a numbered would-do log -- a dry deploy names the Cloudflare Pages deployment or the gh-pages force-push (with the reason it is granted) without performing either. Two consequences to plan for: mutating commands now ask for confirmation, so non-interactive callers (CI, release hooks, scripts) must pass --yes or they exit with stdin is not interactive; and selfdoc check's own --dry-run flag is gone, replaced by the framework flag of the same name -- the reserved names --dry-run, --yes, --quiet and --verbose now belong to the framework and are accepted anywhere in argv.
  • [selfdoc] **selfdoc deploy now asks before it runs.** It is the one selfdoc command whose effects leave the machine and land on a live, publicly-visible site: a Cloudflare Pages deployment is live the moment it lands, and the GitHub Pages provider force-pushes gh-pages, so the previously published tree is gone from the remote. It is declared consequential, so the framework prompts before dispatch and refuses on non-interactive stdin. Pass --approve-consequential from scripts, CI and release pipelines. Every other selfdoc command -- gen, build, check, init, serve, gen-data, baseline accept -- is unaffected and still runs bare.
  • [selfdoc] **--yes is gone; the confirmation-skip flag is --approve-consequential.** strictcli 0.36.0 replaced the inferred "mutating command means prompt" rule -- which caught two thirds of every CLI in the fleet -- with a per-command consequential declaration, and the framework now prompts only for commands that make it. yes is a banned flag name, so selfdoc <cmd> --yes is a hard unknown flag error rather than a no-op. In practice this means the mutating commands that used to demand --yes from every non-interactive caller now need nothing at all.

#0.34.0

Extractor coverage fixes (re-exports, module constants, docstring-less/pydantic classes), new selfdoc quality command, configurable coverage_threshold, three new guides, plus breaking removal of post/assembly subcommands and new explicit deploy-target and assembly config keys

Context

Coordinated minor batch release; the previous batch shipped 2026-07-11. This ships roughly three weeks of accumulated backlog for the selfdoc CLI.

Breaking changes in this batch: the selfdoc post and selfdoc assembly subcommand stubs are gone (that surface lives in selfblog now); deploy_github_pages requires an explicit target instead of inferring it from the current directory's origin; and the assembly config keys changed (topology.assembly is rejected in favour of assembly.repo, and assembly.pages_project is now required).

Features: a new selfdoc quality command scoring documentation on a 0-5 tier scale, a configurable coverage_threshold in selfdoc.json, the gen --version-override release handshake, and new directives/quality/blog guides. Fixes tighten ref coverage accounting (re-exports and module constants are now counted, docstring-less and pydantic classes are no longer dropped), make manifest generation idempotent so --no-allow-dirty releases stop looping, honour package-level excludes, and add remediation hints to DRIFT001/STALE001.

#Breaking

  • [selfdoc] **deploy_github_pages requires an explicit target.** The re-exported selfdoc.deploy.deploy_github_pages now takes a required target keyword instead of force-pushing to whatever origin the current working directory resolves to. selfdoc deploy itself is unchanged.
  • [selfdoc] **selfdoc post and selfdoc assembly are gone.** The ten stub subcommands that only printed "moved to selfblog" are deleted; use the selfblog CLI, which has owned these commands since selfblog was split out. Removing them also un-pollutes selfdoc's strictcli schema, so README's command table is generated from the live schema again instead of being hand-maintained.
  • [selfdoc] Assembly config keys changed. topology.assembly is rejected outright (use assembly.repo), assembly.pages_project is now required for projects that publish into an assembly, and topology.legacy_blog_host is new. topology.posts_base now means the canonical blog URL under the docs site, not a separate blog host.

#Features

  • [selfdoc] Version-override handshake. selfdoc gen --version-override <v> stamps an explicit project version into version-bearing generated root files, and selfdoc check --version-override <v> states the version they are expected to embed. Release orchestrators pass the about-to-be-released version so generated files are no longer committed one release behind. The new VER004 check turns a stale embedded version into a hard failure instead of a silent lag.
  • [selfdoc] **coverage_threshold in selfdoc.json.** New optional float field (0.0-1.0, default 1.0) setting the minimum fraction of public symbols that must be documented for selfdoc check to pass. Lower it below 1.0 to accept partial coverage.
  • [selfdoc] **New selfdoc quality command.** Scores a single project on a 0-5 documentation tier scale with a letter content grade (documentation-to-code ratio, excluding test LOC and templates) and prints the next tier's requirement as concrete guidance.
  • [selfdoc] Three new guides. Added a directives guide, a quality/tier guide, and a blog-post authoring guide to the documentation.

#Fixes

  • [selfdoc] Docs. README now documents post/assembly as selfblog commands.
  • [selfdoc] Coverage respects package-level excludes. A gen.exclude package path (e.g. a vendored package) now excludes its files from coverage counting, matching gen's behavior; previously excluded Go packages leaked into coverage as unreferenced symbols and could fail the coverage threshold.
  • [selfdoc] No more STALE001 on every release. The generated CLI index page now renders its version through a var directive instead of a baked literal, so a version bump no longer moves the page's content hash. Projects that hit STALE001 on the CLI index at every release -- and had to run selfdoc baseline accept each time -- no longer do.
  • [selfdoc] DRIFT001 tells you how to resolve it. Drift errors reported by selfdoc check now end with a remediation hint naming selfdoc baseline accept <page>, so an operator whose description is genuinely still accurate has a stated way out instead of having to invent a description edit.
  • [selfdoc] Release-time version handshake is documented. The rlsbl integration guide now covers gen --version-override / check --version-override and the VER004 check, and the staleness guide no longer claims that a page embedding project.version via a var directive changes its content hash on every release (it does not -- the content hash has used the raw template body since hash schema v2).
  • [selfdoc] **selfdoc.quality is documented.** Every public function in the quality-scoring module -- tier computation, content grading, the LOC counters, and the report formatters -- now carries a docstring, so its API reference page has real content instead of bare signatures.
  • [selfdoc] The dependency claims in the docs are true now. The README, homepage, getting-started guide, and comparison page each claimed selfdoc had one runtime dependency (or zero); it has two direct ones -- strictcli and selfdoc-core -- which bring strictspec and tomlkit. All four are pure Python, and the pages now say exactly that.
  • [selfdoc] The check guide's lint-code table is complete. It listed only the SEO rules and STALE001; the codes selfdoc check can actually emit -- DRIFT001, STALE002, CLI001, CLI002 and VER001-VER004 -- now have rows too, each with its severity and how to clear it.
  • [selfdoc] **ref output now counts __init__.py re-exports and module-level constants.** The Python extractor emitted ### headings only for classes and functions, so __all__ re-exports (from ._impl import X) and module-level constants (__version__) were structurally uncountable in coverage even though they sit in the denominator. They now get headings, and ref target=X resolves a name that is only a re-export instead of erroring not found.
  • [selfdoc] **Docstring-less public classes are no longer dropped from ref output.** A public class with no docstring, no methods, and no @dataclass decorator was silently omitted. Any class named in __all__ now always renders at least a heading and signature, and pydantic BaseModel subclasses get the same field-table rendering as dataclasses.
  • [selfdoc] **selfdoc gen no longer rewrites .selfdoc/manifest.json when nothing changed.** The manifest was rewritten on every run because its last_gen timestamp always differs, dirtying the working tree and breaking --no-allow-dirty release flows in a retry loop. It is now written only when its content (ignoring the timestamp) actually changes.

#0.33.0

table-commands discovers the strictcli schema automatically (path attribute removed; schema-dir disambiguates multi-schema repos)

Context

Phase 9.5 coordinated breaking release. table-commands no longer accepts a path attribute; it auto-discovers the unique .strictcli/schema.json by walking the project root, with an optional schema-dir attribute to disambiguate repos that carry more than one schema. Directive attribute handling is now strict across gen and check: an unknown or missing attribute is a hard error (exit 1) reporting the file, line, directive, and allowed attributes.

Because table-commands path removal is a breaking directive change, all in-tree docs and the eight external consumer repositories that use table-commands were migrated to the new bare-directive syntax in lockstep before this release, so no consumer is left on a directive that would now hard-error.

#Breaking

  • [selfdoc] Strict directive attributes. selfdoc check and selfdoc gen now hard-error (exit 1) when a directive uses an unknown attribute or omits a required one, reporting the file, line, directive, and allowed attributes.
  • [selfdoc] table-commands auto-discovers the CLI schema. table-commands no longer takes path; it finds .strictcli/schema.json by walking the project root. Migration: drop path, and if discovery is ambiguous add schema-dir="<dir>".

#0.32.0

Description ownership by content: handwritten text is never overwritten; machine placeholders identified by hash/template/live-recompute

Context

gen now classifies a page's description text itself -- via current/historical module templates, the per-page seed hash, or a live recompute of CLI defaults -- instead of trusting the seeded flag. Hand-rewritten descriptions survive regeneration even with a stale seeded:true marker, and the STALE001/DRIFT001 exemption keys on the ownership predicate so hand-described generated pages get full staleness protection.

#Fixes

  • [selfdoc] Hand-written descriptions on generated pages are never overwritten. selfdoc gen now decides whether to reseed a description by classifying the text itself, so a description you rewrote by hand survives regeneration even if a stale seeded: true marker was left behind.
  • [selfdoc] Hand-described generated pages get full stale-description protection. The STALE001/DRIFT001 exemption now applies only to pages whose description is genuinely machine-generated, so a generated page you have described by hand is checked for staleness like any other page.
  • [selfdoc] **A legacy auto-generated API reference index description is refreshed on selfdoc gen.** Projects still carrying the old "Complete auto-generated API reference index …" placeholder now have it reseeded with a project-specific description instead of being frozen as if hand-written.

#0.31.0

New name config key, gen-index naming fix, legacy description reseed, CLI defaults are now complete sentences, and the list-features directive is removed (migrated to list-modules).

Context

Descriptions are handwritten-first with machine placeholders: auto-seeded page and CLI descriptions are recognizable so they can be reseeded, while hand-authored frontmatter is left verbatim. The old 155-character truncation produced mid-sentence cuts, so machine placeholders are now complete first sentences. list-features is superseded by list-modules, which yields richer module summaries.

#Features

  • [selfdoc] Auto-seeded page descriptions are complete sentences. Generated module page descriptions now carry the whole first sentence of the docstring, no longer capped at 155 characters or cut with an ellipsis.

#Fixes

  • [selfdoc] SEO009 no longer misfires on wrapped first lines. The advisory description-length check now measures the complete first sentence of the opening paragraph (wrapped lines joined) instead of just the first physical line, so pages with a long but soft-wrapped opening sentence no longer get a spurious 'description too short' warning.
  • [selfdoc] CLI page descriptions are the complete first sentence of the help text. Auto-generated strictcli command and group reference pages now seed the full first sentence instead of a 155-character mid-sentence cut, and pages still carrying the old truncated default are correctly re-seeded rather than frozen as if hand-edited.

#0.30.0

gen-index descriptions: correct project naming, legacy wrong descriptions self-heal; no more phantom STALE/DRIFT on generated pages.

#Fixes

  • [selfdoc] Correct API reference index description. selfdoc gen no longer bakes an arbitrary source folder's name into the API reference index for multi-source projects (it uses the configured name or a generic phrasing), and it now refreshes index pages that still carry the old hardcoded description instead of preserving it forever.
  • [selfdoc] No more phantom staleness errors on auto-generated pages. selfdoc check no longer reports STALE001/DRIFT001 on skeleton (generated + seeded) pages whose source changed -- those pages advance automatically instead of being stuck in an unfixable error.

#0.29.0

baseline accept command and gen-index staleness fix

Context

Adds selfdoc baseline accept for clearing staleness dead-ends on pages with dynamic content. Fixes gen-index to use content-aware seeded descriptions, preventing STALE001 deadlocks on generated index pages.

#Features

  • [selfdoc] **selfdoc baseline accept <page>...**. New command to clear a STALE001/DRIFT001 dead-end when a page's content changed but its existing frontmatter description was reviewed and is still accurate (e.g. pages embedding project.version that change every release). It advances the named pages' hash baselines exactly as if the description had been rewritten. Pages are named explicitly (no --all/glob/--force); accepting a page that does not exist, has no baseline, or is not currently stale/drifted is a hard error.

#Fixes

  • [selfdoc] Fix. gen-index description is now content-aware with a seeded marker, preventing STALE001 deadlocks on generated index pages.

#0.28.1

Fix CI: install playwright browsers before running tests, fix publish gate regex

Context

v0.28.0 CI failed because playwright browsers were not installed. The publish gate regex also did not match the actual CI job name. Both are fixed.

#Fixes

  • [selfdoc] Fix CI. Install playwright browsers before running tests so CI passes and the package publishes to PyPI.

#0.28.0

Monorepo conversion with three independent packages (selfdoc, selfdoc-core, selfblog).

#Breaking

  • Blog functionality moved to selfblog. Post discovery, post checks (POST001-POST005), and the unified multi-project check now live in the selfblog package. selfdoc post/selfdoc assembly commands temporarily delegate to selfblog (install with pip install selfblog); selfdoc check on unified projects now hard-errors and directs to selfblog check. New selfblog check command validates posts and unified sites.
  • [selfdoc] Packaging split. pip install selfdoc no longer bundles the selfdoc_core and selfblog packages: selfdoc-core is now a regular dependency, and selfblog is a separate optional install. The selfblog console script moved to the selfblog package -- install it with pip install selfblog. The perf/og extras now route to selfdoc-core[perf]/selfdoc-core[og].
  • [selfdoc] selfdoc post/assembly commands removed -- use the selfblog CLI (pip install selfblog). Unified and posts-only builds through selfdoc build/serve now hard-error directing to selfblog

#0.27.0

Three-package architecture (selfdoc_core + selfdoc + selfblog), forced-rewrite staleness, per-language list-modules, post revisions.

Context

Splits the codebase into three packages: selfdoc_core (shared build engine and extractors), selfdoc (CLI and documentation generation), and selfblog (blog assembly and CLI). This sets up the future monorepo conversion. Staleness detection gains baseline-hold semantics (baseline does not advance while errors remain), schema-hash gating with seeded markers for CLI pages, and root-file template validation. The list-modules directive now groups modules by language with extractor summaries. Post infrastructure adds a revisions sidecar (content-hash gated revision tracking) and localStorage read indicators. Manifest loading uses a tolerant-reader contract with centralized compatibility checks for forward-compatible schema evolution.

#Features

  • Root-file template validation. selfdoc check now validates directives in root-file templates (docs/_CLAUDE.md, docs/_README.md).
  • Staleness baseline freeze. Baseline does not advance while errors are outstanding, preventing silent degradation.
  • CLI page schema-hash gating. Staleness detection uses seeded markers for CLI page schema hashes, preventing false positives on unchanged content.
  • Module listing improvements. Per-language grouping with extractor summaries and hard error for unsupported languages.
  • Three-package architecture. Split into selfdoc_core (shared engine), selfdoc (CLI + docs), and selfblog (blog + assembly). Modules moved to their owning packages with re-export shims for backward compatibility.
  • selfblog CLI entry point. New python -m selfblog CLI with post (new, list, generate, publish), assembly (init, push, status, rebuild, generate-shared), and build commands. Per-package pyproject.toml files for future monorepo conversion.
  • Tolerant-reader manifest contract. Centralized compatibility check for manifest schema versions, allowing older readers to process newer manifests safely.
  • Post revisions sidecar. Content-hash gated revisions.json tracks edit history per post with automatic revision capture on content changes.
  • Read indicators. Posts track read status in localStorage, enabling visual distinction between read and unread content.

#0.26.1

Assembly workflow cleanup and posts.repo configuration.

#Fixes

  • Assembly workflow cleanup. Removed the 42-line inline Python fallback for selfdoc <= 0.24.0, simplifying the assembly CI workflow.

#0.26.0

Posts repo archival, blog redirect via Pages Function, assembly workflow fixes.

#Features

  • Posts repo archival. New posts.repo config field archives resolved post content to a git repo during post publish.
  • Blog redirect via Pages Function. Replace Cloudflare Pages _redirects with _worker.js for host-specific blog.smmh.dev redirect.

#Fixes

  • Assembly workflow fix. Pass --docs-base to generate-shared in the assembly workflow.

#0.25.1

Fix VER001 for assembly builds, Playwright CI setup, test fixes.

#Fixes

  • VER001 version filter. selfdoc build --version X no longer validates old versions that can't be extracted from shallow clones, fixing assembly builds for multi-version projects like claudestream.
  • Playwright CI. CI workflow now installs Playwright browser binaries, fixing 75 test errors that blocked the v0.25.0 publish.

#0.25.0

Local post publish, portfolio homepage, monorepo labels, and blog URL fixes.

#Features

  • Local post publish. selfdoc post publish now builds posts locally and pushes directly to the assembly repo via Git Data API, eliminating the requirement to push to the project's remote. Posts can be published without software releases.
  • Portfolio homepage. selfdoc assembly generate-shared gains --portfolio-file flag to use a custom HTML file as the site homepage. Project listing moves to /projects/.
  • Monorepo label. Projects with version 0.0.0 show 'monorepo' instead of a version badge on the homepage.

#Fixes

  • Dependency installation no longer requires machine-local checkouts: uv.lock previously carried local paths for strictcli and predraw, breaking installs and CI outside the author's machine. Dependencies now resolve from PyPI (strictcli 0.24.0, predraw 0.2.1).
  • Python version requirement corrected. requires-python bumped from >=3.11 to >=3.12 to match actual compatibility (CI tests 3.12/3.13/3.14 only; codebase uses PEP 701 syntax). Dead tomli fallback code removed; ruff config added with target-version = "py312".
  • Expanded CLI help text. All command and flag help strings now meet the 50-character minimum for documentation quality checks.
  • Expanded CLI command help text. All command help descriptions now meet the 40-60 word target for AI citation quality, and include numeric data points where applicable.
  • Blog index URLs. Fixed broken blog post URLs where project slugs were treated as hostnames.

#0.24.0

Migrated all boolean CLI flags to explicit-default style via strictcli.

Context

All bool flags now use --flag/--no-flag syntax with explicit defaults, following the strictcli migration. --no-commit renamed to --auto-commit, --dry-run and --drafts require explicit values, --from-release is now required.

#Breaking

  • Breaking: --no-commit renamed to --auto-commit (default=True). --dry-run and --drafts now require explicit defaults. --from-release is now required.

#0.23.0

Posts-only build mode and post publish command for publishing blog posts without software releases.

#Features

  • Posts-only build. New --target posts flag on selfdoc build for building only blog posts without the full documentation site. Used by the assembly CI for publishing posts without a software release.
  • Post publish command. New selfdoc post publish dispatches blog posts to the documentation assembly without requiring a version bump. Validates posts are committed and pushed before dispatching.

#Fixes

  • Assembly workflow robustness. Multi-version projects with failed version detection now error clearly instead of silently attempting a full build. Post-manifest overlays enable updating posts independently from docs.

#0.22.1

Fix null manifest fields crashing assembly shared element generation.

#Fixes

  • Fix. Assembly shared element generation no longer crashes when manifest fields are null.

#0.22.0

Assembly Stage 2: multi-project site aggregation with shared elements, search indexing, and persistent combined site.

Context

Rewrites the assembly workflow to implement Solution 10: the assembly repo stores the complete combined site. Each dispatch replaces one project's subtree, regenerates shared elements (homepage, blog index, navigation, feeds, sitemap), runs Pagefind for cross-project search, and deploys the full site to Cloudflare Pages.

#Features

  • Assembly Stage 2. New selfdoc assembly generate-shared command and rewritten assembly workflow for multi-project site aggregation. Each dispatch now surgically updates one project, regenerates shared elements (homepage, blog index, nav, feeds, sitemap, search), commits the combined site, and deploys.

#Fixes

  • CF Pages deploy fix. Deploy to the correct Cloudflare Pages project name (smmh instead of docs-smmh-dev).

#0.21.1

Fix auto-commit with gitignored files, fix inline directive regex, add directive name validation

#Features

  • New. Inline directives now validate names against known directives, matching existing behavior for standalone and block directives. Custom directive names in selfdoc.json are validated at load time.

#Fixes

  • Fix. Auto-commit no longer silently fails when gitignored files are in the commit list. Gitignored files are filtered out and commit errors are now visible on stderr.
  • Fix. Inline directives no longer capture trailing punctuation. (v:-: name). now resolves correctly instead of greedily capturing name). as the directive name.

#0.21.0

Posts system, page types, unversioned pages, deployment topology, assembly infrastructure, Pagefind search, and shared elements for multi-project documentation sites.

Context

This release introduces a complete blog/posts system integrated with rlsbl releases, a page type system with configurable schema.org mappings and per-type layouts, unversioned pages for content that persists across doc versions, a deployment topology config for multi-project unified sites, an assembly system that manages a throwaway GitHub repo for aggregated documentation deployment to Cloudflare Pages, Pagefind as a new search engine option with chunked indexes and filtering, and shared elements generation (homepage, blog index, nav, feeds, sitemap) for assembled sites.

#Features

  • Page type system. Frontmatter-driven page types with configurable schema.org mapping, per-type layout control, and type-aware labeling.
  • Unversioned pages. Pages with versioned: false frontmatter build at stable URLs outside the version path, with persistent navigation and search inclusion.
  • Blog posts. New posts system with selfdoc post new, selfdoc post list, selfdoc post generate --from-release, date-based navigation, auto-generated listing page, type-aware feed ordering, draft support, and lint rules POST001-POST005.
  • Deployment topology. Configurable multi-project URL generation with TopologyURLBuilder, cross-project linking, and topology-aware var directives.
  • Assembly system. selfdoc assembly init/push/status/rebuild commands for managing a unified multi-project documentation site deployed to Cloudflare Pages.
  • Shared elements generator. Homepage, blog index, global navigation, unified Atom feed, sitemap, and cross-project link validation for assembled sites.
  • Pagefind search engine. New pagefind option for search_engine config with chunked lazy-loaded indexes, Cmd/Ctrl+K shortcut, and filtering by project, type, version.
  • Topology migration script. scripts/migrate_topology.py for applying topology config across multiple projects.

#Fixes

  • Bug fixes. Wire schema_types to generate_html, propagate topology URLs to auxiliary files, fix nested index.md URL segments, inject posts for constituent projects in unified builds, fix cross-project link validation for URL-form paths.

#0.20.0

ref+target single-symbol rendering, Go dotted method names, expanded CLI help texts.

Context

ref directives now respect the target attribute across all 9 extractors, rendering a single symbol instead of the entire module. This makes PARAM001/RETURN001 checks reachable for targeted documentation. Go public_symbols returns Type.Method for methods, fixing collision bugs. CLI help texts expanded across selfdoc, rlsbl, safegit, and wesktop to satisfy CLI002.

#Features

  • New feature. ref directives now support the target attribute to render a single symbol instead of the entire module.

#Fixes

  • Bug fix. Go public_symbols now returns dotted Type.Method names for methods, fixing collision when two types share a method name.

#0.19.1

Remove version_source config field (redundant with rlsbl).

Context

version_source was added in v0.16.0 to read the project version from manifest files. Investigation revealed rlsbl already bumps selfdoc.json during releases via _bump_selfdoc_version, making version_source redundant. Reverted to reduce complexity.

#Breaking

  • Breaking. Removed version_source config field. rlsbl already handles selfdoc.json version bumping during releases.

#0.19.0

Dotted target syntax, TS re-export fix, CLI002 lint, gen.py protocol integration, coverage matching fix, and TS module JSDoc fix.

Context

symbol_details across all extractors now supports Type.Method dotted targets for class member disambiguation. TypeScript _extract_exports handles export { X } re-exports. Coverage matching uses heading-based regex instead of fragile substring check. gen.py uses module_docstring protocol for all 9 languages (7 gained auto-descriptions). CLI002 validates help text length. TS _extract_module_jsdoc no longer misclassifies function JSDoc as module-level.

#Features

  • New lint. CLI002 warns when CLI help texts are shorter than 50 characters (commands, flags, args, and group subcommands).
  • All languages get auto-extracted descriptions. gen now uses the module_docstring protocol method for all extractors instead of hardcoded Go/Python paths. TypeScript, Zig, Swift, Kotlin, Svelte, Dart, and SQL pages now show real module descriptions.

#Fixes

  • Fixed. TypeScript module-level JSDoc detection no longer misidentifies function-attached JSDoc as module documentation.
  • Fixed. Coverage computation no longer falsely matches symbols that are substrings of other symbol names.
  • Fix. TypeScript ref output now includes re-exported symbols (export { X } and export { X } from '...'), fixing coverage reports that showed them as undocumented.

#0.18.0

module_docstring and symbol_details protocol methods for all extractors, handler signature refactor, and inline directive fixes.

Context

Handler functions now receive path and target as separate arguments, eliminating the latent arg-combining bug. module_docstring protocol method replaces language-string dispatch in staleness.py, enabling DRIFT001 across all languages. symbol_details implemented for all 9 extractors, enabling PARAM001/RETURN001 cross-language. Double-backtick inline directive spans now masked correctly. Inline pass 2 fixed to split multi-line resolver output before fence tracking.

#Breaking

  • Breaking. Handler functions now receive path and target as separate arguments instead of a combined string.

#Features

  • TypeScript extractor. Implement symbol_details method for extracting function parameters, types, return types, and JSDoc documentation status.
  • Swift extractor. Implement symbol_details for function parameter, return type, and documentation extraction.
  • Go extractor. Implement symbol_details for extracting function parameter types, return types, and documentation status from Go source files.
  • Zig extractor. symbol_details method for function parameter and return type extraction.

#Fixes

  • Fix. table-commands directive now correctly joins path attribute with base_dir for monorepo sub-project schema lookup.
  • Fix. Inline directives inside double-backtick code spans are no longer resolved.
  • Fixed inline directive resolution inside code fences. Directives shown as examples inside code fences in resolved content (e.g., the catalog directive's output) were incorrectly matched and resolved by pass 2, causing errors like 'list-modules returned multi-line output'. Fence tracking now correctly handles multi-line resolver output.

#0.17.0

Inline directives, 10 new doc quality checks, XREF002 Go fix, and ecosystem deployment.

Context

Five new lint codes (EXAMPLE001, CLI001, DRIFT001, PARAM001, RETURN001) complete the doc quality pipeline. Inline directive support enables mid-line dynamic values via a two-pass resolver. Protocol extended with symbol_details() and structural docstring parser. XREF002 fixed for Go package directories. Ecosystem: version_source migrated to 17 projects, extractors deployed to incantino/F/gamehome.

#Features

  • New feature. CLI001 lint checks CLI reference completeness for strictcli-based projects.
  • New feature. EXAMPLE001 lint validates Python and JSON syntax in code blocks.
  • New feature. DRIFT001 lint detects when source docstrings change without corresponding documentation updates.
  • New feature. PARAM001 lint warns when function parameters are not documented.
  • New feature. RETURN001 lint warns when return types are not documented.
  • New feature. Inline directive support: self-closing directives can now appear mid-line for dynamic values in prose.

#Fixes

  • Fix. XREF002 no longer fires false positives on Go package paths (directories).

#0.16.0

Five new language extractors (Swift, Kotlin, Svelte, Dart, SQL), version_source config, and doc quality checks.

Context

This release adds five new language extractors: Swift (doc comments, struct schemas, public symbol detection), Kotlin (KDoc parsing), Svelte (component props, instance/module exports, JSDoc), Dart (class/mixin modifiers, doc comments, part file following, export following with show/hide combinators), and SQL (PostgreSQL DDL -- CREATE TABLE/VIEW/TYPE/FUNCTION and COMMENT ON). It also introduces the version_source config field for reading the project version from the primary manifest, and four new doc quality lint checks: XREF001 (internal page link validation), XREF002 (directive path validation), DQ001 (description restates symbol name), DQ002 (description too short), and DQ003 (function-referencing pages need substantive descriptions). Several base extractor utilities were refactored into shared helpers to reduce duplication across extractors.

#Features

  • New feature. version_source config field for reading version from primary manifest.
  • New feature. Swift language extractor with doc comment parsing, struct schema extraction, and public symbol detection.
  • New feature. Kotlin language extractor with KDoc parsing.
  • New extractor. Svelte language extractor for component documentation -- extracts props, instance/module exports, and JSDoc from .svelte files.
  • New feature. Dart language extractor with class/mixin modifier detection, doc comment parsing, part file following, and export following with show/hide combinators and cycle detection.
  • New feature. SQL schema extractor for PostgreSQL DDL -- parses CREATE TABLE/VIEW/TYPE/FUNCTION statements and COMMENT ON documentation from .sql files.
  • New feature. XREF002 lint check -- verifies that resolved directive source files actually exist on disk.
  • New feature. Doc quality checks: XREF001 (broken page links), DQ001 (restated description), DQ002 (short description), DQ003 (missing function info).

#Fixes

  • Fix. Svelte detection now runs before TypeScript in auto-detection order, preventing Svelte projects from being misidentified as TypeScript.

#0.15.1

Fix pipe escaping in unclosed backtick spans.

#Fixes

  • Bug fix. Pipes inside unclosed backtick spans in table cells are now correctly escaped.

#0.15.0

Generic markdown table renderer as public API, with full internal refactoring.

Context

Added render_markdown_table in selfdoc.tables -- a public utility for custom directive authors to render markdown tables with alignment, pretty-print, and pipe escaping. Refactored all 25 internal table-building callsites to use it, eliminating duplicated table construction across extractors, content directives, and strictcli support. Also updated html.py to handle escaped pipes and alignment markers in table parsing.

#Features

  • New utility. render_markdown_table in selfdoc.tables -- public API for rendering markdown tables with alignment support, pretty-print mode, and backtick-aware pipe escaping.
  • Init command. Detects all languages in multi-language projects for config generation.

#0.14.1

Exclude Python test files from coverage

#Fixes

  • Fix. Python test files (test_*.py, conftest.py) and test directories (tests/, test/, __tests__/) are now excluded from documentation coverage, matching what selfdoc gen already excluded.

#0.14.0

Stub extractors for unsupported languages, skip .venv in source walks, remove javascript alias

#Breaking

  • Breaking. Removed javascript alias from the extractor registry. Use typescript for both TypeScript and JavaScript files.

#Features

  • New feature. Unsupported languages in source entries get a stub extractor instead of a config error. Supported languages work normally alongside unsupported ones. LANG001 lint error reports which source paths lack an extractor.

#Fixes

  • Fix. Source walks now skip .venv, node_modules, __pycache__, and other non-source directories. Previously, a .venv/ inside a source path would generate hundreds of doc pages for third-party packages.

#0.13.1

Fix Go root package ambiguity in multi-language projects

#Fixes

  • Fix. Go root packages in multi-source-path projects no longer crash with ambiguity errors. Each source path's root package gets a unique qualified path instead of the ambiguous path=".".

#0.13.0

Multi-language project support and Zig extractor

#Breaking

  • Breaking. Top-level language config field removed. Each source entry is now an object with path and language fields: {"path": "src/", "language": "python"}.

#Features

  • New feature. Zig language extractor with support for pub fn, pub const, pub var, struct/enum/union declarations, /// doc comments, //! module docs, and test block extraction.
  • New feature. Resolver dispatches directives to the correct language extractor based on source path. Cross-language path ambiguity is detected and errors.
  • New feature. selfdoc gen and selfdoc check work across multiple languages in a single project. Coverage enforcement applies to all languages -- undocumented symbols in any language cause failure.
  • New feature. list-modules directive auto-detects language from source path. project.language variable returns comma-separated list for multi-language projects.

#0.12.0

100% coverage enforced. selfdoc check now requires all public symbols to be documented on non-skeleton pages. The min_coverage config field is removed.

#Breaking

  • 100% coverage enforced. selfdoc check now requires all public symbols to be documented on non-skeleton pages. The min_coverage config field is removed.

#Features

  • Extractor accuracy. Python extractor respects __all__ for public symbol detection. Go extractor handles exported symbols inside const() and var() blocks.
  • Stale file tracking. selfdoc gen now tracks and commits deleted stale doc files alongside newly generated ones.
  • Schema provenance. selfdoc gen and selfdoc check validate that .strictcli/schema.json belongs to the current project via a project_id field.

#Fixes

  • Hash consistency. selfdoc gen updates content hashes after generating, eliminating the 'run check twice' ritual. Gen, check, and build now use consistent locale-prefixed hash keys.
  • Skeleton-only display. selfdoc check now shows which symbols are only referenced on skeleton pages when documented coverage is below 100%.
  • Wider lint suppression. lint_ignore config now accepts all lint code formats (e.g., STALE001, VER002), not just SEO codes.
  • Safer stale cleanup. Stale generated files are now deleted after new files are written, preventing data loss if generation fails midway.
  • Git command safety. All git subprocess calls use -- separator before filenames, preventing filenames from being mistaken for git options.

#0.11.0

New feature. Config-driven redirects for renamed/deleted doc pages. Add a redirects list in selfdoc.json with {from, to} page slugs — the build expands across all locale/version combos, generating both Cloudflare _redirects rules and HTML meta-refresh pages. Existing pages in cached old versions are preserved.

#Features

  • New feature. Config-driven redirects for renamed/deleted doc pages. Add a redirects list in selfdoc.json with {from, to} page slugs — the build expands across all locale/version combos, generating both Cloudflare _redirects rules and HTML meta-refresh pages. Existing pages in cached old versions are preserved.
  • Docs. Added prose documentation for the exclude attribute on table-schema and table-config directives.

#0.10.0

New feature. exclude attribute for table-schema and table-config directives, allowing users to exclude specific top-level keys when rendering JSON/TOML/JSONC config files as tables.

#Features

  • New feature. exclude attribute for table-schema and table-config directives, allowing users to exclude specific top-level keys when rendering JSON/TOML/JSONC config files as tables.

#Fixes

  • Bug fix. Go extractor table-schema now correctly renders JSON/TOML config files instead of failing with 'no struct types found' when the file exists in the project.

#0.9.1

Fix. Go gen root package now correctly uses ref path="." instead of the module name.

#Fixes

  • Fix. Go gen root package now correctly uses ref path="." instead of the module name.

#0.9.0

New feature. Consolidated version detection with new VER002/VER003 lint codes that error when selfdoc.json version drifts from the project manifest.

#Features

  • New feature. Consolidated version detection with new VER002/VER003 lint codes that error when selfdoc.json version drifts from the project manifest.
  • New feature. table-endpoint content directive renders REST API documentation from OpenAPI 3.x JSON specs.
  • New feature. Two-tier coverage reporting distinguishes truly documented symbols (on human-written pages) from merely referenced symbols (on auto-generated skeleton pages).
  • New feature. selfdoc.json now supports an optional version field for explicit project version declaration.

#Fixes

  • Fix. Go gen now produces per-package (per-directory) documentation pages instead of broken per-file pages.

#0.8.1

Check validates all versions. selfdoc check now extracts and validates old tagged versions, not just the working tree. Monorepo version pinning lets docs-site releases freeze constituent project versions.

#Features

  • Check validates all versions. selfdoc check now extracts and validates old tagged versions, not just the working tree. Monorepo version pinning lets docs-site releases freeze constituent project versions.
  • gen_data dogfooding. selfdoc's own docs now use a gen_data script that extracts the directive catalog from source code.

#Fixes

  • Fix frontmatter list parsing. Use bracket syntax [a, b, c] for list values instead of comma detection, which broke description fields containing commas.

#0.8.0

Breaking: always-prefixed URLs. All output now uses /<locale>/<version>/page/ URL structure. versions and locales arrays are now required in selfdoc.json. Version and locale picker dropdowns in the header.

#Breaking

  • Breaking: always-prefixed URLs. All output now uses /<locale>/<version>/page/ URL structure. versions and locales arrays are now required in selfdoc.json. Version and locale picker dropdowns in the header.

#Features

  • Internal refactoring. Introduced BuildContext/PageContext/SearchEntry dataclasses, extracted JS to real files, decomposed \_wrap\_page into sub-renderers, extracted build\_single from build().
  • Multi-version docs. Build documentation for multiple tagged versions from git history. Version picker, old-version banner, per-version SEO (noindex, canonical to latest), git tag extraction with caching. --version CLI flag for dev builds.
  • Localization support. Parallel locale directories (docs/en/, docs/fa/), multi-locale build loop, hreflang tags, per-locale sitemaps with sitemap-index, backward compat for single-locale projects. --locale CLI flag.
  • Search filters. Filter search by version, locale, group, type, target, project, and tags. Syntax: key=value, key=a|b (OR), -key=value (NOT). Auto-injected version=latest default. Chip UI for active filters.
  • Monorepo unified site. New selfdoc/unified.py module builds one site from multiple projects. Hybrid sidebar with project groups, auto-generated landing page, rlsbl workspace.toml validation, unified search/sitemap/glossary, check_unified for all constituent projects.
  • Documentation overhaul. Rewrote homepage, restructured nav into 4 groups, enriched 20 API reference stubs, populated 23-term glossary, added callouts, created 14 new guide pages (search, SEO, code blocks, custom directives, check, comparisons, rlsbl integration, feeds, llms.txt, glossary guide, multi-language, root files, gen-data, staleness).

#Fixes

  • Fix Python logo SVG. The two snake halves in code block language icons no longer appear separated.

#0.7.0

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Breaking

  • strictcli dependency bumped to >=0.7.0 for --dump-schema support.

#Features

  • Shared resolution pipeline. Directive resolution centralized in a single pass, eliminating redundant walks and double resolution in selfdoc check.
  • **--dry-run flag for selfdoc check.** Reports staleness without writing hashes or committing. Hash computation centralized in staleness.py.
  • Glossary opt-out. Set "glossary": false in selfdoc.json to suppress auto-generated glossary page. Feed entry limit. Set "feed_max_entries": N to limit the Atom feed to the N most recent pages.
  • Schema.json-based CLI extraction. Replaced AST-based CLI structure extraction with reading .strictcli/schema.json. Richer data (flag choices, hidden flags, deprecated commands). Go projects get CLI documentation for the first time.

#0.6.0

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • Declarative config schema. Config validation is now driven by a schema (FieldType enum + FieldSpec dataclass) instead of procedural code. Unknown top-level keys in selfdoc.json are now rejected.
  • Five new directives. list-modules, table-commands, table-directives, table-config-schema, and var for generating module lists, CLI command tables, directive catalogs, config reference tables, and project metadata interpolation.
  • Root file generation. selfdoc gen can now produce root-level Markdown files (CLAUDE.md, README.md, etc.) from underscore-prefixed templates in docs/. Configure via root_files in selfdoc.json. Generated files are read-only (0o444) with an auto-generated header.

#Fixes

  • Underscore-prefixed templates excluded from lint. selfdoc check now skips _*.md files in docs/, matching the existing build exclusion.

#0.5.2

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Fixes

  • CLI page preservation fix end-to-end. Handwritten CLI page descriptions now actually survive selfdoc gen (the 0.5.1 preservation logic was defeated by stale-file cleanup deleting CLI pages before they could be read for preservation).

#0.5.1

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • Module page descriptions from docstrings. selfdoc gen now seeds new module pages with the first line of the module's docstring instead of the generic 'API reference for X' template; quote-wrapping length is also fixed.

#Fixes

  • CLI page description preservation. Handwritten description frontmatter on CLI pages (per-command, per-group, and the CLI index) now survives selfdoc gen runs, matching the behavior added for module pages in 0.5.0.
  • Sticky column visuals. Sticky first column in tables now preserves row stripe and hover backgrounds instead of showing a flat fill.

#0.5.0

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Breaking

  • API entry cards default to off. Re-enable via auto_detect.api_entries in config.

#Features

  • Module page descriptions preserved across regenerations. selfdoc gen now reads each existing page's frontmatter; if the description: has been customized (i.e., differs from the default 'API reference for X' template), it's preserved instead of overwritten. Bootstrap workflow: run selfdoc gen once, then handwrite each page's description in its frontmatter — subsequent selfdoc gen runs keep your descriptions.
  • Table redesign. Tables now use content-based widths and support sortable columns.
  • Language icons for code blocks. New display modes: colorful, monochrome, or none.
  • Optional line numbers for code blocks.
  • Subtle code block buttons with a coherent visual design.
  • Configurable run button, page navigation, and page progress indicators.
  • Theme-consistent styling for mark, kbd, abbr, del, ins, small, figure, var, samp, cite.
  • New directives: prose-desc, list-tree, table-dep, list-features.
  • CLI page descriptions use command help text instead of generic boilerplate.

#Fixes

  • Demo knob panel cleanup: removed unused knobs, added font options, fixed bugs.
  • Visual fixes: heading anchor hover, collapsible padding, code background, sidebar spacing.
  • Favicon and OG card now use the theme accent color.
  • Improved coverage matching for generated doc pages.
  • Recursive coverage matching now uses startswith for prefix-based directory matches.
  • code-help directive: path resolution and strictcli flag extraction for Go projects.

#0.4.5

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Breaking

  • Removed deprecated --warn-only flag (warnings are non-fatal by default since 0.4.0)

#Features

  • JSON schema for selfdoc check --format json output (schemas/check-output.schema.json)

#0.4.4

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Fixes

  • Build now cleans the output directory before writing, preventing stale files from previous builds

#0.4.3

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • Directive catalog now includes descriptions, attribute specs, and usage examples for all core directives
  • Generated API and CLI reference pages now appear in organized sidebar groups

#0.4.2

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • Auto-commit prefers rlsbl commit when available, marking commits with Autogenerated trailer for changelog coverage exemption

#0.4.1

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

  • No user-facing changes.

#0.4.0

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • Directive syntax redesigned: new attribute-based format (:-:, :<:, :>:) with a formal directive catalog replacing the old :::name arg syntax. All existing directive blocks must be migrated. The glossary directive is now list-glossary.
  • Custom directive scripts must update from resolve(arg, config) to resolve(attrs, config, body). Body content is now forwarded.
  • Extractors refactored to a LanguageExtractor protocol with a registry. Custom extractor integrations may need updating.
  • URL scheme changed from flat (guide.html) to directory-index (guide/index.html, served as guide/). All canonical URLs, sitemap entries, and internal links updated. External links pointing to old .html URLs will 404.
  • H1 headings are now auto-generated from the page title. The first # heading in Markdown is consumed as the title source (not rendered as-is). Multiple # headings in a single page now cause a build error.
  • selfdoc build no longer exits 1 for lint warnings. Exit 1 is reserved for errors only. The --warn-only flag is deprecated (warnings are non-fatal by default).
  • selfdoc gen command: auto-generates documentation pages from source code structure, with exclusion patterns, generated: true frontmatter, and stale file cleanup
  • selfdoc gen-data command: runs sandboxed scripts (via bubblewrap) to generate CSV/JSON data files for documentation
  • First-class strictcli support: auto-detects strictcli usage and generates CLI documentation pages
  • Description staleness detection: selfdoc check warns (STALE001) when a page description no longer matches page content, tracked via content hashing in .selfdoc/hashes/
  • Pluggable search engine: choose "builtin", "fuse", or "minisearch" via the search_engine config field
  • Landing page template: hero section with tagline, CTA button, and feature cards, configured via branding config field
  • Cross-page term linking: <dfn> definitions automatically linked across pages with dotted-underline .term-link styling
  • Documentation coverage for Go (exported symbols) and TypeScript/JavaScript (export declarations), previously Python-only
  • Per-symbol coverage tracking with configurable min_coverage threshold
  • Callout directives (note, tip, warning, danger, important) as first-class directive types
  • Feed filtering via feed: false frontmatter; changelog pages auto-detected and excluded by default
  • Reading progress bar fixed below the topbar
  • Scroll affordance gradients on overflowing code blocks and tables
  • Sticky first column on horizontally-scrolling tables
  • auto_detect config field to disable step guide and API entry heuristics globally or per-page via auto_steps/auto_api frontmatter
  • Markdown block tokenizer (selfdoc/tokenizer.py): standalone module with zero dependencies, 10 token types. Used internally for both HTML rendering and lint analysis.
  • Auto-commit system: selfdoc build, check, init, gen, and gen-data now auto-commit changed project files (hashes, generated docs, generated data). Disable with --no-commit. Uses safegit when available, falls back to git.
  • Directive token support in tokenizer: :::name arg / ::: blocks are recognized as structured tokens
  • SearchAction in WebSite JSON-LD on the homepage, enabling Google sitelinks search
  • GitHub Pages security headers: <meta http-equiv> tags for X-Content-Type-Options, X-Frame-Options, and Content-Security-Policy injected when deploy target is github-pages
  • WCAG contrast validation for user custom.css: SEO012 checks CSS variable overrides in docs/custom.css against theme backgrounds
  • High-contrast mode overrides: both themes override --link, --text-secondary, --sidebar-text, and --sidebar-active in prefers-contrast: more media query
  • Heading anchor IDs now deduplicate (appends -1, -2 for repeated headings) and preserve Unicode characters
  • Scrollspy correctly tracks headings when scrolling in both directions
  • Step guide detection tightened: keyword must appear at start of heading text, 200-char lookback (no more false positives on "Next Steps" or "Troubleshooting Steps")
  • API entry wrapping tightened: requires identifier-like heading and single-line code block (no more false positives on tutorial sections)
  • Prev/next links show directional labels ("Previous" / "Next") above page titles
  • Admonition icons use CSS mask-image technique, adapting correctly to dark mode
  • Diff highlighting uses +/- prefix symbols in addition to color
  • Collapsible section indicators replaced with 16x16px SVG chevrons (previously 8x12px CSS triangles)
  • Clean theme link color (#635bff) barely passed WCAG AA in light mode (4.70:1) and failed in dark mode (4.23:1). New color #5046e4 passes comfortably (6.29:1 light, 5.93:1 dark).
  • SEO lint false positives from fenced code blocks: heading counts (SEO001), heading level gaps (SEO002), empty alt text (SEO003), paragraph length (SEO007), empty sections (SEO011), and all other checks now use the tokenizer, making them immune to code block content
  • SEO007 false positives on directive-heavy pages: when a heading is followed by a :::directive block, the short-paragraph warning is suppressed
  • Statistics density check (SEO008) now evaluates prose content only, excluding code blocks
  • md_to_html() refactored from a 180-line line-walking loop into a clean tokenize-then-render pipeline
  • _redirects file is no longer generated (directory-index URLs don't need trailing-slash redirects)
  • _headers file is now only generated for cloudflare-pages deploy target
  • Auto-generated glossary page: collects all <dfn> terms site-wide into an alphabetical glossary with source links
  • Changelog auto-detection: CHANGELOG.md in project root is automatically included as a documentation page
  • selfdoc build --warn-only flag to treat lint warnings as non-fatal
  • Page progress indicator ("Page X of Y") between prev/next links
  • Current page title shown in the topbar on non-index pages
  • URL-triggered search: navigate to ?q=term to open search pre-filled with results
  • Meta description auto-generation: pages without frontmatter description now get <meta name="description"> auto-extracted from the first paragraph
  • Horizontal rule support: ---, ***, and ___ in Markdown now render as <hr>
  • Code tab sync no longer infinite-loops with 3+ tab groups sharing a language
  • Heading copy-to-clipboard shows a toast notification
  • Edit link opens in a new tab
  • OG description falls back to first paragraph when no frontmatter description
  • Each admonition type has a distinct background color
  • Focus indicators use :focus-visible throughout (keyboard-only, no mouse outlines)
  • Sidebar active link has a visible background highlight
  • Mobile sidebar traps focus within the overlay
  • Mobile sidebar closes on Escape key
  • Table rows highlight on hover
  • Cmd+K label adapts to platform (shows Ctrl+K on Windows/Linux)
  • "Last updated" date shown at the top of the page alongside breadcrumbs
  • Search "no results" message includes guidance ("Try different terms or browse the sidebar")
  • Feedback "No" response prompts for written feedback instead of just "Thanks"
  • Negative feedback provides a text input for follow-up
  • <summary> elements have :focus-visible outlines
  • <pre> elements have aria-label describing the code language
  • llms-full.txt includes page boundaries with title headings and path comments

#0.3.1

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • npm package renamed from selfdoc to selfdocumenting (npm blocks selfdoc due to similarity with abandoned self-doc package). Install via npm install -g selfdocumenting or npx selfdocumenting. The CLI command remains selfdoc.

#0.3.0

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • base_url is now a required field in selfdoc.json (previously optional)
  • Frontmatter description is now required on every page (auto-extraction removed); missing description is a build error
  • selfdoc build now fails on SEO lint warnings
  • Subdirectory-based nested nav groups with collapsible sidebar sections, localStorage persistence, and frontmatter overrides (nav_group, nav_order)
  • Configurable search trigger via search config field: "icon" (magnifying glass button), "bar" (text input with Cmd+K hint), or "hidden"
  • Functional feedback widget via feedback config field with webhook POST and Google Analytics event support
  • Atom feed generation (feed.xml) with auto-discovery <link> tag in <head>
  • Definition list syntax (term\n: definition) with glossary styling and DefinedTerm JSON-LD
  • Inline stat markup (==value==) producing semantic <data> elements
  • Code tabs for switching between language variants with localStorage persistence
  • Git branch auto-detection for edit links; configurable via branch config field
  • Rich OG card PNG generation with text overlay via predraw (optional dependency)
  • SEO lint framework with 15 rules covering headings, descriptions, images, contrast, and structured data
  • JSON-LD structured data: TechArticle, BreadcrumbList, WebSite, SoftwareSourceCode, Organization/Person, ItemList, DefinedTermSet
  • Open Graph and Twitter Card meta tags with og:locale, og:image:alt, and auto-generated social card images
  • robots.txt with explicit AI crawler permissions (GPTBot, ClaudeBot, PerplexityBot, etc.)
  • Visible "Last updated" dates with <time> elements, dateModified in JSON-LD, and sitemap lastmod
  • selfdoc check --ignore SEO007,SEO008 to suppress specific lint rules
  • selfdoc check --format json for machine-readable output
  • Color-coded selfdoc check output (green/yellow/red by severity)
  • New config fields: lang (BCP 47), author, twitter, branch, search, feedback
  • Sticky table headers no longer hide behind the fixed topbar
  • Copy button now always visible on code blocks (was hidden until hover, invisible on touch)
  • Fixed dark mode contrast for all accent colors
  • Fixed breadcrumb intermediate links pointing to non-existent directory index pages
  • Build-time Pygments syntax highlighting (replaced client-side highlight.js)
  • Build-time CSS, JS, and HTML minification with critical CSS inlining
  • Gzip and Brotli pre-compression of build output
  • Search JS externalized to search.js with lazy index loading
  • Conditional JS inclusion based on page content
  • ARIA labels on sidebar nav, TOC nav, and search dialog
  • Dynamic theme toggle ARIA label indicating current state
  • Roving tabindex on code tabs per WAI-ARIA pattern
  • Heading anchors visible on touch devices
  • Card-style prev/next navigation links
  • Print stylesheet: 2cm margins, forced light colors, hidden breadcrumbs, code wrapping
  • Security headers and trailing slash redirects for Cloudflare Pages
  • Edit link shown at both top and bottom of content area
  • llms.txt and llms-full.txt for AI documentation ingestion
  • selfdoc check reports undocumented public symbols when coverage is below 100%
  • lint_ignore config field for project-level lint rule suppression
  • Edit link and "Last updated" date no longer run together (flex layout with gap)
  • Search shows "No results" message instead of blank space
  • Search dialog closes when clicking a result link
  • Fixed code-block hover shadow invisible in dark mode
  • Table <caption> derived from preceding heading for screen readers
  • 44px minimum touch targets on all interactive elements
  • Admonition icons (distinct SVG per type: info, lightbulb, warning triangle, octagon, exclamation)
  • Styled generic <details>/<summary> in content
  • Styled standalone <dfn> tags outside glossary context
  • RSS feed link in site footer
  • Fragment highlight animation when navigating to #section URLs
  • Topbar truncates long project names with ellipsis

#0.2.0

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • Theme system with per-project theming via "theme" in selfdoc.json and optional docs/custom.css overrides
  • Syntax highlighting via highlight.js (light + dark themes)
  • Google-style docstring formatting (Args, Returns, Raises rendered as structured lists)
  • Heading hierarchy: directive expansions use h2/h3/h4 instead of injecting h1
  • Module name mangling (selfdoc.extractorsthon bug)
  • Nested _build/_build recursion when rebuilding
  • Deploy supports CF_ACCOUNT_ID and CF_PAGES_API_TOKEN env var names (remapped to wrangler's expected names)
  • Minimal theme: clean typography, dark mode, high-contrast, and reduced-motion variants (all auto-detected from OS preferences)
  • Top bar with project name and version badge
  • Heading anchor links for deep linking
  • CSS extracted to cacheable style.css instead of inlined per page

#0.1.0

RECOVERY OBLIGATION: no description was recoverable for this version (neither the GitHub Release notes nor the CHANGELOG.md section carried one). Author a real description from this version's changelog entries and regenerate.

#Features

  • Python, Go, TypeScript/JS extractors
  • Custom directive plugins
  • selfdoc check coverage analysis
  • HTML generation with responsive CSS
  • Deploy to Cloudflare Pages + GitHub Pages
  • SSE live reload in selfdoc serve
  • Code-aware static site generator
  • :::directive syntax for embedding code-extracted content
  • 5 built-in directives (module, schema, test, cli, config)

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • rlsbl Release orchestration and project scaffolding CLI that bumps versions, validates a structured JSONL changelog, tags only the commit CI verified, and publishes to npm, PyPI, Go and more
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search