feat(wiki): add 5 builtin wiki commands based on Karpathy's LLM Wiki pattern
Adds /wiki-init, /wiki-ingest, /wiki-query, /wiki-lint, /wiki-update as builtin commands. These implement a structured knowledge wiki at .sisyphus/wiki/ that reduces session startup tokens by accumulating and maintaining condensed knowledge pages instead of re-reading raw source files every time. - wiki-init: bootstraps wiki directory structure (SCHEMA.md, index.md, log.md, overview.md, pages/) - wiki-ingest: adds sources with takeaway extraction, backlink audit, and index/overview updates - wiki-query: answers questions strictly from wiki content (never from memory), offers to save answers as new pages - wiki-lint: read-only health audit (broken links, orphans, contradictions, coverage gaps, stale sources) - wiki-update: revises pages with diff preview, stale-claim sweep across all pages, source citation Based on Karpathy's LLM Wiki pattern (kfchou/wiki-skills). 68 command tests pass.
This commit is contained in:
@@ -9,6 +9,11 @@ export const BuiltinCommandNameSchema = z.enum([
|
||||
"start-work",
|
||||
"stop-continuation",
|
||||
"remove-ai-slops",
|
||||
"wiki-init",
|
||||
"wiki-ingest",
|
||||
"wiki-query",
|
||||
"wiki-lint",
|
||||
"wiki-update",
|
||||
])
|
||||
|
||||
export type BuiltinCommandName = z.infer<typeof BuiltinCommandNameSchema>
|
||||
|
||||
@@ -4,6 +4,11 @@ import { afterEach, beforeEach, describe, test, expect } from "bun:test"
|
||||
import { loadBuiltinCommands } from "./commands"
|
||||
import { HANDOFF_TEMPLATE } from "./templates/handoff"
|
||||
import { REMOVE_AI_SLOPS_TEMPLATE } from "./templates/remove-ai-slops"
|
||||
import { WIKI_INIT_TEMPLATE } from "./templates/wiki-init"
|
||||
import { WIKI_INGEST_TEMPLATE } from "./templates/wiki-ingest"
|
||||
import { WIKI_QUERY_TEMPLATE } from "./templates/wiki-query"
|
||||
import { WIKI_LINT_TEMPLATE } from "./templates/wiki-lint"
|
||||
import { WIKI_UPDATE_TEMPLATE } from "./templates/wiki-update"
|
||||
import type { BuiltinCommandName } from "./types"
|
||||
import { _resetForTesting, registerAgentName } from "../claude-code-session-state"
|
||||
|
||||
@@ -259,3 +264,374 @@ describe("HANDOFF_TEMPLATE", () => {
|
||||
expect(emojiRegex.test(HANDOFF_TEMPLATE)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("loadBuiltinCommands - wiki commands", () => {
|
||||
test("should register wiki-init in loaded commands", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = []
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-init"]).toBeDefined()
|
||||
expect(commands["wiki-init"].name).toBe("wiki-init")
|
||||
expect(commands["wiki-init"].template).toContain(WIKI_INIT_TEMPLATE)
|
||||
expect(commands["wiki-init"].description).toContain("(builtin)")
|
||||
})
|
||||
|
||||
test("should register wiki-ingest in loaded commands", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = []
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-ingest"]).toBeDefined()
|
||||
expect(commands["wiki-ingest"].name).toBe("wiki-ingest")
|
||||
expect(commands["wiki-ingest"].template).toContain(WIKI_INGEST_TEMPLATE)
|
||||
expect(commands["wiki-ingest"].template).toContain("$ARGUMENTS")
|
||||
})
|
||||
|
||||
test("should register wiki-query in loaded commands", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = []
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-query"]).toBeDefined()
|
||||
expect(commands["wiki-query"].name).toBe("wiki-query")
|
||||
expect(commands["wiki-query"].template).toContain(WIKI_QUERY_TEMPLATE)
|
||||
expect(commands["wiki-query"].template).toContain("$ARGUMENTS")
|
||||
})
|
||||
|
||||
test("should register wiki-lint in loaded commands", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = []
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-lint"]).toBeDefined()
|
||||
expect(commands["wiki-lint"].name).toBe("wiki-lint")
|
||||
expect(commands["wiki-lint"].template).toContain(WIKI_LINT_TEMPLATE)
|
||||
})
|
||||
|
||||
test("should register wiki-update in loaded commands", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = []
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-update"]).toBeDefined()
|
||||
expect(commands["wiki-update"].name).toBe("wiki-update")
|
||||
expect(commands["wiki-update"].template).toContain(WIKI_UPDATE_TEMPLATE)
|
||||
expect(commands["wiki-update"].template).toContain("$ARGUMENTS")
|
||||
})
|
||||
|
||||
test("should exclude wiki-init when disabled", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = ["wiki-init"]
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-init"]).toBeUndefined()
|
||||
})
|
||||
|
||||
test("should exclude wiki-ingest when disabled", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = ["wiki-ingest"]
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-ingest"]).toBeUndefined()
|
||||
})
|
||||
|
||||
test("should exclude wiki-query when disabled", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = ["wiki-query"]
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-query"]).toBeUndefined()
|
||||
})
|
||||
|
||||
test("should exclude wiki-lint when disabled", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = ["wiki-lint"]
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-lint"]).toBeUndefined()
|
||||
})
|
||||
|
||||
test("should exclude wiki-update when disabled", () => {
|
||||
//#given
|
||||
const disabledCommands: BuiltinCommandName[] = ["wiki-update"]
|
||||
|
||||
//#when
|
||||
const commands = loadBuiltinCommands(disabledCommands)
|
||||
|
||||
//#then
|
||||
expect(commands["wiki-update"]).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("WIKI_INIT_TEMPLATE", () => {
|
||||
test("should reference the canonical wiki root .sisyphus/wiki/", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INIT_TEMPLATE).toContain(".sisyphus/wiki/")
|
||||
})
|
||||
|
||||
test("should create the four canonical top-level files and pages directory", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("index.md")
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("log.md")
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("overview.md")
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("SCHEMA.md")
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("pages/")
|
||||
})
|
||||
|
||||
test("should refuse to clobber an existing wiki without explicit user consent", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("already exists")
|
||||
})
|
||||
|
||||
test("should declare the page front-matter contract", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("front-matter")
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("sources")
|
||||
expect(WIKI_INIT_TEMPLATE).toContain("backlinks")
|
||||
})
|
||||
|
||||
test("should not contain emojis", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u
|
||||
expect(emojiRegex.test(WIKI_INIT_TEMPLATE)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("WIKI_INGEST_TEMPLATE", () => {
|
||||
test("should require reading the source before writing anything", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("Read")
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("source")
|
||||
})
|
||||
|
||||
test("should ban writing claims that are not present in the source", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("memory")
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("only what the source supports")
|
||||
})
|
||||
|
||||
test("should require extracting takeaways before drafting the page", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("Takeaways")
|
||||
})
|
||||
|
||||
test("should require updating index.md and appending to log.md", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("index.md")
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("log.md")
|
||||
})
|
||||
|
||||
test("should require a backlink audit pass", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain("backlink")
|
||||
})
|
||||
|
||||
test("should write pages under .sisyphus/wiki/pages/", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_INGEST_TEMPLATE).toContain(".sisyphus/wiki/pages/")
|
||||
})
|
||||
|
||||
test("should not contain emojis", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u
|
||||
expect(emojiRegex.test(WIKI_INGEST_TEMPLATE)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("WIKI_QUERY_TEMPLATE", () => {
|
||||
test("should answer strictly from wiki contents and never from memory", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_QUERY_TEMPLATE).toContain("never")
|
||||
expect(WIKI_QUERY_TEMPLATE).toContain("memory")
|
||||
})
|
||||
|
||||
test("should require reading index.md first", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_QUERY_TEMPLATE).toContain("index.md")
|
||||
})
|
||||
|
||||
test("should require citing every claim by source", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_QUERY_TEMPLATE).toContain("cite")
|
||||
})
|
||||
|
||||
test("should offer to save the answer as a new cited page", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_QUERY_TEMPLATE).toContain("save")
|
||||
expect(WIKI_QUERY_TEMPLATE).toContain("page")
|
||||
})
|
||||
|
||||
test("should declare an explicit fallback when the wiki has no answer", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_QUERY_TEMPLATE).toContain("not in the wiki")
|
||||
})
|
||||
|
||||
test("should not contain emojis", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u
|
||||
expect(emojiRegex.test(WIKI_QUERY_TEMPLATE)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("WIKI_LINT_TEMPLATE", () => {
|
||||
test("should detect contradictions across pages", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_LINT_TEMPLATE).toContain("contradiction")
|
||||
})
|
||||
|
||||
test("should detect broken internal links", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_LINT_TEMPLATE).toContain("broken link")
|
||||
})
|
||||
|
||||
test("should detect orphan pages with no inbound backlinks", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_LINT_TEMPLATE).toContain("orphan")
|
||||
})
|
||||
|
||||
test("should detect coverage gaps", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_LINT_TEMPLATE).toContain("gap")
|
||||
})
|
||||
|
||||
test("should write the report to pages/lint-report.md", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_LINT_TEMPLATE).toContain("pages/lint-report.md")
|
||||
})
|
||||
|
||||
test("should not modify any other page", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_LINT_TEMPLATE).toContain("read-only")
|
||||
})
|
||||
|
||||
test("should not contain emojis", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u
|
||||
expect(emojiRegex.test(WIKI_LINT_TEMPLATE)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("WIKI_UPDATE_TEMPLATE", () => {
|
||||
test("should show diffs of every modified page before writing", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_UPDATE_TEMPLATE).toContain("diff")
|
||||
})
|
||||
|
||||
test("should require citing the new source for every changed claim", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_UPDATE_TEMPLATE).toContain("cite")
|
||||
expect(WIKI_UPDATE_TEMPLATE).toContain("source")
|
||||
})
|
||||
|
||||
test("should sweep stale claims that no longer match the source", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_UPDATE_TEMPLATE).toContain("stale")
|
||||
})
|
||||
|
||||
test("should append the update to log.md", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_UPDATE_TEMPLATE).toContain("log.md")
|
||||
})
|
||||
|
||||
test("should bump the updated timestamp in front-matter", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
expect(WIKI_UPDATE_TEMPLATE).toContain("updated")
|
||||
expect(WIKI_UPDATE_TEMPLATE).toContain("front-matter")
|
||||
})
|
||||
|
||||
test("should not contain emojis", () => {
|
||||
//#given - the template string
|
||||
|
||||
//#when / #then
|
||||
const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u
|
||||
expect(emojiRegex.test(WIKI_UPDATE_TEMPLATE)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -8,6 +8,11 @@ import { REFACTOR_TEMPLATE } from "./templates/refactor"
|
||||
import { START_WORK_TEMPLATE } from "./templates/start-work"
|
||||
import { HANDOFF_TEMPLATE } from "./templates/handoff"
|
||||
import { REMOVE_AI_SLOPS_TEMPLATE } from "./templates/remove-ai-slops"
|
||||
import { WIKI_INIT_TEMPLATE } from "./templates/wiki-init"
|
||||
import { WIKI_INGEST_TEMPLATE } from "./templates/wiki-ingest"
|
||||
import { WIKI_QUERY_TEMPLATE } from "./templates/wiki-query"
|
||||
import { WIKI_LINT_TEMPLATE } from "./templates/wiki-lint"
|
||||
import { WIKI_UPDATE_TEMPLATE } from "./templates/wiki-update"
|
||||
|
||||
export interface LoadBuiltinCommandsOptions {
|
||||
useRegisteredAgents?: boolean
|
||||
@@ -121,6 +126,51 @@ $ARGUMENTS
|
||||
</user-request>`,
|
||||
argumentHint: "[goal]",
|
||||
},
|
||||
"wiki-init": {
|
||||
description: "(builtin) Bootstrap a new LLM-maintained wiki for knowledge accumulation",
|
||||
template: `<command-instruction>
|
||||
${WIKI_INIT_TEMPLATE}
|
||||
</command-instruction>`,
|
||||
},
|
||||
"wiki-ingest": {
|
||||
description: "(builtin) Add a source (paper, URL, file, transcript) to the wiki",
|
||||
template: `<command-instruction>
|
||||
${WIKI_INGEST_TEMPLATE}
|
||||
</command-instruction>
|
||||
|
||||
<user-source>
|
||||
$ARGUMENTS
|
||||
</user-source>`,
|
||||
argumentHint: "<file-path|URL|paste-text>",
|
||||
},
|
||||
"wiki-query": {
|
||||
description: "(builtin) Ask a question against the wiki knowledge base",
|
||||
template: `<command-instruction>
|
||||
${WIKI_QUERY_TEMPLATE}
|
||||
</command-instruction>
|
||||
|
||||
<user-question>
|
||||
$ARGUMENTS
|
||||
</user-question>`,
|
||||
argumentHint: "<question>",
|
||||
},
|
||||
"wiki-lint": {
|
||||
description: "(builtin) Health audit: find contradictions, broken links, orphans, and coverage gaps",
|
||||
template: `<command-instruction>
|
||||
${WIKI_LINT_TEMPLATE}
|
||||
</command-instruction>`,
|
||||
},
|
||||
"wiki-update": {
|
||||
description: "(builtin) Revise existing wiki pages when knowledge changes",
|
||||
template: `<command-instruction>
|
||||
${WIKI_UPDATE_TEMPLATE}
|
||||
</command-instruction>
|
||||
|
||||
<update-details>
|
||||
$ARGUMENTS
|
||||
</update-details>`,
|
||||
argumentHint: "<what-changed>",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
export const WIKI_INGEST_TEMPLATE = `# /wiki-ingest -- Add Source to Wiki
|
||||
|
||||
Add a source (paper, URL, file, transcript) to the wiki at \`.sisyphus/wiki/\`.
|
||||
|
||||
**CRITICAL: Never write from memory. Write only what the source supports.**
|
||||
|
||||
## Pipeline
|
||||
|
||||
### Step 1: Verify wiki exists
|
||||
Check \`.sisyphus/wiki/index.md\`. If missing, tell user to run \`/wiki-init\` first.
|
||||
|
||||
### Step 2: Read SCHEMA.md
|
||||
Read \`.sisyphus/wiki/SCHEMA.md\` for naming conventions.
|
||||
|
||||
### Step 3: Read the source
|
||||
- File path: use Read tool
|
||||
- URL: use WebFetch or Read
|
||||
- Transcript: use provided text
|
||||
|
||||
### Step 4: Extract Takeaways
|
||||
Identify 5-10 most important facts, concepts, or claims. Be specific, no filler.
|
||||
|
||||
### Step 5: Confirm with user
|
||||
Show extracted takeaways and ask:
|
||||
- Which to emphasize?
|
||||
- Any specific topics for pages?
|
||||
- One page or multiple?
|
||||
|
||||
Wait for confirmation before writing.
|
||||
|
||||
### Step 6: Create wiki page(s)
|
||||
Create in \`.sisyphus/wiki/pages/{slug}.md\`:
|
||||
\`\`\`markdown
|
||||
# {Title}
|
||||
|
||||
> Sources: {source path or URL}
|
||||
> Created: {today}
|
||||
> Updated: {today}
|
||||
|
||||
## Summary
|
||||
{2-3 sentence summary}
|
||||
|
||||
## Key Points
|
||||
- {takeaway 1}
|
||||
- {takeaway 2}
|
||||
|
||||
## Details
|
||||
{full content}
|
||||
|
||||
## See Also
|
||||
- [[related-page]]
|
||||
\`\`\`
|
||||
|
||||
### Step 7: Update index.md
|
||||
Append: \`- [[slug]] -- one-line summary\`. Keep alphabetical.
|
||||
|
||||
### Step 8: Backlink audit
|
||||
Read all existing pages. For each, check if new content is relevant. Add bidirectional \`[[new-slug]]\` links to "See Also" sections.
|
||||
|
||||
### Step 9: Update overview.md
|
||||
Re-read and update the synthesis to include new knowledge. Keep concise.
|
||||
|
||||
### Step 10: Append to log.md
|
||||
Add: \`| {today} | ingest | Added [[slug]] from {source} |\`
|
||||
|
||||
### Step 11: Confirm
|
||||
Show: pages created, backlinks added, overview updates.`
|
||||
@@ -0,0 +1,54 @@
|
||||
export const WIKI_INIT_TEMPLATE = `# /wiki-init -- Bootstrap LLM Wiki
|
||||
|
||||
Bootstrap a new structured wiki based on Karpathy's LLM Wiki pattern at \`.sisyphus/wiki/\`.
|
||||
|
||||
**Important:** If \`.sisyphus/wiki/\` already exists, warn the user and ask for confirmation before overwriting.
|
||||
|
||||
## Task
|
||||
|
||||
Create the wiki directory structure:
|
||||
|
||||
- .sisyphus/wiki/SCHEMA.md
|
||||
- .sisyphus/wiki/index.md
|
||||
- .sisyphus/wiki/log.md
|
||||
- .sisyphus/wiki/overview.md
|
||||
- .sisyphus/wiki/pages/.gitkeep
|
||||
|
||||
### SCHEMA.md
|
||||
Document conventions:
|
||||
- Wiki root path: \`.sisyphus/wiki/\`
|
||||
- Page naming: lowercase slugs with hyphens (e.g., \`api-authentication.md\`)
|
||||
- Link format: \`[[page-slug]]\` for internal wiki links
|
||||
- Source citation: \`[source: filename or URL]\`
|
||||
- front-matter: \`# Title\`, \`> Sources: ...\`, \`> Created: date\`, \`> Updated: date\`, \`> Backlinks: ...\`
|
||||
- Index format: one line per page -- \`- [[slug]] -- one-line summary\`
|
||||
- All sources must be cited. No claims from memory.
|
||||
- The backlinks section lists all pages linking to this page.
|
||||
|
||||
### index.md
|
||||
\`\`\`markdown
|
||||
# Wiki Index
|
||||
|
||||
*No pages yet. Use /wiki-ingest to add sources.*
|
||||
\`\`\`
|
||||
|
||||
### log.md
|
||||
\`\`\`markdown
|
||||
# Wiki Log
|
||||
|
||||
| Date | Operation | Details |
|
||||
|------|-----------|---------|
|
||||
| {today} | init | Wiki bootstrapped |
|
||||
\`\`\`
|
||||
|
||||
### overview.md
|
||||
\`\`\`markdown
|
||||
# Wiki Overview
|
||||
|
||||
*This overview will be automatically updated as pages are added.*
|
||||
\`\`\`
|
||||
|
||||
### pages/.gitkeep
|
||||
Create empty file to ensure directory exists.
|
||||
|
||||
After creating all files, confirm what was created and suggest: "Use /wiki-ingest to add your first source."`
|
||||
@@ -0,0 +1,48 @@
|
||||
export const WIKI_LINT_TEMPLATE = `# /wiki-lint -- Wiki Health Audit
|
||||
|
||||
Comprehensive read-only health audit of the wiki at \`.sisyphus/wiki/\`.
|
||||
|
||||
This audit is read-only -- it reports issues but does not modify any page except writing the report.
|
||||
|
||||
## Pipeline
|
||||
|
||||
### Step 1: Verify wiki exists
|
||||
Check \`.sisyphus/wiki/index.md\`. If missing, stop.
|
||||
|
||||
### Step 2: Read everything
|
||||
Read: SCHEMA.md, index.md, overview.md, and ALL files in pages/.
|
||||
|
||||
### Step 3: Check for issues
|
||||
|
||||
**Broken Links (ERROR)**
|
||||
Scan all pages for \`[[link]]\` references. Check for any broken link where the target does not exist in pages/.
|
||||
|
||||
**Orphan Pages (WARNING)**
|
||||
Pages in pages/ not referenced from index.md or any other page. Flag every orphan page found.
|
||||
|
||||
**Index Drift (WARNING)**
|
||||
Pages in pages/ not in index.md, or index entries pointing to missing pages.
|
||||
|
||||
**Contradictions (ERROR)**
|
||||
Compare claims across pages. Flag any contradiction where two pages state conflicting facts.
|
||||
|
||||
**Stale Sources (INFO)**
|
||||
Pages with no "Updated" date or updated more than 30 days ago.
|
||||
|
||||
**Coverage Gaps (INFO)**
|
||||
Topics in overview.md with no dedicated page. Report each coverage gap found.
|
||||
|
||||
**Link Density (INFO)**
|
||||
Pages with zero outgoing [[links]].
|
||||
|
||||
### Step 4: Write report
|
||||
Create \`.sisyphus/wiki/pages/lint-report.md\` with severity tiers.
|
||||
|
||||
### Step 5: Offer fixes
|
||||
For each ERROR/WARNING, offer to fix:
|
||||
- Broken link targets: remove or create missing page
|
||||
- Orphan pages: add to index
|
||||
- Contradictions: show both, ask which is correct
|
||||
|
||||
### Step 6: Log
|
||||
Append to log.md: \`| {today} | lint | {errors} errors, {warnings} warnings |\``
|
||||
@@ -0,0 +1,33 @@
|
||||
export const WIKI_QUERY_TEMPLATE = `# /wiki-query -- Query the Wiki
|
||||
|
||||
Answer a question using ONLY the structured wiki at \`.sisyphus/wiki/\`.
|
||||
|
||||
## CRITICAL RULE
|
||||
**You must never answer from your own knowledge or memory.** Only cite information found in wiki pages. If the wiki doesn't have the answer, say "not in the wiki" explicitly.
|
||||
|
||||
## Pipeline
|
||||
|
||||
### Step 1: Verify wiki exists
|
||||
Check \`.sisyphus/wiki/index.md\`. If missing, tell user to run \`/wiki-init\`.
|
||||
|
||||
### Step 2: Read the index
|
||||
Read \`.sisyphus/wiki/index.md\` to see all available pages.
|
||||
|
||||
### Step 3: Identify relevant pages
|
||||
Based on the question, determine which pages are relevant. Read those pages.
|
||||
|
||||
### Step 4: Follow links
|
||||
If pages reference other pages via \`[[links]]\`, follow them if relevant.
|
||||
|
||||
### Step 5: Synthesize answer
|
||||
Compose answer using ONLY wiki content. Cite every claim by source page:
|
||||
\`According to [[page-slug]], {fact}.\`
|
||||
|
||||
### Step 6: Assess gaps
|
||||
If partially answerable, clearly state what the wiki covers vs what is "not in the wiki".
|
||||
|
||||
### Step 7: Offer to save
|
||||
If the answer combines multiple sources into new insight, offer:
|
||||
"This answer combines information from multiple pages. Save as a new page [[suggested-slug]]?"
|
||||
|
||||
If yes: create page with citations, update index, run backlink audit, log to log.md.`
|
||||
@@ -0,0 +1,50 @@
|
||||
export const WIKI_UPDATE_TEMPLATE = `# /wiki-update -- Revise Wiki Pages
|
||||
|
||||
Update existing wiki pages at \`.sisyphus/wiki/\` with new information.
|
||||
|
||||
## Pipeline
|
||||
|
||||
### Step 1: Verify wiki exists
|
||||
Check \`.sisyphus/wiki/index.md\`. If missing, stop.
|
||||
|
||||
### Step 2: Read SCHEMA.md
|
||||
Read conventions from \`.sisyphus/wiki/SCHEMA.md\`.
|
||||
|
||||
### Step 3: Identify affected pages
|
||||
Based on the update, read index and find all pages containing old/stale information.
|
||||
|
||||
### Step 4: Read affected pages
|
||||
Read each potentially affected page in full.
|
||||
|
||||
### Step 5: Show diffs BEFORE writing
|
||||
For EACH page needing changes, show the diff:
|
||||
\`\`\`
|
||||
## Page: [[slug]]
|
||||
### Old content:
|
||||
> {exact text being replaced}
|
||||
### New content:
|
||||
> {proposed replacement}
|
||||
### Reason:
|
||||
Cite the new source for this change.
|
||||
\`\`\`
|
||||
|
||||
**Wait for user confirmation before making any edits.**
|
||||
|
||||
### Step 6: Apply changes
|
||||
After confirmation:
|
||||
- Update content
|
||||
- Bump "updated" date in front-matter
|
||||
- Add new source to "Sources:" if applicable
|
||||
- Verify [[links]] still valid
|
||||
|
||||
### Step 7: Sweep stale claims
|
||||
After updating direct pages, scan ALL other pages for the same stale claim. Show user and offer to fix.
|
||||
|
||||
### Step 8: Update overview.md
|
||||
If the change affects high-level synthesis, update overview.md.
|
||||
|
||||
### Step 9: Log
|
||||
Append to log.md: \`| {today} | update | Updated [[page-1]], [[page-2]] -- {reason} |\`
|
||||
|
||||
### Step 10: Confirm
|
||||
Show: pages updated, stale claims swept, sources cited.`
|
||||
@@ -1,6 +1,20 @@
|
||||
import type { CommandDefinition } from "../claude-code-command-loader"
|
||||
|
||||
export type BuiltinCommandName = "init-deep" | "ralph-loop" | "cancel-ralph" | "ulw-loop" | "refactor" | "start-work" | "stop-continuation" | "handoff" | "remove-ai-slops"
|
||||
export type BuiltinCommandName =
|
||||
| "init-deep"
|
||||
| "ralph-loop"
|
||||
| "cancel-ralph"
|
||||
| "ulw-loop"
|
||||
| "refactor"
|
||||
| "start-work"
|
||||
| "stop-continuation"
|
||||
| "handoff"
|
||||
| "remove-ai-slops"
|
||||
| "wiki-init"
|
||||
| "wiki-ingest"
|
||||
| "wiki-query"
|
||||
| "wiki-lint"
|
||||
| "wiki-update"
|
||||
|
||||
export interface BuiltinCommandConfig {
|
||||
disabled_commands?: BuiltinCommandName[]
|
||||
|
||||
Reference in New Issue
Block a user