20 KiB
DragonScale Memory Guide
DragonScale Memory is an optional extension for claude-obsidian. It adds conservative helpers for log rollups, stable page addresses, duplicate-page linting, and frontier topic suggestion. Start with docs/install-guide.md. For the design spec and rationale, read wiki/concepts/DragonScale Memory.md.
This page stays close to shipped behavior in v1.6.0. It explains what setup creates, what each mechanism actually does, what it needs, and how to turn it off safely without uninstalling the repo.
What DragonScale Is
Scope and opt-in status
DragonScale is a memory-layer extension for the wiki. It covers rollups, deterministic page IDs, duplicate detection, and one opt-in topic-selection path for /autoresearch. It is not required for the base vault.
If you never run bash bin/setup-dragonscale.sh, the base install and the original skill behavior remain in place. The repo uses feature detection so DragonScale can stay optional instead of becoming a hard dependency.
The concept page is broader than this guide. This guide is operational. When the spec and implementation differ in detail, prefer the shipped scripts and skills for day-to-day behavior.
What ships in 1.6.0
Version 1.6.0 ships all four DragonScale mechanisms as opt-in features:
- Mechanism 1, Fold Operator:
skills/wiki-fold/ - Mechanism 2, Deterministic Page Addresses:
scripts/allocate-address.shpluswiki-ingestandwiki-lintintegration - Mechanism 3, Semantic Tiling Lint:
scripts/tiling-check.pypluswiki-lintintegration - Mechanism 4, Boundary-First Autoresearch:
scripts/boundary-score.pyplusskills/autoresearch/SKILL.mdTopic Selection logic
Use CHANGELOG.md for the release trail, docs/install-guide.md for the quick-start view, and wiki/concepts/DragonScale Memory.md for the full design context.
Before You Enable It
Base install requirements
DragonScale is an add-on, not a replacement for base setup. Do the normal vault install first by following docs/install-guide.md.
At minimum:
- clone the repo or install the plugin
- run
bash bin/setup-vault.sh - open the folder as an Obsidian vault
- use
/wikito scaffold or continue setup
The DragonScale setup script accepts one optional argument, the vault path:
bash bin/setup-dragonscale.sh
bash bin/setup-dragonscale.sh /path/to/vault
If you omit the path, it uses the repo root inferred from bin/.
Universal prerequisite: flock
flock is the universal prerequisite. Mechanism 2 uses it directly in scripts/allocate-address.sh to guard .vault-meta/.address.lock. Mechanism 3 uses flock from Python to guard .vault-meta/.tiling.lock around cache I/O.
Quick check:
command -v flock
If that prints nothing, install flock before relying on DragonScale. On Linux it is usually already present. On macOS it commonly comes from util-linux.
If flock is missing, setup can still create files, but the address allocator and tiling cache path are not reliable. Treat that as a blocker.
Mechanism 3 extra prerequisites: python3, ollama, nomic-embed-text
Mechanism 3 is the only mechanism with the full local embeddings stack. You need python3, ollama, and the nomic-embed-text model pulled into ollama.
Useful checks:
command -v python3
curl -sS http://127.0.0.1:11434/api/version
ollama pull nomic-embed-text
The setup script does not install any of those. It only checks and reports status. Mechanism 4 needs python3, but not ollama. Mechanisms 1 and 2 do not need either.
What happens when optional deps are missing
DragonScale is meant to fail closed or no-op cleanly.
If python3 is missing:
- Mechanism 3 cannot run
- Mechanism 4 cannot run
- Mechanisms 1 and 2 still work
If ollama is unreachable, scripts/tiling-check.py exits 10. If ollama is reachable but nomic-embed-text is not installed, it exits 11. wiki-lint is expected to treat those as skip conditions for semantic tiling, not as a reason to break the rest of the lint flow.
If the boundary helper fails, /autoresearch falls back to the normal ask-the-user topic path. It does not force a candidate list and it does not improvise a topic.
If DragonScale setup has never been run, wiki-ingest and wiki-lint keep their non-DragonScale behavior.
Setup
Run bin/setup-dragonscale.sh
Run:
bash bin/setup-dragonscale.sh
The script is idempotent. It is safe to re-run and it does not overwrite the runtime files it already created.
Before provisioning state, it verifies:
scripts/allocate-address.shscripts/tiling-check.pyskills/wiki-fold/SKILL.md
If any of those are missing, setup stops and tells you to reinstall the plugin.
What setup does:
- makes
scripts/allocate-address.shexecutable - makes
scripts/tiling-check.pyexecutable - creates
.vault-meta/if needed - creates address, tiling, and legacy-baseline state files if missing
- creates
.raw/.manifest.jsonif missing - runs sanity checks at the end
What setup does not do:
- install ollama
- pull
nomic-embed-text - backfill addresses onto old pages
- run a fold
- run semantic tiling
- rewrite your existing wiki pages
What files and state it creates
Setup provisions a small amount of runtime state.
In .vault-meta/ it creates:
address-counter.txttiling-thresholds.jsonlegacy-pages.txt
In .raw/ it creates:
.manifest.json
address-counter.txt starts at 1, so the next reserved page address in a brand-new vault will be c-000001.
tiling-thresholds.json is seeded with error: 0.90, review: 0.80, and calibrated: false. These are conservative seed bands, not calibrated truth for your vault.
legacy-pages.txt gets a rollout marker comment:
# rollout: YYYY-MM-DD
wiki-lint uses that baseline to separate legacy pages from post-rollout pages for address enforcement.
.raw/.manifest.json starts with empty sources and address_map objects. The ingest skill maintains that file. The source documents under .raw/ remain immutable.
How to verify setup
The setup script already performs sanity checks, but it is useful to verify a few things yourself.
Check the next address without reserving one:
./scripts/allocate-address.sh --peek
Check that runtime state exists:
ls -1 .vault-meta
Check tiling readiness without computing embeddings:
python3 ./scripts/tiling-check.py --peek
Check the boundary helper:
python3 ./scripts/boundary-score.py --top 5
If your vault is small or tightly integrated, the boundary helper may report no positive-score frontier pages. That is still a valid run.
Mechanism 1: Fold Operator
What it does
The fold operator is a log rollup. It reads the most recent 2^k entries from wiki/log.md and produces an extractive fold page under wiki/folds/.
The fold is additive. It does not delete, move, or rewrite the child entries. The fold is extractive. Every outcome and theme in the output must be traceable to a child log entry.
The current shipped skill is intentionally narrow. It supports a flat fold over raw log entries. Hierarchical fold-of-folds behavior remains outside the scope of the current skill even though the concept spec discusses stacked folds.
The fold ID is deterministic for a given range:
fold-k{K}-from-{EARLIEST-DATE}-to-{LATEST-DATE}-n{COUNT}
That gives structural idempotency. If the exact fold already exists, the skill should stop instead of writing a duplicate.
When to use it
Use a fold when the log has accumulated a coherent batch of work and you want a checkpoint page that is easier to scan than a raw run of entries.
Typical cases:
- after several ingests on one theme
- after a burst of research sessions
- before a long flat
wiki/log.mdgets harder to use
Do not treat folds as garbage collection. They summarize. They do not compact by deletion.
Example command:
fold the log, dry-run k=3
That asks for a dry-run over 2^3 = 8 entries.
Dry-run vs commit mode
Dry-run is the default and it is stdout-only. That matters because the repo has a PostToolUse hook for writes.
In dry-run mode:
- no file is written
- no auto-commit hook is triggered
- you get the proposed fold content in the terminal output
In commit mode:
- the fold page is written to
wiki/folds/ wiki/index.mdis updatedwiki/log.mdgets a new fold entry
The skill docs expect three separate write operations in commit mode, so three auto-commits from the hook are normal.
Example commit command:
fold the log, commit k=3
Run a dry-run first. Commit only if the fold content looks right.
To disable Mechanism 1 without uninstalling DragonScale, stop invoking wiki-fold. Existing fold pages can remain in the vault, or you can remove them manually if you no longer want them.
Mechanism 2: Deterministic Page Addresses
Address format and rollout policy
Mechanism 2 assigns stable frontmatter addresses. The shipped format is:
address: c-000042
c- means creation-order counter. The numeric part is zero-padded to six digits. This is not a content hash. The spec is explicit that the shipped address is deterministic and stable, but not content-addressable.
The rollout baseline is 2026-04-23. After DragonScale adoption, post-rollout non-meta pages are expected to have addresses. Legacy pages are exempt until you do a deliberate backfill.
The helper has three real modes:
./scripts/allocate-address.sh
./scripts/allocate-address.sh --peek
./scripts/allocate-address.sh --rebuild
The default mode reserves and prints the next address. --peek is read-only. --rebuild recomputes the counter from the highest observed c-NNNNNN.
Example command:
./scripts/allocate-address.sh --peek
How ingest and lint use it
wiki-ingest enables address assignment only when ./scripts/allocate-address.sh is executable and ./.vault-meta exists. If both conditions are true, new non-meta pages get address: in frontmatter. If not, ingest proceeds without addresses.
wiki-lint enables address validation only when ./scripts/allocate-address.sh is executable and ./.vault-meta/address-counter.txt exists. If those conditions are true, lint checks address format, uniqueness, counter consistency against --peek, missing addresses on post-rollout pages, and address_map consistency in .raw/.manifest.json.
The single-writer rule matters here. The allocator uses flock, but the ingest skill still says Phase 2 is single-writer only. Do not run parallel ingests from multiple sessions or sub-agents that assign addresses.
One hard rule from the skill docs is worth repeating. Never edit .vault-meta/address-counter.txt directly. Only mutate it through scripts/allocate-address.sh.
To disable Mechanism 2 without uninstalling:
- stop running ingests that depend on address assignment
- remove
.vault-meta/if you want feature detection to turn off - stop using
./scripts/allocate-address.sh
Existing address: fields can stay on pages. They become inert metadata if the feature is disabled.
Mechanism 3: Semantic Tiling Lint
What it checks
Mechanism 3 is an embedding-based duplicate-page detector. It scans markdown files under wiki/ and excludes:
wiki/folds/wiki/meta/- common meta filenames such as
index.md,log.md,hot.md,overview.md,dashboard.md,Wiki Map.md, andgetting-started.md - files with
type: meta - files with
type: fold - symlinks or paths that escape the vault root
It computes one embedding per included page, compares pairs by cosine similarity, and emits candidate overlap in bands.
Default bands:
>= 0.90as error0.80 - 0.90as review< 0.80as pass
The helper never auto-merges pages. It only reports candidates for review.
Example command:
python3 ./scripts/tiling-check.py --peek
That gives structured diagnostics without computing embeddings.
Local embeddings requirement
By default, the helper only trusts a local ollama endpoint at http://127.0.0.1:11434. Remote ollama endpoints require an explicit override flag because page bodies are sent as embedding input.
Remote override example:
python3 ./scripts/tiling-check.py --allow-remote-ollama --peek
The normal ready path is local:
python3is installed- ollama is reachable on localhost
nomic-embed-textis installed in ollama
Important exit codes:
0success10ollama unreachable11model missing
wiki-lint is written to treat those as skip conditions.
Calibration and no-op behavior
The shipped thresholds are conservative seeds, not calibrated truth. The skill docs call for a manual one-time calibration pass per vault. Until you do that, expect both false negatives and false positives.
The helper also has intentional no-op behavior. If ollama or the model is missing, it exits with the skip code. It does not fake results.
Useful commands:
python3 ./scripts/tiling-check.py --peek
python3 ./scripts/tiling-check.py --rebuild-cache
python3 ./scripts/tiling-check.py --report wiki/meta/tiling-report-YYYY-MM-DD.md
--report is real and path-confined to the vault. Use it when you want a saved report. Use --peek when you only want readiness and diagnostics.
To disable Mechanism 3 without uninstalling:
- stop running
python3 ./scripts/tiling-check.py - stop using the semantic-tiling path in
wiki-lint - do not provision ollama or the model if you do not need them
Note that .vault-meta/ is a shared gate for Mechanisms 2, 3, and 4. Do not remove it to disable Mechanism 3 alone, or you will also turn off address allocation and boundary-first autoresearch. The tiling cache lives under .vault-meta/ but is inert when the helper is not invoked.
Mechanism 4: Boundary-First Autoresearch
What it does
Mechanism 4 scores frontier pages in the wiki graph. The shipped formula is:
boundary_score(p) = (out_degree(p) - in_degree(p)) * recency_weight(p)
In practice, high-score pages point outward to many scoreable pages, receive relatively fewer inbound links, and were updated recently enough to still be frontier-like.
The helper reads wiki/**/*.md, builds a wikilink graph, and emits ranked results to stdout or JSON. It is intentionally stdout-only. Unlike the tiling helper, it has no --report PATH mode.
Example command:
python3 ./scripts/boundary-score.py --json --top 5
That is the exact command the autoresearch skill uses for candidate generation.
Agenda-control caveat
This caveat is explicit in both the spec and the skill docs.
This is agenda control, not pure memory.
Mechanism 4 does not just describe the vault. It influences what the agent is likely to research next. That crosses the memory and planning boundary.
The project keeps it opt-in and labels it honestly. If you want the strict memory-layer subset only, omit this path. Do not use /autoresearch without a topic, or do not set up and invoke the boundary scorer.
How /autoresearch behaves with and without it
With Mechanism 4 available, and only when /autoresearch is invoked without a topic, the skill:
- checks for
scripts/boundary-score.py - checks for
./.vault-meta - checks for
python3 - runs
./scripts/boundary-score.py --json --top 5 - presents the top frontier pages as candidate topics
- lets the user pick, override with free text, or decline
If the helper exits non-zero, returns invalid JSON, or returns an empty results array, the skill falls back.
Without Mechanism 4, or after fallback, /autoresearch simply asks:
What topic should I research?
The helper suggests. The user still decides.
To disable Mechanism 4 without uninstalling:
- stop running
python3 ./scripts/boundary-score.py - use
/autoresearch [topic]with an explicit topic - avoid the no-topic
/autoresearchpath if you do not want frontier suggestions
Note that .vault-meta/ is a shared gate for Mechanisms 2, 3, and 4. Do not remove it to disable Mechanism 4 alone. The scorer itself is read-only and uses no shared state; disabling it just means not invoking it.
Operational Policies
Single-writer rule
DragonScale assumes a single writer for the address-assignment path. The allocator is flock-guarded, which protects the counter from simple races. It does not turn the whole wiki into a safe multi-writer system.
The ingest skill is explicit here. Do not run parallel ingests from multiple Claude sessions or sub-agents that assign addresses.
The safe operating policy is:
- one active ingest writer at a time
- one address allocator path at a time
- no direct manual edits to counter state
Mechanism 1 is human-invoked and easy to serialize. Mechanism 3 uses a lock for cache I/O. Mechanism 4 is read-only.
Feature detection and graceful fallback
DragonScale is meant to be feature-detected, not assumed.
wiki-ingest only assigns addresses when the allocator is executable and .vault-meta/ exists.
wiki-lint only validates addresses when the allocator exists and .vault-meta/address-counter.txt exists.
wiki-lint only runs semantic tiling when the helper exists and python3 is available, then interprets readiness from --peek.
autoresearch only uses boundary-first selection when the helper exists, .vault-meta/ exists, and python3 is present.
When those conditions are not met, the repo falls back to earlier behavior. That is the intended operational posture.
Troubleshooting
Missing flock
If flock is missing, fix that first. Symptoms can include an unsafe address-allocation path or a tiling cache path that cannot lock correctly.
Check:
command -v flock
If it is absent, install the package that provides it for your system, then rerun:
bash bin/setup-dragonscale.sh
Do not work around this by editing .vault-meta/address-counter.txt directly.
Missing ollama or model
This only blocks Mechanism 3. It does not block the rest of DragonScale.
Check ollama reachability:
curl -sS http://127.0.0.1:11434/api/version
Check tiling readiness:
python3 ./scripts/tiling-check.py --peek
If the helper exits 10, ollama is not reachable. If it exits 11, pull the model:
ollama pull nomic-embed-text
Then rerun:
python3 ./scripts/tiling-check.py --peek
Remember that Mechanism 4 does not need ollama. If you only want boundary-first autoresearch, python3 is enough.
Safe rollback / disable path
You do not need to uninstall the repo to turn DragonScale off. Use the smallest rollback that fits what you want:
- Mechanism 1: stop invoking
wiki-fold. It uses no shared state. - Mechanism 2: stop using
./scripts/allocate-address.sh. Existingaddress:frontmatter fields remain as plain content. - Mechanism 3: stop running
python3 ./scripts/tiling-check.pyand stop invoking the semantic-tiling path inwiki-lint. Cache under.vault-meta/is inert when not used. - Mechanism 4: stop running
python3 ./scripts/boundary-score.pyand avoid the no-topic/autoresearchpath. The scorer is read-only; disabling is not invoking it.
.vault-meta/ is a shared gate for Mechanisms 2, 3, and 4. Removing it disables all three together, not just one.
If you want to disable DragonScale feature detection across the setup-based mechanisms at once, remove .vault-meta/:
rm -rf .vault-meta
Then stop invoking the DragonScale-specific helpers and skills. This leaves your normal wiki content intact. It does not remove fold pages, and it does not strip existing address: fields from frontmatter. Those remain as plain content unless you choose to clean them up manually.
If you later want DragonScale back, rerun:
bash bin/setup-dragonscale.sh