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:
parent
35ef01fd70
commit
0a5713c704
5 changed files with 242 additions and 0 deletions
34
README.md
34
README.md
|
|
@ -114,6 +114,40 @@ in follow-up passes.
|
||||||
The `dev` CLI is the single entry point. See the top of this README
|
The `dev` CLI is the single entry point. See the top of this README
|
||||||
for the verb set.
|
for the verb set.
|
||||||
|
|
||||||
|
### Claude orientation seeding (optional)
|
||||||
|
|
||||||
|
If you use [Claude Code](https://docs.anthropic.com/en/docs/claude-code),
|
||||||
|
opt in to having curated CLAUDE.md files seeded into your workspace.
|
||||||
|
The files live under `files/` in this repo and are symlinked into
|
||||||
|
`~/dev/` via home-manager's `mkOutOfStoreSymlink` — edits in your
|
||||||
|
checkout take effect on the next Claude session, no rebuild.
|
||||||
|
|
||||||
|
Wire it in `settings.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
devEnv = {
|
||||||
|
enable = true;
|
||||||
|
scaffoldPath = "/home/<you>/dev/lnbits-sensei"; # absolute path to your checkout
|
||||||
|
claude = {
|
||||||
|
enable = true; # ~/dev/lnbits/CLAUDE.md
|
||||||
|
workspaceOrientation = false; # also ~/dev/CLAUDE.md (opt-in;
|
||||||
|
# clobbers any existing one)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- `claude.enable` seeds `~/dev/lnbits/CLAUDE.md` from
|
||||||
|
`files/lnbits-CLAUDE.md` — project-level orientation that loads for
|
||||||
|
any Claude session in the lnbits worktree subtree (settings
|
||||||
|
precedence, Quasar UMD self-closing-tag rule, auth-decorator
|
||||||
|
distinctions, …).
|
||||||
|
- `claude.workspaceOrientation` *additionally* seeds `~/dev/CLAUDE.md`
|
||||||
|
from `files/dev-CLAUDE.md` — generic workspace orientation. Off by
|
||||||
|
default because most people already maintain their own.
|
||||||
|
|
||||||
|
If you don't use Claude Code, leave both off — the same content is in
|
||||||
|
`docs/` for human reading.
|
||||||
|
|
||||||
### Workspace layout (the `~/dev/` tree)
|
### Workspace layout (the `~/dev/` tree)
|
||||||
|
|
||||||
The dev-env module's job is to put every project, every worktree, and
|
The dev-env module's job is to put every project, every worktree, and
|
||||||
|
|
|
||||||
61
files/dev-CLAUDE.md
Normal file
61
files/dev-CLAUDE.md
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# `~/dev` — lnbits dev workspace
|
||||||
|
|
||||||
|
You're working in a dev workspace bootstrapped by **lnbits-sensei**.
|
||||||
|
This file is workspace-level orientation; per-project CLAUDE.md files
|
||||||
|
(e.g. `~/dev/lnbits/CLAUDE.md`) layer project-specific gotchas on top.
|
||||||
|
|
||||||
|
> This file is a symlink into your lnbits-sensei checkout's
|
||||||
|
> `files/dev-CLAUDE.md` (via home-manager's `mkOutOfStoreSymlink`).
|
||||||
|
> Edits should happen in the checkout and be committed there.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
~/dev/
|
||||||
|
├── repos/ # bare git repos, one per project
|
||||||
|
├── <project>/<worktree>/ # worktrees per branch
|
||||||
|
├── upstream-prs/<topic>/ # PR branches against upstreams
|
||||||
|
├── shared/, scratch/ # workspace utilities
|
||||||
|
└── refs/ # curated reference repos (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
Rationale: bare-repos + per-project-worktree directories means one git
|
||||||
|
object database per project (no clone-per-branch churn) and an explicit
|
||||||
|
PR contract in `upstream-prs/`. See the lnbits-sensei README's
|
||||||
|
"Workspace layout" section for the full reasoning.
|
||||||
|
|
||||||
|
## Quick commands
|
||||||
|
|
||||||
|
- `dev up [--fakewallet|--regtest]` — start the lnbits dev server.
|
||||||
|
Default `--fakewallet` is instant, no docker, good for
|
||||||
|
extension/UI/API work.
|
||||||
|
- `dev down` / `dev logs` / `dev shell` — control / inspect.
|
||||||
|
- *(planned)* `prb <repo> <branch>` — create a PR worktree branched
|
||||||
|
from `upstream/main` under `~/dev/upstream-prs/`.
|
||||||
|
- *(planned)* `lb <worktree>` — cd shortcut into `~/dev/lnbits/<worktree>`.
|
||||||
|
|
||||||
|
## Reference docs
|
||||||
|
|
||||||
|
Full reference lives in the lnbits-sensei checkout's `docs/`:
|
||||||
|
|
||||||
|
- `docs/remotes.md` — three remote-topology patterns (upstream-only /
|
||||||
|
github-fork / multi-remote-with-private).
|
||||||
|
- `docs/upstream-prs.md` — PR workflow with a primer for anyone new
|
||||||
|
to fork-based contribution.
|
||||||
|
- `docs/lnbits-upstream-flow.md` — how `lnbits/lnbits` itself moves
|
||||||
|
(the `dev` / `main` branch split, squash-merge convention).
|
||||||
|
- `docs/lnbits-workspace-notes.md` — practical gotchas: port choice,
|
||||||
|
`LNBITS_SRC` build-context traps, extension-folder-upgrade wiping
|
||||||
|
forks, Nostr key handling, CLINK scope, fork versioning, **settings
|
||||||
|
precedence (`.env` vs DB)**.
|
||||||
|
|
||||||
|
## Per-project orientations
|
||||||
|
|
||||||
|
Per-project CLAUDE.md files are placed at the worktree root:
|
||||||
|
|
||||||
|
- `~/dev/lnbits/CLAUDE.md` — LNbits dev gotchas (settings precedence,
|
||||||
|
frontend rules, auth decorators, …).
|
||||||
|
|
||||||
|
These are also symlinked from your lnbits-sensei checkout (under
|
||||||
|
`files/`); the seeding is driven by `lnbits-sensei.devEnv.claude.*`
|
||||||
|
options.
|
||||||
94
files/lnbits-CLAUDE.md
Normal file
94
files/lnbits-CLAUDE.md
Normal 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.
|
||||||
21
home.nix
21
home.nix
|
|
@ -35,4 +35,25 @@
|
||||||
# Future passes: shell prompt, editor, lnbits dev shell aliases,
|
# Future passes: shell prompt, editor, lnbits dev shell aliases,
|
||||||
# direnv integration, tmux launcher, etc. Keep this file thin and
|
# direnv integration, tmux launcher, etc. Keep this file thin and
|
||||||
# delegate behaviour to modules/.
|
# delegate behaviour to modules/.
|
||||||
|
|
||||||
|
# CLAUDE.md seeding — symlinks under ~/dev/ that point at files
|
||||||
|
# tracked in your lnbits-sensei checkout, so Claude sessions in the
|
||||||
|
# workspace pick up the curated orientation automatically. Gated on
|
||||||
|
# `lnbits-sensei.devEnv.claude.*` options in the NixOS config.
|
||||||
|
#
|
||||||
|
# `mkOutOfStoreSymlink` keeps the link pointed at your live checkout
|
||||||
|
# (not the Nix store), so editing the source file takes effect on
|
||||||
|
# the next Claude session without a rebuild.
|
||||||
|
home.file = lib.mkMerge [
|
||||||
|
(lib.optionalAttrs osConfig.lnbits-sensei.devEnv.claude.enable {
|
||||||
|
"dev/lnbits/CLAUDE.md".source =
|
||||||
|
config.lib.file.mkOutOfStoreSymlink
|
||||||
|
"${osConfig.lnbits-sensei.devEnv.scaffoldPath}/files/lnbits-CLAUDE.md";
|
||||||
|
})
|
||||||
|
(lib.optionalAttrs osConfig.lnbits-sensei.devEnv.claude.workspaceOrientation {
|
||||||
|
"dev/CLAUDE.md".source =
|
||||||
|
config.lib.file.mkOutOfStoreSymlink
|
||||||
|
"${osConfig.lnbits-sensei.devEnv.scaffoldPath}/files/dev-CLAUDE.md";
|
||||||
|
})
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,21 @@ in
|
||||||
options.lnbits-sensei.devEnv = {
|
options.lnbits-sensei.devEnv = {
|
||||||
enable = mkEnableOption "lnbits-sensei dev-env tooling";
|
enable = mkEnableOption "lnbits-sensei dev-env tooling";
|
||||||
|
|
||||||
|
scaffoldPath = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Absolute path to your lnbits-sensei checkout on this machine.
|
||||||
|
Used to source the seedable CLAUDE.md files (and, later, the
|
||||||
|
dev-env scripts) via `mkOutOfStoreSymlink` so edits in your
|
||||||
|
checkout take effect without a rebuild.
|
||||||
|
|
||||||
|
Required when any `claude.*` integration is enabled. Type is
|
||||||
|
`str` (not `path`) intentionally — `path` would copy the file
|
||||||
|
into the Nix store and break the out-of-store-symlink semantics.
|
||||||
|
'';
|
||||||
|
example = "/home/alice/dev/lnbits-sensei";
|
||||||
|
};
|
||||||
|
|
||||||
root = mkOption {
|
root = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "/home/${config.lnbits-sensei.user or "user"}/dev";
|
default = "/home/${config.lnbits-sensei.user or "user"}/dev";
|
||||||
|
|
@ -108,6 +123,23 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
claude = {
|
||||||
|
enable = mkEnableOption ''
|
||||||
|
Seed `~/dev/lnbits/CLAUDE.md` from
|
||||||
|
`''${scaffoldPath}/files/lnbits-CLAUDE.md` so Claude sessions
|
||||||
|
anywhere in the lnbits worktree subtree pick up project-specific
|
||||||
|
orientation (settings precedence, frontend rules, auth
|
||||||
|
decorators, …)
|
||||||
|
'';
|
||||||
|
|
||||||
|
workspaceOrientation = mkEnableOption ''
|
||||||
|
Also seed `~/dev/CLAUDE.md` from
|
||||||
|
`''${scaffoldPath}/files/dev-CLAUDE.md`. Skip if you already
|
||||||
|
maintain a workspace-level CLAUDE.md — this option clobbers
|
||||||
|
whatever is there
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
projects = mkOption {
|
projects = mkOption {
|
||||||
type = types.attrsOf projectType;
|
type = types.attrsOf projectType;
|
||||||
default = { };
|
default = { };
|
||||||
|
|
|
||||||
Reference in a new issue