Scriptorium is a WordPress-style CMS written entirely in WFL, rendering
through the Scribe template engine (a git submodule at lib/scribe) and
persisting to SQLite. Start with README.md, then
docs/ARCHITECTURE.md.
Scriptorium is maintainer-led; Brad is the primary Maintainer. The binding policies live at the repository root:
| Document | Purpose |
|---|---|
| GOVERNANCE.md | Roles, decisions, compatibility, releases, and amendments |
| CONTRIBUTING.md | Contribution workflow and Contributor applications |
| CODE_OF_CONDUCT.md | Community conduct and reporting |
| AI_POLICY.md | AI-assisted work is welcome; authors remain accountable |
| SECURITY.md | Private vulnerability reporting and security scope |
| testing.md | Required test evidence, risk triggers, and current gaps |
| REPOSITORY_HYGIENE.md | Content placement, runtime data, and the enforced hygiene profile |
Protect existing databases, uploads, URLs, theme contracts, and extension hooks. Behavioral changes need failing-then-passing test evidence and updated docs in the same change. Documentation-only changes need relevant validation, not artificial application tests. Do not log or commit secrets or real site data. Maintainers own merges, releases, access grants, and policy exceptions; AI assistance does not change that authority or the quality bar.
AGENTS.md points here so agent guidance has one canonical home. Keep this
section and the root policies aligned when changing contribution workflow.
docs/PROJECT-LAYOUT.md is the house standard for
NEW WFL projects. This repository does not follow it, and that is deliberate.
Scriptorium predates the policy. Its main.wfl is one 51 KB file, its themes use
sections/ + templates/, and its tests live in TestPrograms/. All three
violate the standard.
- Do not "fix" this repo to match the policy as a drive-by. Retrofitting it is a separate, deliberate migration that has not been approved.
- Do apply the policy in full when scaffolding a new project, or when asked what shape something new should take.
- If a change here would move the repo toward the standard anyway, say so and let Brad decide — don't fold it silently into unrelated work.
- Read
docs/ARCHITECTURE.mdbefore changingmain.wflorapp/. It catalogues the WFL constraints that shaped the design. The structure looks odd until you know which limitation forced it. Most importantly: includes form a tree, not a flat namespace — diamonds break. The library chainutil ← db ← auth ← renderis load-bearing, and the router plus every handler live inmain.wflbecause they must share one scope. - Reserved words.
store,count,data,content,status,header,file,port,error,find,oneand friends are WFL keywords. Qualify identifiers instead:the_status,media_row,db_path. - Run from the repo root. Template and asset paths resolve relative to the working directory.
- Bug reports: follow CONTRIBUTING.md and .github/ISSUE_TEMPLATE/bug_report.yml, including for reports created through a CLI or API. Record observed behavior, reproduction steps, expected/actual results, and known versions; mark unknown details honestly. Use sanitized evidence and the private security channel for suspected vulnerabilities.
- Pull requests: follow the title convention and body format in CONTRIBUTING.md, using .github/pull_request_template.md even when creating a PR through a CLI or API. Keep all five sections, scale the detail to the change, and update the title and body to match the final diff. Record actual check results and explain inapplicable or unavailable evidence.
- Scribe is a submodule. Don't edit
lib/scribe/in place; changes go upstream to WebFirstLanguage/Scribe, then bump viascripts/update-scribe.sh. - Checks:
wfl --execution-timeout 1200 scripts/run_tests.wflruns the complete suite: application, ORM/migrations/recovery, HTTP integration, tooling, executable examples, and pinned Scribe.--group toolingor--group applicationselects a focused run. Runpython scripts/check_repo_hygiene.pyfor the repository hygiene gate. Every test, fixture, assertion, helper and driver is WFL. Python 3.11+ and Git are required only for the hygiene checker's implementation subject. The runner uses the WFL executable that launched it, with an optional--wfloverride. It needs the owned-process completion andcurrent_executableruntime APIs. Governance provisions WFL and runs tooling and hygiene on Blacksmith Linux and GitHub-hosted Windows. WFL tests runs the complete suite on Blacksmith using a freshly pulledbsbyrdwfl/wfl:nightlyimage; its summary records the resolved image digest, runtime version, and source revisions. See testing.md for commands, coverage limits, and merge evidence. data_dirandweb_server_portare application configuration.main.wflreads.wflcfgitself at boot using helpers inapp/util.wfl; the runtime does not apply these keys. The HTTP port accepts whole numbers from 1 to 65535 and defaults to 8080 for a missing file or setting, or an empty, malformed, fractional, or out-of-range value. Restart after changing it.
- Theme selection is configurable now.
render_publicresolves<theme_root>/<theme>/body/<name>.html, then.../templates/<name>.html, then the base theme, wherethemeandtheme_rootcome from.wflcfg.main.wflapplies them at boot viaset_public_theme; a module-levelstoreis used becausemain.wflcannot assign to a variable defined in an included file, only call an action that does. This closes the gapdocs/PROJECT-LAYOUT.md§6.1 describes — a site with a custom theme no longer needs a patched clone. Unset keys keep the exact legacy behaviour. app/site_ext.wflis the site-extension seam, and it is whymain.wflincludes it rather thanrender.wfl. A deployment replaces that one file to add its own routes, tables and boot work; the stock copy is inert. It has to be a whole file at the tail of the chain because includes form a tree — a sibling include cannot seerender.wfl's definitions at all. It is consulted first indispatch_public, so a site can own/and still inherit/post/:slug,/page/:slugand the 404. See the header comment in the file, andwebsite/in LogbieLLC/logbie for a real one.- Body template names are a contract.
home.html,post.html,page.html, andnotfound.htmlare named as string literals inside the handlers inmain.wfl. Adding a new body template requires a new handler.
Live Scriptorium sites (news.starnet and others) are Starnet infrastructure.
Follow the workspace instructions in the starnet folder for those: load the
starnet-devops and knowledge-mcp-dev skills, check the knowledge base before
acting, and record what changed afterward. Use git-safe-commit for any git
write operation.