name: wiki description: ACT Wikipedia — ingest sources, query knowledge, lint for gaps, and manage the LLM-compiled wiki at wiki/. Use when user says "wiki", "ingest", "add to wiki", "wiki query", "wiki lint", "knowledge base", or wants to add/query/maintain the ACT knowledge base.
ACT Wikipedia Skill
LLM-managed knowledge base at wiki/ following the Karpathy second-brain pattern. The wiki is the domain of the LLM — humans curate sources, the LLM compiles and maintains articles. Questions feed back as synthesis articles, so curiosity literally makes the system smarter.
Folder layout (second-brain pattern)
wiki/
raw/ ← immutable source documents (never edit)
sources/ ← one summary per ingested raw file
concepts/ ← frameworks, methodologies, theories
projects/, people/, communities/, art/, finance/, technical/, decisions/, research/, stories/
synthesis/ ← THE COMPOUNDING LAYER — answers built by /wiki query
output/ ← reports, audits, lint results (not part of the article graph)
log.md ← append-only timeline of every wiki operation
index.md ← master catalog
The four layers that compound:
- Sources — what was ingested (one summary per raw file in
sources/) - Entities & concepts — the things sources are about
- Synthesis — the answers to your questions, saved permanently so the next query builds on them
- Output — reports the wiki generated, not part of the curated graph
Commands
Parse the user's intent and route to the appropriate operation:
| Trigger | Operation | Example |
|---|---|---|
/wiki ingest <path-or-url> |
Ingest | "ingest this article into the wiki" |
/wiki query <question> |
Query (read-only) | "what do we know about PICC?" |
/wiki synthesize <question> |
Query + auto-save synthesis | "synthesize Diagrama vs Oonchiumpa" |
/wiki lint |
Lint | "health check the wiki" |
/wiki status |
Status | "how big is the wiki?" |
/wiki enrich <slug> |
Enrich | "flesh out the goods-on-country article" |
/wiki log [n] |
Recent activity | "what's been happening in the wiki?" |
/wiki narrative status [project] |
Narrative — frame distribution + gaps | "what claims have we made about CONTAINED?" |
/wiki narrative draft <project> [--frame ... --channel ...] |
Narrative — assemble draft brief | "draft a moral-frame LinkedIn post for CONTAINED" |
/wiki narrative oped <project> |
Narrative — long-form draft brief | "write an op-ed for CONTAINED" |
/wiki narrative log <claim> <channel> |
Narrative — record a deployment | "log that we shipped claim-cost-comparison on LinkedIn today" |
/wiki narrative refresh [project] |
Narrative — regenerate INDEX | "refresh the narrative index" |
/wiki narrative ingest <path> |
Narrative — extract from a file/folder | "ingest the goods-on-country folder into the narrative store" |
/wiki narrative watch [--schedule daily|weekly] |
Narrative — run all configured sources | "watch the narrative sources" |
/wiki narrative process <digest> |
Narrative — apply an ingest digest | "process today's digest" |
/wiki narrative funder <slug> |
Narrative — assemble funder pitch brief | "draft a Minderoo pitch" |
/wiki narrative cycle <phase> |
Narrative — filter draft by campaign cycle | "draft for budget-week" |
/wiki narrative review [project] |
Narrative — weekly strategy review | "what's the campaign retro saying" |
/wiki (no args) |
Status | Show current wiki stats |
After every ingest, lint, synthesis, viewer-build or url-audit operation, append a one-line entry to wiki/log.md via node scripts/wiki-log.mjs <op> "<summary>" [files...]. The log is the second-brain timeline — without it the system can't answer "what changed and when?".
Auto-rebuild pipeline
When wiki content is pushed to main, the wiki-rebuild.yml GitHub Action automatically:
- Lints the wiki
- Rebuilds the Tractorpedia HTML viewer (
tools/act-wikipedia.html) - Syncs the command-center snapshot (
apps/command-center/public/wiki/) - Copies the viewer to
apps/command-center/public/tractorpedia.html - Dispatches to
act-regenerative-studioto sync its wiki JSON snapshots
You do NOT need to manually run wiki-build-viewer.mjs after every edit — just commit and push. The pipeline handles the rest. Run it manually only if you want to preview locally before pushing.
See also: wiki/AGENTS.md for agent-agnostic wiki conventions.
Operation: Ingest
Add a new source to the wiki and update affected articles.
Steps
Identify the source. The user provides a file path, URL, or pastes content.
- If URL: fetch with WebFetch and save to
wiki/raw/YYYY-MM-DD-<slug>.md - If file path: read the file, copy or reference it in
wiki/raw/ - If pasted content: save to
wiki/raw/YYYY-MM-DD-<slug>.md
- If URL: fetch with WebFetch and save to
Read the source. Extract key entities, concepts, facts, and relationships.
2a. Write a source summary to wiki/sources/<slug>.md. Always create one summary per ingested raw file. The summary captures: 1-line description, key facts (3-7 bullets), entities mentioned (linked), concepts touched (linked), and a backlink to the raw file. This is the bridge between immutable raw/ and the curated entity/concept layer.
Check existing articles. Read
wiki/index.mdto understand current wiki state. For each entity/concept found in the source, check if an article already exists.Update or create articles.
- If an article exists: read it, merge new information, preserve existing structure and backlinks, write updated file
- If no article exists: create a new article in the appropriate domain directory
- Use Obsidian
[[wikilinks]]format for all internal links:[[filename|Display Text]] - Add backlinks section at the bottom of every article
Update index. Add any new articles to
wiki/index.mdin the appropriate section.Report. Tell the user what was ingested, which articles were created/updated, and suggest related topics to explore.
Article Structure Template
# Title
> One-line summary or quote
## Overview
What this is and why it matters.
## [Domain-specific sections]
Details, data, evidence.
## Backlinks
- [[related-article|Display Name]] — how it connects
Domain Directory Guide
| Content Type | Directory | Examples |
|---|---|---|
| Frameworks, methodologies, theories | concepts/ |
LCAA, Third Reality |
| ACT ecosystem projects | projects/ |
CivicGraph, PICC, Empathy Ledger |
| Place-based relationships | communities/ |
Palm Island, Quandamooka |
| Key people and roles | people/ |
Named individuals with public roles |
| Artworks, installations, exhibitions | art/ |
Uncle Allan paintings, CONTAINED |
| Funding, grants, R&D, financial strategy | finance/ |
R&D tax, grant pipeline |
| Architecture, infrastructure, builds | technical/ |
Local AI, Supabase architecture |
| Key decisions and reasoning | decisions/ |
Dual entity structure, mono-repo |
| Compiled research and analysis | research/ |
ACCO sector, global precedents |
Rules for Ingestion
- Never modify files in
raw/. They are immutable source documents. - Always use
[[wikilinks]]—[[filename|Display Text]]format, no markdown links for internal references. - Preserve existing content. When updating an article, merge new info — don't overwrite what's already there.
- Add provenance. Note the source at the bottom of new/updated sections:
(Source: raw/YYYY-MM-DD-slug.md) - Cross-link aggressively. If an article mentions another wiki topic, link it.
- Keep articles focused. One article per entity/concept. Split if an article grows past ~200 lines.
Operation: Query
Research a question using the wiki as the knowledge base. Two modes:
/wiki query <question>— read-only, present the answer in chat/wiki synthesize <question>— same as query, then automatically save the answer as a synthesis article (no confirmation needed). This is the compounding loop — use it for any non-trivial question.
Steps
Read the index. Start at
wiki/index.mdto understand what's available. Also checkwiki/synthesis/index.md— the answer may already exist.Identify relevant articles. Based on the question, determine which articles to read. Use the index and backlinks to navigate.
Read relevant articles. Deep-read 3-7 articles that are most relevant to the question. Follow backlinks if needed.
Synthesize an answer. Combine information across articles into a coherent response. Cite which articles informed the answer.
Save back to synthesis (the compounding step).
- If the user invoked
/wiki synthesize, immediately call:
Or for long answers, pipe via stdin:node scripts/wiki-save-synthesis.mjs "<question>" "<answer markdown>" <citation1.md> <citation2.md> ...cat answer.md | node scripts/wiki-save-synthesis.mjs "<question>" --stdin <citations...> - If the user invoked
/wiki queryand the answer is non-trivial (multiple citations, real synthesis, not just a fact lookup), proactively offer to save it: "Want me to save this as a synthesis article so future queries can build on it?" - The script writes to
wiki/synthesis/<slug>.md, updateswiki/synthesis/index.md, and appends asynthesisentry towiki/log.mdautomatically.
- If the user invoked
Report. Tell the user what was answered, which articles were cited, and (if saved) the path to the synthesis article.
Rules for Queries
- Always cite sources. Reference which wiki articles informed your answer. The save-synthesis script preserves citations as wikilinks.
- Flag gaps. If the wiki doesn't have enough information, say so and suggest what to ingest into
raw/. - Synthesize, don't just retrieve. A query that returns the contents of one article isn't a synthesis. A query that combines facts from 3+ articles to produce a new claim is — and that's worth saving.
- Don't save trivial answers. Single-fact lookups ("what year was PICC founded?") don't need a synthesis page. Multi-source comparisons, contradictions, gap analyses, and "what's the trend across X" do.
Operation: Lint
Health check the wiki for quality, consistency, and completeness.
Checks to Run
Orphaned articles. Files in wiki directories that aren't linked from
index.mdor any other article.Broken wikilinks.
[[links]]that point to articles that don't exist.Stub articles. Articles with "Stub — needs enrichment" or fewer than 20 lines of content.
Missing backlinks. If article A links to article B, article B should link back to A.
Stale data. Articles with claims that can be verified against live data (Supabase, git, Notion). Flag anything that looks outdated.
Missing articles. Entities, people, or concepts mentioned in multiple articles but lacking their own article.
Index completeness. All articles should be listed in
wiki/index.md.
Steps
- Glob all
.mdfiles inwiki/(excludingraw/) - Read each file, extract all
[[wikilinks]] - Build a link graph: which articles link to which
- Run each check above
- Report findings as a health scorecard
Output Format
## Wiki Health Report — YYYY-MM-DD
**Articles:** X total (Y full, Z stubs)
**Links:** X total (Y valid, Z broken)
**Orphans:** X articles not linked from anywhere
**Missing backlinks:** X one-way links that need reciprocation
**Suggested new articles:** [list of frequently-mentioned but unwritten topics]
**Enrichment priority:** [top 5 stubs that would benefit most from enrichment]
Operation: Status
Quick overview of the wiki's current state.
Steps
- Count all
.mdfiles inwiki/by directory (excludingraw/) - Count files in
raw/ - Report total articles, articles per domain, raw sources
Output
## ACT Wikipedia Status
Total articles: X
concepts/: X | projects/: X | communities/: X
people/: X | art/: X | finance/: X
technical/: X | decisions/: X | research/: X
Raw sources: X
Last modified: [most recent file modification date]
Operation: Enrich
Flesh out a stub article or deepen an existing article using available data sources.
Steps
Read the current article. Understand what's already there.
Gather data from available sources:
- Supabase: query relevant tables (use
LIMIT 10for exploratory queries) - Notion: search for related pages
- Git history: check for related commits and code
thoughts/directory: look for related plans, research, handoffsconfig/directory: check for project configuration data- Web: fetch relevant public information if needed
- Supabase: query relevant tables (use
Enrich the article. Add sections, data, context, and backlinks. Maintain the existing article structure.
Update backlinks. If the enriched article now connects to new topics, add backlinks in both directions.
Update index if needed.
Rules for Enrichment
- Verify before writing. Don't add data you haven't confirmed from a source.
- Cite sources. Note where enrichment data came from.
- Don't fabricate. If you can't find data to enrich with, say so. Suggest what sources might help.
- Respect TK protocols. If enriching community or cultural articles, note where cultural review is needed.
Wiki Conventions
File Naming
- Use kebab-case:
goods-on-country.md,third-reality.md - Match project slugs from
config/active-projects.jsonwhere possible
Wikilinks
- Always use
[[filename|Display Text]]format - Filename is just the stem — no path, no
.mdextension - Example:
[[third-reality|The Third Reality]]
Backlinks Section
Every article ends with a ## Backlinks section listing related articles with a brief note on the relationship.
Provenance
When adding information from specific sources, note it inline: (Source: raw/2026-04-06-acco-report.md) or (Source: Supabase gs_entities table)
Article Size
- Stub: < 20 lines — needs enrichment
- Standard: 30-150 lines — solid article
- Comprehensive: 150-300 lines — deep reference
- Consider splitting if > 300 lines
Cultural Sensitivity
Articles about communities, Indigenous knowledge, or cultural practices should note where Elder/community review is needed. Never present cultural information as definitive without community validation.
Operation: Narrative
The narrative store is a Rowboat-style typed-entity layer that lives at wiki/narrative/<project>/. Each file is a claim — one public argument the project has made — with frontmatter (frame, channels, deployment count, audiences, sources) and a body that lists variants used, audience reactions, and an explicit ## What we haven't said yet section.
Read first: wiki/narrative/README.md — the schema, frame taxonomy, and lint rules.
The narrative layer answers a different question than the rest of the wiki. The wiki tells you what something is. The narrative store tells you what we have already said about it — so the next post builds on the last one instead of repeating it.
Subcommands
/wiki narrative status [project]
Read the project's INDEX.md and report:
- Frame distribution (which frames are overused, which are starved)
- Top 7 under-deployed claims (highest leverage)
- Recently-deployed claims (what's hot)
- Stat conflicts blocking publication
If no project is given, list all projects with claim counts.
/wiki narrative draft <project>
Run node scripts/narrative-draft.mjs <project> [--frame ...] [--channel ...] [--length ...] [--news-hook "..."].
The script reads the claim files, picks the right ones for the requested frame and channel, and writes a brief to wiki/output/narrative-drafts/<date>-<slug>.md. The brief is not the final post — it shows you (or the LLM writing the next post) which claims to build on, what we have already said (so we don't repeat), and what the gaps are (so we build something new).
Default behaviour:
- If no
--frameis given, picks the most starved frame automatically - Default
--lengthismedium(3 claims) - Default
--channelisoped - Selection mode is "gap" (least-deployed first); pass
--recentto build on momentum instead
After drafting the actual post against the brief, always call /wiki narrative log to record the deployment.
/wiki narrative oped <project>
Equivalent to /wiki narrative draft <project> --channel oped --length long. Pulls 5 claims, prefers under-deployed across multiple frames, and structures the brief for a long-form piece.
/wiki narrative log <claim-id> <channel>
Run node scripts/narrative-log-deployment.mjs <claim> <channel> [--source ...] [--variant "..."] [--audience ...] [--date ...].
Updates the claim file's frontmatter:
times_deployed+= 1last_used= today (or--date)channels+= channel if newstatusflips back toliveif it wasneeds-refresh- New entry in
sources:with the URL/path - Optional new row in the
## Variants usedtable
Then auto-runs narrative-refresh for the project so INDEX.md re-sorts.
Always log every public deployment. This is what keeps the system live.
/wiki narrative refresh [project]
Run node scripts/narrative-refresh.mjs [project].
Reads every claim file and regenerates INDEX.md:
- Most-recently-used claims at the top
- Frame distribution recomputed from frontmatter
- Top under-deployed claims surfaced
- Claims untouched > 90 days flipped to
status: needs-refresh
Run after every deployment (the log command does this automatically) or on a weekly cron.
Drafting an op-ed — the canonical workflow
/wiki narrative status contained— see the gap landscape- Pick a frame the campaign has not been leading with (usually
moral,confrontational, ortestimonialfor CONTAINED right now) /wiki narrative draft contained --frame moral --channel oped --news-hook "..."— generates a brief- Read the brief — confirm the picked claims are the right ones; if not, re-run with
--claimto target a specific one - Write the op-ed against the What we haven't said yet sections, not from memory
- Verify every stat against
STAT-CONFLICTS.mdbefore publishing. A hostile journalist will check the math. - After publishing:
/wiki narrative log <each-claim-id> <channel> --source <url> --variant "<the actual line>"for each claim used - The system now knows the claim has been used, the next draft will skip it, and the index updates automatically
Rules for narrative ops
- Never edit
INDEX.mdby hand. It's auto-regenerated bynarrative-refresh.mjsfrom the claim file frontmatter. Edit individual claim files instead. - Never invent stats. Every number must trace to a
sources:entry in a claim file. If it isn't sourced there, it doesn't go in a draft. - Always log deployments. A claim that was used but not logged looks "starved" to the next draft and gets recommended again — producing the exact "we've said this so many times" loop the system exists to prevent.
- The brief is not the post. The brief tells you which claims to build on. You (or the model) still write the post. Then you log it.
- Cross-project pollination. A claim in one project (e.g.
claim-built-by-handfor CONTAINED) can be referenced viarelated_claimsin another project's claim file. The narrative store is a graph, not a folder.
Ingestion — how the system learns from new content
The narrative store does not depend on humans hand-extracting every claim. It has a one-command ingestion pipeline that reads new content from any source — local files, JSON exports, scraped pages, database queries — and produces a structured digest that proposes which claims to update or create.
/wiki narrative ingest <path>
Run node scripts/narrative-ingest.mjs <path> --project <slug> --source-type <type>.
The script walks the path (file or folder), extracts:
- Stats — every dollar figure, percentage, and unit count via regex
- Named quotes —
"..." — Namepatterns - Argument paragraphs — paragraphs containing trigger phrases (
The argument is,The decision rule,The point is, etc.) - Headings — section structure for context
- Likely matches — keyword overlap against every existing claim file
It writes a digest to wiki/output/narrative-ingest/<date>-<source>.md that lists each finding with a suggested action: log as a variant of claim-X, file as new claim, log as audience reaction, or file in wiki/decisions/ instead because this is operational not narrative.
The script does not call an LLM API. It's heuristic. The point is to give Claude (you) a structured handoff so that processing the digest is one command, not a multi-hour read.
/wiki narrative process <digest>
Open the digest, walk through each finding, and apply the suggested actions:
- For "log as variant" findings →
node scripts/narrative-log-deployment.mjs <claim-id> <channel> --source <path> --variant "<line>" - For "new claim" findings → write a new
claim-*.mdfile using the template - For "audience reaction" findings → edit the matched claim file's
## Audience reactions loggedsection directly - For "file in decisions" findings → write to
wiki/decisions/instead, do not pollute the narrative store
After processing, run narrative-refresh (or wait — the log command auto-refreshes).
/wiki narrative watch [--schedule daily|weekly]
Run node scripts/narrative-watch.mjs [--schedule <s>] [--source <id>].
Reads wiki/narrative/sources.json — a config of every source the system watches — and ingests anything new since the last run. Tracks last-seen via wiki/narrative/.seen.json. Drop into a cron / launchd loop and the inbox fills automatically with digests for review.
Sources — what the system can learn from
wiki/narrative/sources.json lists every connected source. Edit that file to add new ones. Currently configured:
| Source | Type | Project | Wired |
|---|---|---|---|
act-wiki-raw-essays |
folder (wiki/raw/) |
contained | ✅ |
justicehub-compendium |
folder (JusticeHub) | contained | ✅ |
justicehub-output-emails |
folder | contained | ✅ |
justicehub-linkedin-engagement |
folder (JSON) | contained | ✅ (basic) |
justicehub-output-goods |
folder | goods-on-country | ✅ |
contained-site-content |
folder (Astro src) | contained | ✅ |
supabase-articles |
Supabase MCP query | auto | ⏳ adapter needed |
empathy-ledger-stories |
EL v2 Supabase | auto | ⏳ adapter needed |
ghl-contact-responses |
GHL API | auto | ⏳ adapter needed |
act-place-website |
URL scrape | auto | ⏳ adapter needed |
To wire a new source:
- Add it to
sources.jsonwithwired: trueif it's a local folder, orwired: falseif it needs an adapter - For local folders, no code needed —
narrative-watch.mjspicks it up automatically - For Supabase / GHL / EL APIs, add an adapter case in
narrative-watch.mjsthat fetches the data, writes it to a temp.mdfile, then callsnarrative-ingest.mjson that file - For URL scrapes, use
firecrawl_scrape(MCP) and pipe the result through ingest
Cross-project linking
Claim files can reference claims in other projects via related_claims: [project:claim-id, ...]. Example: goods-on-country/claim-bed-to-courtroom.md references contained:claim-goods-on-country-bed-pipeline. The same argument can live in multiple projects with different framings, and the relationship is explicit.
This is how the strategy compounds across the ecosystem — a Goods on Country pitch can pull a CONTAINED claim, a CONTAINED essay can pull a Goods claim, and the deployment-logging flows in both directions.
Funder targeting (--funder <slug>)
wiki/narrative/funders.json lists every active funder with their thesis tags, stage, deadline, primary contact, and the specific claims that should lead any pitch to them. The draft script reads this file when invoked with --funder:
node scripts/narrative-draft.mjs contained \
--funder qbe-catalysing-impact \
--channel pitch --length long
The script:
- Loads claims from all projects (so cross-project picks work — a QBE pitch can pull both
contained:andgoods-on-country:claims) - Pulls exactly the claims listed in
funders[slug].claims_to_lead_with - Refuses to include any claim in
claims_to_avoid - Includes the funder's framing notes, tone, and deadline at the top of the brief
- Logs the pitch via the same deployment workflow
When you add a new funder to the pipeline, add them to funders.json. When a funder's thesis shifts, update their claims_to_lead_with. The system does not infer the right pitch — you tell it once, then it applies the same logic forever.
Campaign cycle filtering (--cycle <phase>)
Claim files can carry a cycle: array in frontmatter — pre-launch, launch, tour-stop, budget-week, funder-pitch, term-sheet, election-cycle, always, etc. The draft script filters by cycle:
node scripts/narrative-draft.mjs contained --cycle budget-week --frame confrontational
Pick the cycle when the campaign moment changes — launch week, budget week, parliament sitting, election, term sheet pending. Claims that don't carry the matching cycle tag are excluded from the pool, so the brief only shows what's appropriate for the moment.
Weekly strategy review (/wiki narrative review)
Run node scripts/narrative-strategy-review.mjs [project] weekly. It writes wiki/narrative/<project>/STRATEGY-REVIEW.md containing:
- Frame budget — actual vs recommended distribution, with
over/starvedflags. The "what frame should I lead with this week" answer in one table. - Audience coverage — under-served audiences flagged
- Channel freshness — when each channel was last touched, color-coded by recency
- Cold claims — anything untouched 30+ days, ranked
- Funder pipeline — funders with open asks whose lead-with claims have gone cold (14+ days). Names the specific funder and the specific claim.
- Cycle coverage — how many claims tagged for each cycle phase
- This week's recommended actions — 3-4 concrete commands to run
The strategy review file IS the campaign retro. No meeting required — open the file Monday morning, run the recommended commands, ship the post.
Wired sources
Every adapter is built and wired in narrative-watch.mjs:
- Local folders — JusticeHub compendium, output, contained-site content, wiki/raw, Goods folder
scripts/narrative-adapters/supabase-articles.mjs— pulls published articles from the shared Supabase, routes by tag/category to the right project, ingestsscripts/narrative-adapters/el-stories.mjs— pulls Empathy Ledger v2 stories with default-deny consent enforcement (internal-onlyis refused at the adapter layer;with-careis tagged in the digest so downstream draft scripts respect the constraint)scripts/narrative-adapters/ghl-responses.mjs— pulls contact notes forcontained-*andgoods-*tagged contacts via the existingGHLServicescripts/narrative-adapters/url-scrape.mjs— fetches a URL, converts to text, diffs against last snapshot atwiki/narrative/.url-snapshots/, only ingests if changed. Falls back to plainfetch+ HTML→text; uses Firecrawl ifUSE_FIRECRAWL=1andFIRECRAWL_API_KEYare set.
Run all of them at once:
node scripts/narrative-watch.mjs # daily + weekly sources
node scripts/narrative-watch.mjs --schedule daily
node scripts/narrative-watch.mjs --source supabase-articles # single source
narrative-watch.mjs dispatches by source.type to the right adapter, deduplicates against wiki/narrative/.seen.json, and leaves digests in the inbox for /wiki narrative process.