feat(claude): seed curated CLAUDE.md files into ~/dev/ workspace

Adds the omnixy-pattern out-of-store-symlink wiring so consumers can
opt into Claude Code orientation without copying anything by hand.
Files live in lnbits-sensei (so they evolve via PR), symlinks point
back at the consumer's checkout (so edits take effect on the next
Claude session without a nixos-rebuild).

New files under files/:

- dev-CLAUDE.md — generic workspace orientation. Workspace layout,
  quick command set, pointers to docs/. Opt-in (clobbers an existing
  ~/dev/CLAUDE.md, so off by default).
- lnbits-CLAUDE.md — per-project orientation for the lnbits worktree
  subtree. Inline summary of the four most-stepped-on gotchas
  (settings precedence, Quasar UMD self-closing rule, auth-decorator
  distinctions, upstream PR target = `dev` not `main`) plus pointers
  to the docs/ for full reference.

New options under lnbits-sensei.devEnv:

- scaffoldPath — absolute path to the consumer's lnbits-sensei
  checkout. types.str (not types.path) intentionally: types.path
  would copy the file into the Nix store and defeat
  mkOutOfStoreSymlink. Required when any claude.* flag is on.
- claude.enable — seeds ~/dev/lnbits/CLAUDE.md.
- claude.workspaceOrientation — additionally seeds ~/dev/CLAUDE.md.

Wiring lives in home.nix (gated via `osConfig.lnbits-sensei.devEnv.*`)
rather than the dev-env NixOS module, since the file destinations are
under home-manager's purview and the home-manager scope is where
`mkOutOfStoreSymlink` is in scope.

`nix flake check` stays green — `optionalAttrs` is lazy, so
`scaffoldPath` isn't accessed when claude.{enable,workspaceOrientation}
are both false (their defaults).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-26 00:54:55 +02:00
commit 0a5713c704
5 changed files with 242 additions and 0 deletions

94
files/lnbits-CLAUDE.md Normal file
View file

@ -0,0 +1,94 @@
# `~/dev/lnbits` — LNbits dev orientation
Per-project CLAUDE.md for the LNbits worktree subtree. Workspace-level
orientation is at `~/dev/CLAUDE.md` (when wired). Full reference
material lives in your lnbits-sensei checkout under `docs/`.
> This file is a symlink to `files/lnbits-CLAUDE.md` in your
> lnbits-sensei checkout. Edits should happen there.
## Critical gotchas (read first)
### Settings: `.env` seeds the DB on first boot, then DB wins
After first boot, **editing `.env` and restarting changes nothing**
for editable fields. Only `ReadOnlySettings` (`host`, `port`,
`lnbits_path`, `lnbits_data_folder`, `lnbits_extensions_path`,
`lnbits_database_url`, `auth_secret_key`, `first_install_token`,
`lnbits_title`, `lnbits_admin_ui`, `lnbits_allowed_funding_sources`)
re-read env every boot.
Editable settings (site title, fees, watchdog, funding-source
credentials, the whole Admin UI form) change only via:
- `PUT /api/v1/settings` (Admin UI), or
- Clearing the relevant rows in the `system_settings` table.
Deploy-side: declarative env vars are a *seed* for editable fields,
not authoritative. Plan accordingly.
Full reference: `docs/lnbits-workspace-notes.md` → "Settings precedence".
### Frontend templates: NO self-closing tags
LNbits pages load Vue 3 + Quasar 2 as UMD globals. The browser's
HTML parser doesn't honor self-close on non-void elements — the
close tag gets implied at the wrong place and subsequent siblings
end up inside the prior component.
```html
<q-input v-model="foo" label="Foo"></q-input> <!-- ✓ correct -->
<q-input v-model="foo" label="Foo" /> <!-- ✗ silently broken -->
```
Applies to `lnbits/templates/*.html`, every extension's `templates/`,
every fork. Fine in `.vue` SFCs (the build step rewrites them) — if
you copy a snippet from a Vue SFC repo into an LNbits template,
**expand all self-closing tags before saving**.
### Auth decorators
Easy to confuse. Different scopes:
| Decorator | Auth scope |
|---|---|
| `require_invoice_key` | Wallet invoice key — read access |
| `require_admin_key` | Wallet admin key — write to **own wallet only** |
| `check_admin` | **LNbits instance admin** (super_user / admin users) |
| `check_super_user` | LNbits super user only |
`require_admin_key``check_admin`. Use `check_admin` for
cross-user / admin-only endpoints.
### Upstream PRs target `dev`, not `main`
PRs to `github.com/lnbits/lnbits` go to `dev`. `main` only moves on
release merges. Use lowercase conventional-commit titles
(`feat:`, `fix:`, `chore:`, `chore(deps):`, `docs:`, `ci:`).
Full reference: `docs/lnbits-upstream-flow.md`.
## Default dev workflow
```
dev up # FakeWallet, instant
dev up --regtest # multi-node regtest (slower boot, real channels)
```
Use **FakeWallet** for extension CRUD / UI / API work. Spin up
**regtest** only when actual channel/payment behavior is under test.
## Key paths
- `~/dev/lnbits/main/` — worktree on `main` (your fork's day-to-day)
- `~/dev/lnbits/dev/` — worktree on `dev` (integration / staging)
- `~/dev/upstream-prs/lnbits-<topic>/` — PR worktrees branched from
`upstream/main`
- `~/dev/repos/lnbits.git` — the bare repo all the above point at
## When in doubt
The canonical reference for any of the above lives in your
lnbits-sensei checkout's `docs/`. Trust the docs over this file when
they diverge — this CLAUDE.md is a quick-reference; the docs are the
source of truth.