wiki-fold
wiki-fold reads the last 2^k entries from a wiki log file, extracts their content without invention, and writes a structural index page linking back to those entries. Use it to periodically consolidate flat log records into browsable fold summaries, with dry-run mode for preview and commit mode for persisted changes protected by wiki-locking in concurrent environments.
git clone --depth 1 https://github.com/AgriciDaniel/claude-obsidian /tmp/wiki-fold && cp -r /tmp/wiki-fold/skills/wiki-fold ~/.claude/skills/wiki-foldSKILL.md
# wiki-fold: Extractive Log Rollup
Implements a bounded subset of Mechanism 1 from [[DragonScale Memory]]: flat fold over raw `wiki/log.md` entries. Fold-of-folds (hierarchical level-stacking) is **out of scope for this skill**; see "Scope boundary" below.
A fold is **additive**: child log entries and their referenced pages are never modified, moved, or deleted. A fold is **extractive**: every outcome and theme in the output must be traceable to a specific child log entry. No invented facts, no synthesis beyond what the child entries support.
---
## Scope boundary (explicit)
This skill does **not** implement:
- Fold-of-folds / hierarchical level stacking (DragonScale spec calls for it; deferred to a future skill).
- Automatic triggering (folds are always human-invoked in Phase 1).
- Semantic-tiling dedup (Mechanism 3; separate skill).
It **does** implement:
- Flat fold over raw log.md entries at a chosen batch exponent `k`.
- Structural idempotency via a deterministic fold ID.
- Extractive summarization with count-checking.
When referring to level in frontmatter, use `batch_exponent: k` (not `level: k`), because this skill does not produce hierarchical levels.
---
## Modes
| Mode | Writes? | Invocation |
|---|---|---|
| **dry-run (default)** | **No Write tool calls.** Emit fold content via Bash `cat`/`heredoc` to stdout only. | `fold the log, dry-run k=3` |
| **commit** | Uses Write/Edit tools. Each Write fires the repo PostToolUse hook which auto-commits wiki changes. Accept this. Compose full content first, then sequence writes. | `fold the log, commit k=3` (only after a clean dry-run) |
**Why stdout-only in dry-run**: the repo's `hooks/hooks.json` PostToolUse hook fires on any `Write|Edit` and runs `git add wiki/ .raw/`. Writing to `/tmp` does not stage /tmp, but it still triggers the hook, which will commit *any pending wiki changes* under a generic message. Dry-run must leave zero residue. Bash stdout does not fire the hook.
---
## Concurrency (v1.7+)
The fold-page write in commit mode MUST be preceded by `wiki-lock acquire`:
```bash
FOLD_PATH="wiki/folds/${FOLD_ID}.md"
bash scripts/wiki-lock.sh acquire "$FOLD_PATH" || {
echo "FAIL: another writer holds $FOLD_PATH; aborting fold."; exit 75
}
# … write the fold via Write/Edit (which fires the PostToolUse hook) …
bash scripts/wiki-lock.sh release "$FOLD_PATH"
```
Fold pages are deterministically named (`fold-k{K}-from-{DATE}-to-{DATE}-n{COUNT}.md`), so two parallel folds with the same parameters target the same path. Without the lock, they could overwrite each other's outputs. The duplicate-detection check inside this skill (already documented below) handles the "fold already exists" case at the SKILL level; the lock handles the in-flight-write race at the OS level.
Dry-run mode does not acquire a lock (no writes happen).
See `skills/wiki-ingest/SKILL.md` §Concurrency for the full lock semantics.
---
## Deterministic fold ID
Every fold has an ID derived from its inputs:
```
fold-k{K}-from-{EARLIEST-DATE}-to-{LATEST-DATE}-n{COUNT}
```
Example: `fold-k3-from-2026-04-10-to-2026-04-23-n8`.
The filename in commit mode is `wiki/folds/{FOLD-ID}.md`. No date-of-creation in the filename. No timestamp in the title.
**Duplicate detection (required)**: before emitting any output, check if `wiki/folds/{FOLD-ID}.md` already exists. If so, report "Fold already exists at wiki/folds/{FOLD-ID}.md. Use --force to overwrite, or pick a different range." and stop. This is the no-op idempotency guarantee; byte-identical content is NOT guaranteed (LLM prose varies) but the filename and scope are.
---
## Parameters
- `k` (default 4): batch exponent. Batch size = `2^k`. Typical values: k=3 (8), k=4 (16), k=5 (32).
- `range` (optional): explicit entry range `entries 1-16`. Overrides k.
- `--force`: overwrite an existing fold with the same ID. Default no.
- `--commit`: write to wiki/. Without it, dry-run stdout-only.
If fewer than `2^k` log entries exist, report the shortfall and stop. Do not silently fold a partial batch.
---
## Procedure
### 1. Parse log entries
```
grep -n "^## \[" wiki/log.md | head -{2^k}
```
Record for each entry: line number, date, operation, title, and the following bullet lines until the next `## [` or end-of-section.
### 2. Extract child page identifiers
From each entry's bullet list, extract:
- `Location: wiki/path/to/page.md` (the primary page)
- `[[Wikilinks]]` inline
- `Pages created:` and `Pages updated:` lists
Build a structured children list:
```yaml
children:
- date: "2026-04-23"
op: "save"
title: "DragonScale Memory v0.2 — post-adversarial-review"
page: "[[DragonScale Memory]]"
- ...
```
One record per log entry. Do not dedupe by page: if two entries both point to `[[DragonScale Memory]]`, both records appear, distinguishable by date and title.
### 3. Read referenced pages (bounded)
Read only the pages that are not already captured fully in the log entry's bullets. Budget: 0-10 page reads. Hard ceiling: 15. If an entry's referenced page is missing, record `page_missing: true` and proceed.
### 4. Extractive summarization with count checks
Write the fold body per `references/fold-template.md`. **Rules**:
- **Extractive only.** Every outcome bullet and theme bullet must cite a specific child entry (e.g., `(from 2026-04-14 session)`) or a quoted line from that entry. Do not introduce events, counts, or interpretations not present in a child entry.
- **Log entry is the primary source.** If the log entry's bullets and the referenced meta-page disagree on a fact (e.g., a count), prefer the log-entry bullets and flag the mismatch as "source mismatch: log says X, meta says Y."
- **Count checks.** If you write "N concept pages" or "M repos updated," grep the source entries for the number and verify. Numeric mismatches are dry-run blockers.
- **No merging across entries without naming them.** A theme that spans multiple entries must name each contributing entry inline.
- **Unc>
Ingest sources into the Obsidian wiki vault. Reads a source, extracts entities and concepts, creates or updates wiki pages, cross-references, and logs the operation. Supports files, URLs, and batch mode. Triggers on: ingest, process this source, add this to the wiki, read and file this, batch ingest, ingest all of these, ingest this url.
>
>
Visual layer of the wiki. Add images, text cards, PDFs, and wiki pages to Obsidian canvas files with auto-positioning inside zones. Integrates with /banana for image capture. Triggers on: /canvas, canvas new, canvas add image, canvas add text, canvas add pdf, canvas add note, canvas zone, canvas list, canvas from banana, add to canvas, put this on the canvas, open canvas, create canvas.
>
>
Strip clutter from web pages before ingesting into the wiki. Removes ads, navigation, headers, footers, and boilerplate: leaving clean readable markdown that saves 40-60% tokens. Triggers on: defuddle, clean this page, strip this url, fetch and clean, clean web content before ingesting, strip ads, remove clutter, clean URL content, readable markdown from URL.