Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RQhTgskDx8LLpD47rzLRS
4.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this repo is
A single-file catalog: extensions.json is the manifest LNbits hosts read
via LNBITS_EXTENSIONS_MANIFESTS. No server code, no build, no tests, no
tags. Every commit on main is live for every host that pulls the raw URL
(…/aiolabs/lnbits-extensions/raw/branch/main/extensions.json), including
bohm's native lnbits and the regtest compose stack. Hosts pick up changes
on lnbits restart, then upgrade via the admin UI. Audit trail is git log;
rollback is git revert.
This is an infra repo: commit straight to main, no PR. The release
procedure that leads up to a catalog commit (merge PRs in the extension
repo, chore(release) bump, test on dev lnbits, tag, hash) lives in
~/dev/CLAUDE.md under "Extension release procedure". This file only
covers the catalog side.
Manifest shape
{ "featured": [<id>, …], "extensions": [<entry>, …] }
Required entry fields: id, repo, name, version, short_description,
archive, hash (sha256 of the archive zip). Optional: icon,
min_lnbits_version, max_lnbits_version, details_link. Many entries
omit min_lnbits_version entirely; copy the previous entry for the same
id and change only version, archive, hash.
Entries are grouped by id in the file. Insert a new version directly after
the last existing entry for that id, not at the end of the array.
Rules that bite
- Add, never overwrite. A new version is a new object alongside the old
ones; installs on the previous version must still resolve it. The one
historical exception (
lnurlp: replace v1.3.0-aio.1 with v1.3.0-aio.2) was a same-day fix of a broken tag. - Keep 4-space indent and
ensure_ascii=False. A 2-space re-serialise once turned a one-entry bump into a whole-file diff and needed a follow-upchore: restore 4-space JSON formattingcommit. Hand-edit the block, or round-trip with the snippet below (verified byte-identical). - Aio forks point at
git.atitlan.io/aiolabs/<ext>, never GitHub. The threegithub.com/lnbits/lnurlpentries (1.1.3, 1.2.0, 1.3.0) predate the fork and stay only for installs that still run them. Don't add new upstream entries for any extension that has an aio fork; production only sees this manifest, so an upstream URL here bypasses our vetting. - Aio semver must outrank the upstream tag (
v1.3.0-aio.2>v1.3.0). Dev instances also see LNbits's built-in catalog; if upstream wins the semver comparison, clicking Upgrade overwrites the git checkout under~/dev/shared/extensions/. hashis the integrity gate. LNbits refuses to install when the downloaded archive's sha256 differs. Always recompute from the tag's archive URL; never copy a hash from a previous entry.
Commands
Compute the hash for a tagged release (Forgejo archive URL form):
curl -sL https://git.atitlan.io/aiolabs/<ext>/archive/v<version>.zip | sha256sum
Validate the manifest before committing (parse, required fields, duplicate
id+version, and that the archive URL's tag matches version):
python3 - <<'EOF'
import json, sys
d = json.load(open("extensions.json"))
req = {"id","repo","name","version","short_description","archive","hash"}
seen = set(); bad = 0
for e in d["extensions"]:
key = (e.get("id"), e.get("version"))
for m in (req - e.keys(), ["dup"] if key in seen else [], ["archive!=version"] if f"v{e.get('version')}.zip" not in e.get("archive","") else []):
if m: print(key, m); bad += 1
seen.add(key)
sys.exit(bad)
EOF
Re-serialise without formatting drift (only if editing programmatically):
python3 -c "
import json
d = json.load(open('extensions.json'))
open('extensions.json','w').write(json.dumps(d, indent=4, ensure_ascii=False) + '\n')"
Verify a committed entry matches the live archive:
git diff -U0 HEAD~1 | grep -oE '"(archive|hash)": "[^"]+"'
Commit message convention
One entry per commit, subject <ext>: add v<version> (<one-line what changed>),
e.g. events: add v1.6.1-aio.15 (promo codes enforced). The parenthetical
is the only human-readable changelog the catalog has, so name the user-visible
change, not "bump". Formatting-only fixes use chore:.