Sources & Methods
WikiFred
How the wiki is built and maintained.
WikiFred — Presentation Layer
How to turn a processed life-archive into a browsable, threaded website
Owner: Fred Heald
Updated: 2026-06-04
Status: Active development. ~561 pages, 10+ threads, live at obtainium.org/wiki/ (early-review period, noindex).
Project: projects/private/wikifred/
This is the presentation end of the archive pipeline. The sources-and-methods doc covers raw source → processed text → synthesis. This doc covers the last step: synthesis → a thing people can read and wander through. Output is a public, hyperlinked static site on obtainium.org.
If the sources-and-methods work is the mise en place — a life’s worth of raw material washed, sorted, and laid out in its station — this doc is where it goes on the heat and gets plated. The archive is the stocked pantry; the articles are the dishes; the site is the dining room.
Working name: WikiFred. Generic candidates for the reusable version: WikiArchive, WikiPerson. The method generalizes to anyone with a processed personal/family archive.
The core idea
Everything is articles and threads.
- An article is one short page — one story, one event, one observation. A page at most; shorter is fine. Quality and quantity.
- A thread is an ordered set of articles — the only structural primitive. A person is a thread. A place is a thread. A vehicle is a thread. A curated arc is a thread.
Two ways an article joins a thread:
| Kind | How | Example |
|---|---|---|
| Curated | declared in threads: frontmatter |
dylan-stories, burning-man |
| Entity | auto-generated from people/pets/places/vehicles: tags |
every article tagged dora is the Dora thread |
Article pipeline
Raw source (journal, Facebook post, blog, Yelp review, photo story)
↓ Select identify good standalone stories
↓ Extract get Fred's actual words from the raw source
↓ Scrub remove private/NSFW content → visibility: public
↓ Tag frontmatter: threads + entity tags + source thread
↓ Photos check photo-reviews.jsonl for matching photos (by people/place/date/topic)
— copy matches to src/img/, add to article frontmatter
— photo-matches.md has pre-analyzed candidates
— record ALL candidates found (selected + not selected) in the source
file for the subject (memory-notes, portrait source, or equivalent)
NOT in the wiki article itself — wiki articles are output targets
↓ Build eleventy → static HTML; pagefind → search index (cook)
↓ Deploy rsync _site/ → obtainium.org/wiki/ (plate & serve)
Critical rule: Always use Fred’s actual words from the raw source. Never paraphrase.
The feedback loop
The pipeline above looks one-way but isn’t. Building a wiki article is also a research pass — and discoveries made during that pass feed back into the source files.
The loop:
- Finding photos for an article → record ALL candidates (selected + not) in the source/notes file
- Discovering a new fact while writing → add it to the portrait source or memory-notes
- Fred adds content during review (new quotes, corrections, stories) → goes back into the source, not just the article
- Wiki articles are output — they receive content, they don’t store it
Why this matters: if photo candidates or new facts only exist in the wiki article, they’re lost the next time the article is regenerated or the session compacts. The source files are the memory; the wiki is the display.
In practice: any time you find, select, or decide against a photo — note it in the subject’s source file (memory-notes, portrait source, or equivalent). Same for facts Fred adds during conversation. The article is the last stop, not the only stop.
The tagging system
Every article carries two kinds of tags in its frontmatter:
1. Curated thread membership (threads: array)
Explicit membership in named threads. An article can belong to multiple:
- Content threads:
stories,burning-man,travel,food,el-centro,tech,vehicles,portraits,fragments,doofs,webb - Source threads:
src-journal,src-facebook,src-blog,src-yelp,src-autobiography,src-photo-stories,src-journal-summary(needs raw replacement)
2. Entity tags (auto-generate entity threads)
Tags in people:, pets:, places:, vehicles: arrays. Every article tagged with a slug automatically joins that entity’s thread — no declaration needed. E.g. every article with people: ["nicholas-corwin"] becomes part of his thread.
Thread kinds (controlled in lib/registry.mjs):
curated · person · pet · toy · place · vehicle · source · topic
topic = fallback for unregistered slugs. These work for article nav but are hidden from the browse index. To promote a slug from topic to a proper kind, add it to the registry.
Browse index visibility: Currently suppressed from the index: topic (unregistered overflow), vehicle (covered by curated Vehicles thread), toy (Stick Fluffy only). Hardcoded in src/browse.njk. Future: make a registry hideFromBrowse flag.
Validation: npm run validate checks all articles for malformed frontmatter — trailing slashes in thread slugs, invalid visibility values, missing required fields.
Source threads
Every article is tagged with a src-* thread identifying its provenance. This lets you browse by source at /thread/src-journal/ etc., and tracks what’s been mined.
| Thread | Label | Raw source | Selection aid |
|---|---|---|---|
src-journal |
Journal | self-analysis/source/journal-notes-*.md (Apple Notes exports) |
The notes files are the raw material |
src-facebook |
facebook/posts.md, facebook/posts 2.md |
self-analysis/source/facebook-notes-*.md identify good posts; get actual text from posts.md |
|
src-blog |
Blog | blogs/source/*.md — one file per post |
Read directly |
src-yelp |
Yelp review | yelp/reviews/all-reviews.md |
Read directly |
src-autobiography |
Autobiography draft | autobiography/drafts/*.md |
Read directly; already in Fred’s voice |
src-photo-stories |
Photo story | journals/originals/2026/*/photo-stories.md |
Read directly |
src-quora |
Quora | self-analysis/source/obtainium-notes.md (Quora section) |
Read directly |
Mining status tracked in wikifred/SOURCES.md.
Voice rules
- Dylan Stories — third-person warm voice (“Dylan was nine years old and it was a mountain creek”)
- All other articles — Fred’s actual words from raw source. Quote or minimally expand. Never paraphrase into a neutral voice.
- Editorial notes — a soupçon of italics at the bottom of the article body: only when context is genuinely needed, never enough to taste on its own
Names & deadnames
Display a person’s current/chosen name everywhere it is presented: article titles, headings, the registry display name (which drives thread headings and link labels), and slugs.
In historical article body text, the default is to keep the name as it was actually used at the time — the prose stays true to the lived moment. John and I were the ones who did the thing, even if the title now reads “Jane and Fred Did the Thing.” This default yields to the subject’s own preference: if they want the former name fully replaced in the prose too, do that.
Always keep the original in source-provenance fields (source.file, entry:) — these must match the source filename/heading, not the display name.
Worked example: Nicholas Corwin went by “Kip” for decades. Titles, slugs, and his thread/registry name are all Nicholas Corwin; the old article bodies still say “Kip” where that’s how it happened.
Scrubbing rules (public site)
Omit: romantic/sexual relationships, marriage/separation/divorce, therapy/counseling, substance self-monitoring, gender expression outings, other people’s private medical/financial/relationship info.
Safe: travel, adventure, vehicles, places, food, Burning Man (public aspects), work (general), tech observations, family history (deceased relatives fine), funny incidents, friends in public/fun contexts.
Visibility / access model — an audience axis (who may see it) plus admin-only flags. Single source of truth: lib/visibility.mjs. Three roles: anyone / logged-in / admin (Fred).
visibility |
Who may see it | Deploy build (_site) |
Admin build (npm run review) |
|---|---|---|---|
public |
anyone | yes | yes |
login |
logged-in users | no¹ | yes |
admin |
admin (Fred) only | no | yes |
draft |
admin only — review state | no | yes |
¹ login needs real logins; pre-login it simply isn’t deployed. Legacy aliases: private→login, personal/hidden→admin.
Admin-only flags (force admin-only regardless of visibility; both keep an article out of deploy until resolved):
needs_review: true— pending review. Approve-forward: apublicarticle with this flag is held back from deploy until cleared. Also what puts an article on/review/; every draft is initialized with it.nsfw: true— not-safe-for-public. Admin sees it; deploy never does.
Build rule (in code): deploy = public AND not needs_review AND not nsfw; the admin build shows everything. The “logged-in” middle role (public + login) isn’t separately buildable until logins land.
NSFW photo filtering from LR export: When exporting photos from the LR catalog for published stubs, exclude photos tagged with the NSFW keyword subtree (LR keyword id=67335 in this catalog). Descendants include: NSFW, Medical, Private, Dresses, Mushrooms. Do NOT use the broader NoPublish tree (id=1628171) — it includes organizational categories (Collections, Events, Burning Man, etc.) that are safe to publish and would produce hundreds of false exclusions. Use album-scoped queries when checking for NSFW tags — basename-only lookup produces false positives from duplicate filenames across different LR folders.
Editor-comment processing (review-questions.md): apply the note, then set state and clear needs_review. A bare “OK” / “ok to publish” = reviewed & approved → visibility: public. Dispositions Fred uses: “keep private” → login; “hide this” / admin-only → admin; “split into two” → public part + admin/login part.
Travel stubs
Naming convention: YYYY-MM Destination Subject (e.g., 2007-07 Santa Fe Blake and Joley's Wedding). Slug follows: 2007-07-santa-fe-blake-joley-wedding.
trips thread: One entry per trip. The trip-overview article gets trips in threads. Day articles within a multi-day trip (e.g., oregon-trip-2024-day-1) get the trip slug as their thread but not trips — day articles should not clutter the trips timeline. Solo-day trips that have no overview article also get trips.
Slug rename cascade: If the trip slug doubles as a thread name referenced by other articles (e.g., day articles), renaming it requires updating all those articles’ threads lists and the registry entry simultaneously. Script it — don’t do it by hand.
LR collection query types:
- Direct collection:
c.creationId = 'com.adobe.ag.library.collection'— queryAgLibraryCollectionImagedirectly. - Collection set (older organization): join parent set → child named
'Project Photos'→AgLibraryCollectionImage. Many pre-2010 albums use this structure.
Craft rules — lessons learned
Hard rules from review passes. Running log of specifics: wikifred/review-feedback.md.
Conventions (2026-06, established across the relative-profile batch; per-rule enforcer “cleanup runs” tracked in wikifred/TODO.md):
- tag ≠ link. A
people:/threads:tag means the article is about that entity (puts it in the entity’s hub) — tag deliberately, only the subject(s). A[[link]]is just a mention — link freely. Profiles link direct family in prose; don’t over-tag. Scrub over-tagged articles. - No relative dates in our editorial prose (“a year ago” → “2025”). Fred’s verbatim journal quotes keep their original phrasing.
- No rimshots — front or back. Cut trite scene-setting openers (“He started a long way from the desert”) as well as theme-stating closers. Lead with the concrete.
- Sensitive info → a “Personal / do-not-publish” section in the source/data record, never the published article (cause of death, private family matters).
- Photo curation: young + old + action per person; avoid group shots. Default search = processed
photo-reviews.jsonl; the Lightroom catalog is the expensive, face-tag-dependent tier (seesources-and-methods.md§ Photo search). - Web-search augment for notable ancestors (a line or two + a source link).
- People pipeline + data-record format:
people/people-workflow.md.
Use Fred’s actual words; add nothing. A source link is necessary but not sufficient. For every article:
- Read the actual
_source/<source>/entry — never a summary, rehash, or analysis doc. - Record the resolvable source path in frontmatter.
- Use Fred’s own words; quote or lightly edit — never paraphrase into a neutral voice.
- Add no inference, dates, places, or “what happened” narration that isn’t in the source. (Canonical failure:
gila-bend-postcardinvented a wrong birthday and a “that’s the thing about photos” closer on top of good source.)
Editorial notes — the keep/cut test. A trailing italic note is allowed only if it adds external verifiable fact the source itself can’t supply: identity (“X was Fred’s grandfather”), aftermath (“X passed away in 2000”), archival significance (“the last journal entry that mentions him alive”). Cut it if it restates the article, infers/embellishes, or lands an aphorism. Keep example: the Gramp-death note on daltons-rash-decisions. Cut example: gila-bend.
No rimshots. Don’t end on a tidy thematic closer that states the theme out loud. Cut unless it’s Fred’s own line.
Avoid chops (journal duplication). A journal entry with several dated sub-entries (YYMMDD.HHMM) must not be split so one article keeps the whole entry (duplicated tail), and adjacent articles must not overlap. Detect by shared timestamps and shared verbatim sentences. (See the journals extraction doc.)
Scrub at the line, not the article. Cut the offending sentence and keep the article when the rest is safe — e.g. gender-expression asides (bra shopping, “wear a dress”) get surgically removed, and a revealing slug gets renamed (sachs-madass-and-bras → sachs-madass). Draft the whole article only when its premise is the private content.
Verify photo captions. Never trust an inherited caption — confirm who/what/when from the image plus sources (the “Amy” who was actually Britt). Check photo-reviews.jsonl / photo-matches.md.
One canonical slug per entity. No alias slugs (kip vs nicholas-corwin); the display label carries the nickname via [[nicholas-corwin|Kip]].
Frontmatter format
---
title: "Title"
date: YYYY-MM-DD
threads: ["content-thread", "src-source-thread"]
people: ["slug"]
places: ["slug"]
vehicles: ["slug"]
pets: ["slug"]
visibility: public # public | hidden | draft
needs_review: true # optional; author flag only, no visual effect until Phase 2
photos:
- src: /img/filename.jpg
caption: "Caption"
source:
label: "Journal" # or: Facebook | Blog | Yelp review | Autobiography draft | Photo story
url: "https://..." # optional, for external links
---
Entity registry
All entity slugs and thread metadata live in lib/registry.mjs. Key fields:
name— display namekind—curated | person | pet | toy | place | vehicle | source | topicblurb— shown on thread hub page
Unknown slugs auto-titleize from the slug (no registry entry needed for one-offs).
Technology
| Concern | Choice | Why |
|---|---|---|
| Generator | Eleventy (11ty) | Markdown-native, plain JS, static HTML |
| Search | Pagefind | Zero-backend full-text; indexes built HTML |
| Hosting | static files on obtainium.org | No server, no DB, no login |
| Linking | custom [[wiki-link]] markdown-it plugin |
First-mention treatment at build time |
| Client nav | tiny JS over /threads.json |
In-place next/random; degrades gracefully |
Build note: npx eleventy hangs on Node v24. Use node node_modules/@11ty/eleventy/cmd.cjs directly. This is wired into package.json scripts.
Dylan Stories: generated vs. hand-authored
Dylan Stories are the only generated thread. scripts/build-content.mjs:
- Reads source files from
../journals/dylan-stories/— never modified - Injects frontmatter (tags, date, people/places/pets) from a per-file META map
- Injects
[[wiki-links]]on first entity mention - Writes derived articles to
src/articles/dylan-stories/— always overwritten
All other articles are hand-authored .md files placed directly in src/articles/<thread>/.
Current threads (2026-06-03)
Content: Dylan Stories, Stories, Burning Man, Travel, Food, El Centro, Tech, Vehicles, Portraits, Fragments
Source: src-journal, src-facebook, src-blog, src-yelp, src-autobiography, src-photo-stories, src-quora
Entity (people): Fred Heald, Becke Shulman, Amy Heald, Phillip Heald, Nicholas Corwin “Kip”, Pamarie, Dylan Heald, and others
Entity (pets/toys): Dora, Pasquale, Sabio, The Puppies, Stick Fluffy, Tikka, Masala
Entity (places): El Centro, Mission Bay, Colorado, Telluride, Ouray, Claremont, San Felipe, and others
Entity (vehicles): Pinzgauer, and individual vehicle articles via the Vehicles thread
Generalizability
This pattern works for any processed personal or family archive: write short articles, tag entities, let entity threads auto-generate, publish static. The reusable version (WikiArchive) is the same code with Fred-specific registry and source-derive script swapped out. Candidate for the Personal Archive Handbook publication.
Chef’s note: the kitchen metaphor running through this doc — mise en place, soupçon, cook, plate — is a deliberate seasoning, not an accident. Keep the pinch light if you add to it.