Deep dive into Foswiki focused on its deltas from TWiki (not the shared lineage): the pluggable Foswiki::Store backend (RcsWrap/RcsLite/PlainFile) behind a versioned interface via Foswiki::Meta, the OO/MVC core rewrite, Foswiki::Func + registerTagHandler, DataForms + MetaDataPlugin multi-record, and WysiwygPlugin TML<->HTML round-trip. The store abstraction is logged as prior art for shard-wiki's own adapter contract (SHARD-WP-0002). Catalog (now 43 UCs): - UC-42 read/write a non-Markdown shard via lossless syntax translation (Markdown-first for prose; Foswiki WysiwygPlugin is proof) - UC-43 tolerate a shard's storage-backend swap (RCS<->PlainFile) under a stable identity - enrich UC-39 (multi-record metadata) and UC-40 (PlainFile direct-attach) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 KiB
Findings — Foswiki: store abstraction, extension API, ecosystem
Date: 2026-06-13 · Status: research draft
Scope: Foswiki as distinct from TWiki — only the deltas, since the two share a
data model, markup, plugin-handler API, and per-topic ACL. The deltas that matter to
shard-wiki: a pluggable store backend behind a versioned interface
(Foswiki::Store + Foswiki::Meta), an OO/MVC core rewrite, a cleaner extension
API (Foswiki::Func::registerTagHandler), enhanced DataForms, and a TML↔HTML
round-trip editor framework. Sources: foswiki.org Development + System docs,
foswiki/distro on GitHub.
Read first for shared lineage: research/260613-twiki-deep-dive/ (flat-file +
RCS store, Webs/Topics, handler callbacks, per-topic ALLOW/DENY ACL). This file
does not repeat those.
1. Origin and compatibility
Forked from TWiki 4.2.x in October 2008 by most of the TWiki community (sources
cite 4.2.3–4.2.4; the TWiki dive recorded 4.2.4). Design goal: ~100% content
compatibility — same TML markup, same plugin API — via a TWikiCompatibilityPlugin
that maps the TWiki:: namespace and legacy variables. So everything in the TWiki
dive still applies; Foswiki then grew the features below.
2. The headline delta — a pluggable store behind a versioned interface
This is the reason Foswiki earns its own dive.
2.1 Foswiki::Meta indirection
After Foswiki 1.0.4 the core was changed to delegate almost all store operations
to a topic object, Foswiki::Meta. Callers manipulate a Foswiki::Meta object
representing the item they're changing and never touch the store implementation
directly; Foswiki::Meta talks to the real store through the well-defined
Foswiki::Store interface. This is a clean MVC/repository separation.
2.2 Swappable backends
Foswiki::Store:: ships multiple low-level back-ends behind that one interface:
RcsWrap— RCS via the externalrcsbinaries (classic TWiki behavior)RcsLite— a pure-Perl RCS implementationPlainFileStoreContrib— a newer store that saves topics/attachments as timestamped copies instead of RCS diffs: more disk, but no RCS dependency and much higher performance.
So in Foswiki the storage format is a configuration choice, not a fixed property of the engine — the same wiki can run on RCS or PlainFile behind an unchanged core.
2.3 OO/MVC core rewrite
Foswiki has steadily rearchitected from "disconnected Perl CGI scripts" toward object-oriented, unit-tested, MVC Perl ("solidify the sand piles"), preserving backward compatibility through tests. The store abstraction above is the most load-bearing result.
3. Extension API deltas
Shared with TWiki: handler callbacks (initPlugin, commonTagsHandler,
before/afterSaveHandler, afterRenameHandler, attachment handlers), REST handlers,
Config.spec, package types (Plugin / Skin / AddOn / Contrib). Foswiki refinements:
Foswiki::Funcis the blessed API — "if there's aFoswiki::Funcway and another way, theFoswiki::Funcway is almost always right." Direct use of internal packages is discouraged and governed byPluginsApiPolicies.Foswiki::Func::registerTagHandler($tag, \&sub)— register a custom macro/variable programmatically (cleaner than TWiki'scommonTagsHandlerstring-matching convention).- Contrib-defined APIs carry an explicit "use at your own risk / awaiting merge" policy — a maturity signal on extension interfaces.
EmptyPlugin(lib/Foswiki/Plugins/EmptyPlugin.pm) is the canonical handler reference/skeleton.
4. DataForms and structured data (delta)
DataForms = Foswiki's name for TWiki Forms: typed fields (text, date, single/multi
value, label) stored as %META:FIELD% in the topic text. Foswiki extends the model
via popular extensions:
- MoreFormfieldsPlugin — additional special-purpose field types.
- FlexFormPlugin — render DataForm interfaces from custom templates
(
Foswiki::Formclasses). - MetaDataPlugin — multiple structured data records per topic (beyond the classic one-form-per-topic), closing the gap toward XWiki's multi-XObject model while keeping data in the text file.
5. Editing / syntax (delta relevant to "Markdown-first")
- WysiwygPlugin — a generic framework that transforms TML → HTML for a browser editor and HTML → TML on save (lossless round-trip).
- TinyMCEPlugin — pre-installed WYSIWYG editor built on WysiwygPlugin.
This proves bidirectional, lossless translation between an engine's native markup and another representation is feasible — directly relevant to shard-wiki reading a non-Markdown shard and writing Markdown overlays back (UC-42).
6. Foswiki as a shard — capability profile (delta from TWiki)
| Capability | Foswiki | Note vs TWiki |
|---|---|---|
| Store backend | pluggable | RCS or PlainFile behind Foswiki::Store — direct-attach target is cleaner on PlainFile (UC-40) |
| History | RCS or timestamped copies | PlainFile = whole-version snapshots, not diffs; both file-format, git-importable (UC-41) |
| Structured payload | DataForms %META%, multi-record via MetaDataPlugin |
richer than classic TWiki Forms (UC-34/39) |
| Syntax translation | WysiwygPlugin TML↔HTML | bidirectional round-trip exists (UC-42) |
| Extension host | Foswiki::Func + registerTagHandler + REST |
cleaner adapter-host surface (UC-38) |
| Store as contract | Foswiki::Store versioned interface |
architectural prior art for shard-wiki's adapter contract |
7. Mapping to shard-wiki INTENT (compare, do not equate)
7.1 Reinforcements
| Observation | INTENT principle |
|---|---|
Foswiki::Store versioned interface + swappable backends |
capability-aware adapters / shard adapter contract — an engine that already did exactly this separation |
Foswiki::Meta mediates all store access |
clean mechanism over policy boundary worth mirroring in the adapter contract |
| PlainFile store = timestamped text copies | git-addressable coordination / direct-attach (UC-40), history import (UC-41) |
| WysiwygPlugin TML↔HTML round-trip | Markdown-first, backend-neutral is achievable for prose via translation (UC-42) |
| MetaDataPlugin multi-record topics | structured pages beyond one form (UC-34/39) |
7.2 Deliberate divergences (design bugs if conflated)
| Foswiki assumption | shard-wiki correction |
|---|---|
| One pluggable store per wiki, chosen at config | shard-wiki federates many heterogeneous stores at once |
| TML is the canonical syntax; HTML is a render target | shard-wiki is Markdown-first; TML↔Markdown is an adapter translation, not core |
| Store interface is Foswiki-internal Perl | shard-wiki's adapter contract is cross-language, cross-backend, versioned |
| ACL in topic preferences | authorize in core; engine ACL is advisory provenance |
7.3 What Foswiki teaches that shard-wiki should not lose
- The store-abstraction pattern works in practice —
Foswiki::Storeis a real-world proof that a stable interface + swappable backends is viable; the shard adapter contract is the same idea generalized across engines. - Backend format should be swappable under a stable identity — Foswiki migrates RCS↔PlainFile without changing the wiki; shard-wiki should tolerate a shard's backend changing under it (UC-43).
- Lossless syntax round-trip is a solved problem — don't treat non-Markdown prose as read-only; translate it (UC-42).
8. Use-case seeds → catalog (promoted 2026-06-13)
| Seed | Catalog UC | Disposition |
|---|---|---|
| Read/write a non-Markdown shard via lossless syntax translation (TML↔Markdown) | UC-42 (new) | realizes Markdown-first for prose; WysiwygPlugin is proof |
| Tolerate a shard's storage-backend swap without losing identity/provenance | UC-43 (new) | Foswiki RCS↔PlainFile; orchestration robustness |
| Structured / multi-record pages | UC-34 / UC-39 | enriched: DataForms + MetaDataPlugin multi-record |
| Attach a file-backed engine's on-disk store directly | UC-40 | enriched: PlainFile store is a cleaner direct-attach target than RCS |
Foswiki::Store versioned interface |
(no UC) | architecture prior art → SHARD-WP-0002 adapter contract |
9. Open questions (for spec / workplans)
- Adapter-contract shape — how much of
Foswiki::Store's method set (read/save/move/getRevisionInfo/getRevisionHistory/lock) maps onto shard-wiki's capability-aware adapter contract? (architecture,SHARD-WP-0002) - Syntax-translation fidelity — is TML↔Markdown lossless enough for overlay round-trips, or must overlays be stored in TML to be safe (UC-42)?
- Backend-swap detection — how does shard-wiki notice and tolerate a shard changing store format underneath (RCS→PlainFile), and does provenance/history survive it (UC-43)?
- Multi-record metadata — represent MetaDataPlugin multi-record topics and XWiki multi-XObject pages in one structured-metadata page model (shared open question).
10. Sources
11. Traceability
| This document section | Informs (future) |
|---|---|
| §2 store abstraction | adapter contract design (SHARD-WP-0002) — Foswiki::Store as prior art |
| §3 extension API | UC-38 engine-side adapter host |
| §4 DataForms | structured-metadata page model (UC-34/39) |
| §5 WysiwygPlugin | UC-42 syntax-translation adapter |
| §6 capability profile | adapter capability-profile vocabulary |
| §7 INTENT mapping | architecture-blueprint guardrails |
| §8 UC seeds | spec/UseCaseCatalog.md (UC-42, UC-43; UC-34/39/40 enrichment) |