
Wiki Builder
- 52 installs
- 2.8k repo stars
- Updated August 3, 2026
- rohitg00/pro-workflow
Helps with ai & agent building tasks during AI-assisted development.
About
wiki-builder is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- wiki-builder
- AI & Agent Building
- AI-coding skill
Wiki Builder by the numbers
- 52 all-time installs (skills.sh)
- +12 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #7,112 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/rohitg00/pro-workflow --skill wiki-builderAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 52 |
|---|---|
| repo stars | ★ 2.8k |
| Last updated | August 3, 2026 |
| Repository | rohitg00/pro-workflow ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Wiki Builder
Persistent knowledge base for any topic. Markdown on disk + SQLite FTS5 shadow index.
When to use
- "Start a wiki on <topic>"
- "Add this paper / link / note to the <slug> wiki"
- "Compile a concept page on X in <slug>"
- "What does the <slug> wiki say about Y?" (delegates to wiki-query)
- "List my wikis"
Locations
- Global:
~/.pro-workflow/wikis/<slug>/— default, never committed - Project:
<project>/.claude/wikis/<slug>/— pass--scope project, committable
Both register in the same ~/.pro-workflow/data.db.
Flavors
| Flavor | Use for |
|---|---|
research | ongoing topic exploration |
paper | one-paper deep dive |
domain | broad subject area |
product | product/tool KB |
person | researcher/founder dossier |
organization | company/lab profile |
project | internal project KB |
codebase | symbol/file-aware KB tied to a repo |
incident | post-mortem KB |
Layout
<slug>/
├── wiki.config.md # purpose, audience, page types, style, auto_research block
├── raw/ # untouched source material (PDFs, scrapes, transcripts)
├── wiki/
│ └── index.md # entry point, hand-curated TOC
├── derived/ # generated artifacts (surveys, charts, summaries)
├── prompts/ # per-task prompts (compile-page, lint, query)
├── logs/maintenance-log.md
└── sources.md # one row per source: id | url | title | hash | fetched_atFlavor adds folders: wiki/papers, wiki/concepts, wiki/people, wiki/products, wiki/timelines, wiki/questions.
CLI surface
node $SKILL_ROOT/scripts/wiki-cli.js init <slug> --title "X" --flavor research [--scope project] [--root <path>]
node $SKILL_ROOT/scripts/wiki-cli.js list
node $SKILL_ROOT/scripts/wiki-cli.js page <slug> <rel-path> --title "X" [--type concept|paper|person|...] [--from-file path]
node $SKILL_ROOT/scripts/wiki-cli.js reindex <slug>
node $SKILL_ROOT/scripts/wiki-cli.js info <slug>init runs init_wiki.sh (mirrors dair layout) AND registers the wiki in SQLite. page writes markdown + upserts FTS row.
Workflow when invoked
1. Resolve action (init / ingest / compile / list / reindex / info). 2. Read wiki.config.md of the target wiki before any compile. 3. Every claim that lands in wiki/ must cite a row in sources.md (one citation = one source row). 4. After page write, call wiki-cli.js page so FTS index stays in sync. 5. Append a one-line entry to logs/maintenance-log.md per change. 6. Update wiki/index.md if new top-level page.
Quality bar
- First page useful immediately, not stub.
- Stable slug filenames (
tool-use-benchmarks.md, not2026-05-08-notes.md). - Separate raw source from compiled interpretation.
- Cross-link related pages in same wiki via relative links.
- Mark speculation with
> SPECULATION:block. - No duplicate summaries — link existing page instead.
- Generated pages stay navigable for future agents.
Privacy
Wikis with private: true in config never get fetched from web sources by wiki-research-loop. Local raw/ only.
Auto-research opt-in
Phase 3.3.0 ships builder + query only. Loop arrives in 3.3.1. To prep, wiki.config.md may include:
auto_research:
enabled: false # flip in 3.3.1
max_pages_per_run: 5
max_depth: 3
budget_usd: 0.50
fetchers: [web, arxiv, github]Templates
See templates/ for wiki.config.md, index.md, prompt files. init_wiki.sh copies these into the new wiki root.
interface:
display_name: "Wiki Builder"
short_description: "Persistent research wikis indexed in pro-workflow's SQLite FTS5 store"
brand_color: "#1e1e2e"
default_prompt: "Use $wiki-builder to start a new persistent research wiki. Pages auto-index for FTS5 retrieval."
Wiki Flavors
Starting points only. Each wiki's wiki.config.md overrides any structure listed here.
Research
Ongoing topic with many source types.
wiki/index.md— overview + navigationwiki/maps/research-map.md— conceptual mapwiki/concepts/<concept>.md— durable ideaswiki/sources/<source>.md— important source writeupswiki/questions/<question>.md— open investigationsderived/briefs/— synthesis memos
Paper
A paper, paper cluster, or literature review.
wiki/index.md— paper-set overviewwiki/papers/<paper-slug>.md— individual paperswiki/concepts/<concept>.md— reusable technical ideaswiki/comparisons/<topic>.md— cross-paper comparisonswiki/questions/<question>.md— research gaps
Paper pages cover: problem, method, results, limitations, implementation notes, related papers.
Domain
Tracking an entire field.
wiki/index.md— high-level mapwiki/landscape.md— actors, concepts, tools, debateswiki/timelines/<topic>.md— historical developmentwiki/glossary.md— termswiki/questions/<question>.md— active uncertainties
Product
Products, tools, APIs, platforms.
wiki/index.md— product summarywiki/features/<feature>.md— feature pageswiki/use-cases/<use-case>.md— applied workflowswiki/competitors/<competitor>.md— alternativeswiki/questions/<question>.md— evaluation gaps
Distinguish documented behavior, observed behavior, pricing/availability, limitations, integration notes.
Person
Researcher, founder, writer, public expert.
wiki/index.md— profile + navigationwiki/work/<work-slug>.md— papers, talks, posts, projects, artifactswiki/themes/<theme>.md— recurring ideaswiki/timeline.md— dated milestoneswiki/questions/<question>.md— unresolved context
Source-grounded language only. No unsupported biographical claims.
Organization
Labs, companies, communities, institutions.
wiki/index.md— overviewwiki/projects/<project>.md— important initiativeswiki/people/<person>.md— relevant peoplewiki/timeline.md— milestoneswiki/strategy.md— source-grounded strategic analysis
Separate facts from interpretation, especially for strategy.
Project
Internal build, research initiative, course, content project.
wiki/index.md— status + navigationwiki/decisions/<decision>.md— important choiceswiki/specs/<spec>.md— requirementswiki/notes/<note>.md— working notesderived/briefs/— summaries + handoffs
Project wikis make current state obvious to the next agent.
Codebase (pro-workflow extension)
Symbol/file-aware KB tied to a repo.
wiki/index.md— module mapwiki/modules/<module>.md— per-module deep divewiki/symbols/<symbol>.md— high-traffic types/functionswiki/decisions/<decision>.md— ADR-style entrieswiki/runbooks/<flow>.md— operational sequenceswiki/questions/<question>.md— open architecture questions
Pages link to file paths; reindex on git pull. Pair with --scope project for committable form.
Incident (pro-workflow extension)
Post-mortem KB.
wiki/index.md— incident rosterwiki/timeline/<incident>.md— minute-by-minutewiki/signals/<signal>.md— early-warning patternswiki/fixes/<fix>.md— applied remedieswiki/questions/<question>.md— what we still don't know
Pin status (active | resolved | recurring). Cross-link to runbooks if a codebase wiki exists.
#!/usr/bin/env bash
set -euo pipefail
slug=""
title=""
flavor="research"
scope="global"
root=""
usage() {
cat <<EOF
Usage: init_wiki.sh <slug> --title "<title>" [--flavor <flavor>] [--scope global|project] [--root <path>]
Flavors: research paper domain product person organization project codebase incident
EOF
}
if [ $# -lt 1 ]; then usage; exit 1; fi
slug="$1"; shift
if ! [[ "$slug" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
echo "Invalid slug: lowercase letters, digits, hyphens only (must start alphanumeric)" >&2
exit 1
fi
while [ $# -gt 0 ]; do
case "$1" in
--title) title="$2"; shift 2 ;;
--flavor) flavor="$2"; shift 2 ;;
--scope) scope="$2"; shift 2 ;;
--root) root="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown arg: $1" >&2; usage; exit 1 ;;
esac
done
if [ -z "$title" ]; then echo "--title required" >&2; exit 1; fi
case "$scope" in
global|project) ;;
*) echo "Invalid --scope: $scope (expected global|project)" >&2; exit 1 ;;
esac
case "$flavor" in
research|paper|domain|product|person|organization|project|codebase|incident) ;;
*) echo "Invalid --flavor: $flavor" >&2; exit 1 ;;
esac
if [ -z "$root" ]; then
if [ "$scope" = "project" ]; then
project_dir="${CLAUDE_PROJECT_DIR:-$PWD}"
root="$project_dir/.claude/wikis"
else
root="${WIKI_ROOT:-$HOME/.pro-workflow/wikis}"
fi
fi
dest="$root/$slug"
if [ -d "$dest" ]; then
echo "Wiki already exists: $dest" >&2
exit 2
fi
mkdir -p "$dest"/{raw,wiki,derived,prompts,logs}
case "$flavor" in
paper) mkdir -p "$dest/wiki/sections" ;;
domain|research) mkdir -p "$dest/wiki"/{concepts,papers,questions} ;;
product) mkdir -p "$dest/wiki"/{features,decisions,issues} ;;
person|organization) mkdir -p "$dest/wiki"/{publications,timelines} ;;
project) mkdir -p "$dest/wiki"/{decisions,runbooks,questions} ;;
codebase) mkdir -p "$dest/wiki"/{modules,symbols,decisions} ;;
incident) mkdir -p "$dest/wiki"/{timeline,signals,fixes} ;;
esac
skill_dir="$(cd "$(dirname "$0")"/.. && pwd)"
templates="$skill_dir/templates"
render() {
local src="$1" dst="$2"
sed -e "s|{{SLUG}}|$slug|g" \
-e "s|{{TITLE}}|$title|g" \
-e "s|{{FLAVOR}}|$flavor|g" \
-e "s|{{SCOPE}}|$scope|g" \
-e "s|{{TODAY}}|$(date -u +%Y-%m-%d)|g" \
"$src" > "$dst"
}
render "$templates/wiki.config.md" "$dest/wiki.config.md"
render "$templates/index.md" "$dest/wiki/index.md"
render "$templates/sources.md" "$dest/sources.md"
render "$templates/maintenance-log.md" "$dest/logs/maintenance-log.md"
for p in compile-index compile-source-page compile-concept-page query-and-file lint-wiki; do
if [ -f "$templates/prompts/$p.md" ]; then
render "$templates/prompts/$p.md" "$dest/prompts/$p.md"
fi
done
echo "$dest"
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const os = require('os');
const crypto = require('crypto');
const { execFileSync } = require('child_process');
const PRO_WORKFLOW_ROOT = path.resolve(__dirname, '..', '..', '..');
function getStore() {
const distPath = path.join(PRO_WORKFLOW_ROOT, 'dist', 'db', 'store.js');
if (!fs.existsSync(distPath)) {
die(`Built store missing at ${distPath}. Run: cd ${PRO_WORKFLOW_ROOT} && npm install && npm run build`);
}
const mod = require(distPath);
if (typeof mod.createStore !== 'function') die('createStore not exported');
return mod.createStore();
}
function die(msg) {
console.error(`[wiki] ${msg}`);
process.exit(1);
}
function parseArgs(argv) {
const out = { _: [] };
for (let i = 0; i < argv.length; i++) {
const a = argv[i];
if (a.startsWith('--')) {
const key = a.slice(2);
const next = argv[i + 1];
if (next && !next.startsWith('--')) { out[key] = next; i++; }
else out[key] = true;
} else {
out._.push(a);
}
}
return out;
}
function defaultRoot(scope) {
if (scope === 'project') {
const proj = process.env.CLAUDE_PROJECT_DIR || process.cwd();
return path.join(proj, '.claude', 'wikis');
}
return process.env.WIKI_ROOT || path.join(os.homedir(), '.pro-workflow', 'wikis');
}
function sha256(s) {
return crypto.createHash('sha256').update(s).digest('hex').slice(0, 16);
}
function cmdInit(args) {
const slug = args._[0];
if (!slug) die('init: slug required');
const title = args.title || slug;
const flavor = args.flavor || 'research';
const scope = args.scope || 'global';
const root = args.root || defaultRoot(scope);
const initSh = path.join(__dirname, 'init_wiki.sh');
const dest = execFileSync('bash', [initSh, slug, '--title', title, '--flavor', flavor, '--scope', scope, '--root', root], { encoding: 'utf8' }).trim();
const store = getStore();
try {
store.upsertWiki({ slug, title, flavor, root_path: dest, scope });
} catch (e) {
die(e.message);
} finally {
store.close();
}
console.log(JSON.stringify({ slug, title, flavor, scope, root_path: dest }, null, 2));
}
function cmdList(args) {
const store = getStore();
try {
const wikis = store.listWikis(args.scope);
if (args.json) { console.log(JSON.stringify(wikis, null, 2)); return; }
if (!wikis.length) { console.log('(no wikis)'); return; }
for (const w of wikis) {
console.log(`${w.slug.padEnd(24)} ${w.flavor.padEnd(12)} ${w.scope.padEnd(8)} ${w.root_path}`);
}
} finally {
store.close();
}
}
function cmdInfo(args) {
const slug = args._[0];
if (!slug) die('info: slug required');
const store = getStore();
try {
const wiki = store.getWiki(slug);
if (!wiki) die(`unknown wiki: ${slug}`);
const pages = store.listWikiPages(slug);
console.log(JSON.stringify({ wiki, page_count: pages.length, pages: pages.map(p => p.rel_path) }, null, 2));
} finally {
store.close();
}
}
function cmdPage(args) {
const slug = args._[0];
const relPath = args._[1];
if (!slug || !relPath) die('page: slug and rel-path required');
const store = getStore();
try {
const wiki = store.getWiki(slug);
if (!wiki) die(`unknown wiki: ${slug}. Run: wiki-cli.js init ${slug} --title "..."`);
const rootAbs = path.resolve(wiki.root_path);
const fileAbs = path.resolve(wiki.root_path, relPath);
if (fileAbs !== rootAbs && !fileAbs.startsWith(rootAbs + path.sep)) {
die(`rel-path escapes wiki root: ${relPath}`);
}
let content = '';
if (args['from-file']) {
content = fs.readFileSync(args['from-file'], 'utf8');
fs.mkdirSync(path.dirname(fileAbs), { recursive: true });
fs.writeFileSync(fileAbs, content);
} else if (fs.existsSync(fileAbs)) {
content = fs.readFileSync(fileAbs, 'utf8');
} else {
die(`page file does not exist: ${fileAbs}. Pass --from-file or write the file first.`);
}
const title = args.title || extractTitle(content) || path.basename(relPath, '.md');
const summary = args.summary || extractSummary(content);
const pageType = args.type || inferType(relPath);
const row = store.upsertWikiPage({
wiki_slug: slug,
rel_path: relPath,
title,
summary,
content,
page_type: pageType,
content_hash: sha256(content),
});
console.log(JSON.stringify({ id: row.id, wiki_slug: slug, rel_path: relPath, title, page_type: pageType }, null, 2));
} finally {
store.close();
}
}
function cmdReindex(args) {
const slug = args._[0];
if (!slug) die('reindex: slug required');
const store = getStore();
try {
const wiki = store.getWiki(slug);
if (!wiki) die(`unknown wiki: ${slug}`);
const wikiDir = path.join(wiki.root_path, 'wiki');
if (!fs.existsSync(wikiDir)) die(`no wiki/ folder at ${wikiDir}`);
let count = 0;
walk(wikiDir).forEach(abs => {
if (!abs.endsWith('.md')) return;
const rel = path.relative(wiki.root_path, abs);
const content = fs.readFileSync(abs, 'utf8');
store.upsertWikiPage({
wiki_slug: slug,
rel_path: rel,
title: extractTitle(content) || path.basename(rel, '.md'),
summary: extractSummary(content),
content,
page_type: inferType(rel),
content_hash: sha256(content),
});
count++;
});
console.log(JSON.stringify({ slug, indexed: count }, null, 2));
} finally {
store.close();
}
}
function walk(dir) {
const out = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const abs = path.join(dir, entry.name);
if (entry.isDirectory()) out.push(...walk(abs));
else out.push(abs);
}
return out;
}
function extractTitle(md) {
const m = md.match(/^#\s+(.+)$/m);
return m ? m[1].trim() : null;
}
function extractSummary(md) {
const stripped = md.replace(/^---[\s\S]*?---\s*/m, '').replace(/^#.*\n/m, '').trim();
const para = stripped.split(/\n\n/)[0] || '';
return para.slice(0, 500) || null;
}
function inferType(relPath) {
const parts = relPath.split(path.sep);
if (parts[0] === 'wiki' && parts.length >= 3) return parts[1].replace(/s$/, '');
return null;
}
function usage() {
console.error(`Usage:
wiki-cli.js init <slug> --title "X" [--flavor research] [--scope global|project] [--root path]
wiki-cli.js list [--scope global|project] [--json]
wiki-cli.js info <slug>
wiki-cli.js page <slug> <rel-path> [--title "X"] [--type concept|paper|...] [--from-file path]
wiki-cli.js reindex <slug>`);
process.exit(1);
}
function main() {
const [, , cmd, ...rest] = process.argv;
const args = parseArgs(rest);
switch (cmd) {
case 'init': return cmdInit(args);
case 'list': return cmdList(args);
case 'info': return cmdInfo(args);
case 'page': return cmdPage(args);
case 'reindex': return cmdReindex(args);
default: usage();
}
}
main();
{{TITLE}}
{{FLAVOR}} wiki · created {{TODAY}}
A persistent knowledge base on {{TITLE}}.
Sections
_Add links to compiled pages here as you build them._
Open questions
_List unresolved threads. New seeds for the research loop start here._
Sources
See sources.md.
Maintenance log
See logs/maintenance-log.md.
Maintenance Log — {{TITLE}}
One line per change. Newest on top.
- {{TODAY}} init: scaffolded wiki ({{FLAVOR}}, {{SCOPE}})
Compile concept page — {{TITLE}}
Synthesize a single idea across multiple sources. Output wiki/concepts/<slug>.md:
1. One-line definition that future-you will trust. 2. Why it matters — when this concept changes a decision. 3. Variants / related concepts with cross-links. 4. Evidence — bulleted claims [^src-id], multi-source where possible. 5. Counter-evidence — claims that contradict, also cited. 6. Status: stable | contested | speculative.
Rules:
- A concept page that cites only one source is suspect; flag in the page header.
- Prefer multi-source synthesis over single-source restatement.
- Link to relevant
paper/<key>.mdpages instead of restating the paper.
Compile index — {{TITLE}}
Refresh wiki/index.md so it stays the entry point.
1. List sections by type (concepts, papers, questions...). 2. Within each section, link pages alphabetically by slug. 3. Surface 3-5 "open questions" pulled from question/ pages with status open. 4. Top of file: 2-line orientation paragraph. 5. Bottom: link to sources.md and logs/maintenance-log.md.
Never delete user prose at the top; only update the generated section bounded by:
<!-- BEGIN GENERATED INDEX -->
...
<!-- END GENERATED INDEX -->Compile source page — {{TITLE}}
Given a single source (paper, blog, video transcript, doc), produce wiki/<type>/<slug>.md with:
1. Front-matter: title, source_id, page_type, last_verified. 2. One-paragraph TL;DR in plain language. 3. Key claims as bulleted list, each suffixed [^src-id]. 4. Method / argument summary — what the source actually does, not editorial. 5. Open questions raised — feed back into wiki seeds. 6. Cross-links — relative links to existing pages in this wiki when topics overlap.
Rules:
- Never paraphrase without citing.
- Never copy long verbatim quotes. Two sentences max per quote.
- If source is paywalled or
private: true, skip web verification. - Mark inferences with
> SPECULATION:.
Lint wiki — {{TITLE}}
Audit the wiki and report (do not auto-fix unless asked):
1. Orphan pages — pages not linked from wiki/index.md or any other page. 2. Broken cross-links — relative links pointing to missing files. 3. Uncited claims — paragraphs in wiki/ with no [^src-id] reference. 4. Stale claims — last_verified_at older than 90 days. 5. Duplicate summaries — pages whose first paragraph is >80% similar to another's. 6. Missing sources rows — [^src-NNN] cited but src-NNN not in sources.md.
Output a report under derived/lint-{{TODAY}}.md. Do not modify wiki/ content.
Query and file — {{TITLE}}
When a user asks a question that the wiki should answer:
1. Search the wiki via wiki-query (FTS5). 2. If a page already covers the answer, cite it directly. Do not duplicate. 3. If coverage is partial, draft an addendum to the existing page. 4. If no coverage, create the appropriate page type (concept/paper/question/...). 5. If still uncertain, file a question/<slug>.md and append it as a seed for the research loop (Phase 3.3.1+).
Always echo the answer with citations. Never fabricate citations.
Sources — {{TITLE}}
Every claim in wiki/ cites a row from this table by [^id].
| id | type | url / path | title | hash | fetched_at |
|---|
<!-- Append new rows under the header. id format: src-NNN. -->
{{TITLE}} — Wiki Config
Purpose
Why this wiki exists. Who reads it. What questions it answers.
Audience
Primary: <author / future-you / team> Secondary: <other agents that might query this wiki>
Page types
concept/<slug>.md— durable explanation of a single ideapaper/<key>.md— one-paper deep dive (key = author-year-shortname)question/<slug>.md— open question, links to claims/papers that bear on itnote/<date>-<slug>.md— dated raw thinking, may be promoted to concept later
Adjust per flavor.
Style rules
- Plain markdown, no HTML.
- Headings: H1 = page title, H2 = top-level section, H3 = subsection.
- Citations inline as
[^src-id]referencingsources.mdrow. - Speculation marked
> SPECULATION:blockquote. - Each page ≤ 1500 words; split if longer.
Update workflow
1. Land raw material in raw/ (PDFs, scrapes, transcripts). 2. Add a row to sources.md (id, url, title, hash, fetched_at). 3. Compile wiki/<type>/<slug>.md citing those sources. 4. Cross-link from wiki/index.md. 5. Run wiki-cli.js page to update the FTS index. 6. Append a one-line entry to logs/maintenance-log.md.
Auto-research
Loop is opt-in. Set auto_research.enabled: true once Phase 3.3.1 ships. Budget caps are enforced; loop halts on cap or convergence.