Storage and configuration
Releaseledger storage topology is owned by the canonical Ledgercore project
manifest. New projects use schema 3 and keep Releaseledger configuration at
.ledger/releaseledger/config.toml; authoritative data is a data mount and
derived indexes are a cache mount. Inspect the resolved topology with:
releaseledger --root PATH storage where
releaseledger --root PATH storage validate --strict
Change topology through the command boundary, with a real dry-run before a write:
releaseledger storage set data --storage external \
--storage-root ../ledger --scope project --dry-run
releaseledger storage set data --storage external \
--storage-root ../ledger --scope project
Authoritative data must not use cache storage. Local overrides can be removed
with storage clear-override data; its result reports the effective location.
Legacy projects are migrated through the named lifecycle:
releaseledger migrate status
releaseledger migrate plan storage-layout --output migration-plan.json
releaseledger migrate apply storage-layout --plan-file migration-plan.json \
--reason "Adopt the canonical Ledgercore storage layout"
releaseledger migrate recover --journal PATH --policy auto --dry-run
releaseledger migrate cleanup storage-layout --dry-run
releaseledger migrate cleanup storage-layout --yes \
--reason "Remove verified legacy artifacts"
Plans are deterministic and hash-protected. The v2 plan carries one shared migration ID, exact source/before/target fingerprints, and the rendered config target. Apply is copy-only; physical activation and recovery belong to the Ledgercore schema-3 journal. Cleanup never happens implicitly as part of apply and requires a committed journal plus Releaseledger receipt.
The examples below document the pre-migration layout retained for discovery; they are not the canonical configuration format.
Default layout
A normal project stores release state inside the workspace:
config_version = 1
releaseledger_dir = ".releaseledger"
ledger_ref = "main"
ledger_parent_ref = ""
ledger_next_entry_number = 1
ledger_branch_guard = "off"
[ledger]
code = "rl"
name = "releaseledger"
[release]
default_changelog = "CHANGELOG.md"
default_status = "planned"
allow_dirty_worktree = true
Storage tree:
.releaseledger/
ledgers/
main/
releases/
<version>/
release.md
entries/
entry-0001.md
events/
events.jsonl
indexes/
releases.json
entries.json
Release and entry Markdown records use schema version 2 and include validated record metadata:
schema_version: 2
object_type: release
versioning:
schema_version: 1
revision: 1
version: 1.2.0
status: released
released_at: 2026-06-14
released_at is the public changelog date. Mutation dates are not stored.
Indexes are derived and expose record_revision for inspection. Events are
append-only operation rows with affected record revisions; git history provides
chronology and exact before/after content.
External state directories
Projects that keep generated state in a sibling repository can opt in to an external path:
releaseledger_dir = "../ledger/release/releaseledger"
releaseledger_dir_policy = "external"
The CLI form is:
releaseledger init \
--releaseledger-dir ../ledger/release/releaseledger \
--external-dir
releaseledger config set releaseledger_dir \
../ledger/release/releaseledger \
--external-dir
Relative paths that escape the workspace are rejected unless the external policy is explicit.
Diagnostics
Inspect effective paths and layout health without mutating state:
releaseledger storage where
releaseledger --json storage where
releaseledger config show
releaseledger --json config show