Skip to content

Commit 26df54c

Browse files
cailmdaleyclaude
andcommitted
docs + CLAUDE.md: reflect plugin marketplace install model
Updates every doc surface that described the old `lc init` behavior (copy bundle subdirs into project `.claude/`) to match the new install flow (`claude plugin marketplace add` + `claude plugin install lightcone@lightcone-cli`). Touched: - docs/index.md, docs/architecture.md, docs/contributing/setup.md, docs/skills/index.md — show the new wheel layout (the repo-root `.claude-plugin/marketplace.json` plus `claude/lightcone/.claude-plugin/ plugin.json`); describe `get_marketplace_root()` (replaces `get_plugin_source_dir`); update the force-include block to include the marketplace manifest. - docs/cli/init.md — describe what `lc init` writes (just the permissions tier) and what it shells out for (the plugin install, idempotent, soft-fail when claude CLI is missing). - docs/cli/update.md, docs/skills/authoring.md — replace the old `shutil.copytree(get_plugin_source_dir(), …)` recipes with `claude plugin marketplace add` + `claude plugin install` flows. - docs/skills/ralph.md — switch the launcher path to `${CLAUDE_PLUGIN_ROOT}/skills/ralph/scripts/ralph`. - docs/user/getting-started.md, docs/user/troubleshooting.md — user-facing description of what lives in the project's `.claude/` (just `settings.json`) vs. what's user-scoped under `~/.claude/` (the plugin itself). - CLAUDE.md — refresh the Repository Structure block to show the new manifest files and the renamed `get_marketplace_root` constant. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> (cherry picked from commit 659278f)
1 parent 6486900 commit 26df54c

11 files changed

Lines changed: 188 additions & 105 deletions

File tree

CLAUDE.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ src/lightcone/ # namespace — NO __init__.py
5050
├── cli/ # Click surface
5151
│ ├── __init__.py # exposes main()
5252
│ ├── commands.py # init, run, status, verify, build
53-
│ ├── plugin.py # get_plugin_source_dir
53+
│ ├── plugin.py # get_marketplace_root + MARKETPLACE_NAME / PLUGIN_NAME constants
5454
│ └── claude/ # force-included Claude plugin bundle (in installed wheel only)
5555
├── engine/ # execution substrate — Snakemake-based
5656
│ ├── __init__.py
@@ -66,17 +66,23 @@ src/lightcone/ # namespace — NO __init__.py
6666
├── cli.py # `lc eval` subcommand group
6767
├── harness.py, sandbox.py, graders.py, build.py, report.py, models.py
6868
69-
claude/lightcone/ # Claude plugin source — force-included into the wheel
69+
.claude-plugin/ # marketplace manifest (force-included into the wheel)
70+
└── marketplace.json # declares the `lightcone` plugin sourced from ./claude/lightcone
71+
72+
claude/lightcone/ # Claude Code plugin source — force-included into the wheel
73+
├── .claude-plugin/plugin.json # plugin manifest (name=lightcone)
7074
├── skills/ # lc-new, lc-from-code, lc-from-paper,
7175
│ # lc-feedback, ralph;
7276
│ # paper-reproduction bundle: lc-from-paper (entry),
7377
│ # ralph (loop substrate), narrative,
7478
│ # paper-extraction, figure-comparison,
7579
│ # check-sentence-by-sentence
80+
│ # plus reference skills astra, lc-cli
7681
│ # (see skills/README.md for the full bundle map)
7782
├── agents/ # lc-extractor
78-
├── templates/ # Project CLAUDE.md template
79-
└── scripts/ # Session hooks (bash): venv activation, validate-on-save, session-start primer
83+
├── hooks/hooks.json # hook config (${CLAUDE_PLUGIN_ROOT}-rooted commands)
84+
├── scripts/ # hook handlers (bash): activate-venv, session-start primer, validate-on-save
85+
└── templates/ # Project CLAUDE.md template
8086
8187
tests/ # pytest — mirrors src/ structure
8288
pyproject.toml # hatchling + hatch-vcs, ASTRA + Snakemake as deps

docs/architecture.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,31 +236,44 @@ the qualified `<analysis_id>.<output_id>` form.
236236

237237
## Claude Code plugin
238238

239-
The plugin lives at `claude/lightcone/`. It is force-included into the
240-
installed wheel via `pyproject.toml` so `lc init` can find it whether
241-
you're running from source or from PyPI:
239+
The bundle at `claude/lightcone/` is a proper Claude Code plugin: manifest at
240+
`claude/lightcone/.claude-plugin/plugin.json`, hooks at
241+
`claude/lightcone/hooks/hooks.json` (with command paths rooted at
242+
`${CLAUDE_PLUGIN_ROOT}`), plus the skill / agent / script subdirectories.
243+
The repo root carries a `.claude-plugin/marketplace.json` declaring one
244+
plugin (`lightcone`) sourced from `./claude/lightcone`.
245+
246+
Both directories are force-included into the wheel so `lc init` finds the
247+
marketplace whether you're running from source or from PyPI:
242248

243249
```toml
244250
[tool.hatch.build.targets.wheel.force-include]
245251
"claude/lightcone" = "lightcone/cli/claude/lightcone"
252+
".claude-plugin/marketplace.json" = "lightcone/cli/.claude-plugin/marketplace.json"
246253
```
247254

248-
`lightcone.cli.plugin.get_plugin_source_dir()` does the lookup: bundled
249-
location first, dev location (relative to the repo root) second.
255+
`lightcone.cli.plugin.get_marketplace_root()` does the lookup — it returns
256+
the directory containing `.claude-plugin/marketplace.json` (the wheel-
257+
installed package root, or in dev the repo root). `lc init` shells out to
258+
`claude plugin marketplace add <root>` then `claude plugin install
259+
lightcone@lightcone-cli`. Both Claude CLI calls are idempotent.
250260

251261
### Permission tiers
252262

253263
`lc init --permissions {yolo,recommended,minimal}` writes a
254264
`.claude/settings.json` from the matching tier in
255265
`PERMISSION_TIERS`. `recommended` (the default) allows the agent to
256266
edit, write, and shell out, but blocks edits to dotfiles, scratch
257-
paths, and `git push`.
267+
paths, and `git push`. This is the only thing `lc init` writes into
268+
the project's `.claude/` — the plugin (skills, agents, hooks) lives
269+
user-scoped under `~/.claude/plugins/`, not duplicated per project.
258270

259271
### Hooks
260272

261273
The plugin registers Claude Code hooks for venv activation,
262-
auto-validation on save, and integrity-aware "did you forget `lc run`?"
263-
warnings.
274+
auto-validation on save, and surfacing materialization status at session
275+
start. Hook scripts live at `${CLAUDE_PLUGIN_ROOT}/scripts/` and the
276+
matchers/timeouts are declared in `claude/lightcone/hooks/hooks.json`.
264277

265278
---
266279

docs/cli/init.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,25 @@ CLAUDE.md # short note pointing future agents at the project
2222
lightcone.yaml # currently a stub: { target: local }
2323
results/ # placeholder; populated by `lc run`
2424
universes/ # placeholder; populate via `astra universe generate -n …`
25-
.claude/ # bundled Claude Code plugin
26-
skills/, agents/, hooks/, scripts/, templates/
27-
settings.json # the chosen permission tier
25+
.claude/
26+
settings.json # the chosen permission tier (project-scoped)
2827
.venv/ # Python venv (skipped with --no-venv)
2928
```
3029

30+
`lc init` then shells out to the `claude` CLI (if found on PATH) to install
31+
the `lightcone` plugin into the user's Claude Code config:
32+
33+
```
34+
claude plugin marketplace add <wheel-installed marketplace root>
35+
claude plugin install lightcone@lightcone-cli
36+
```
37+
38+
The plugin (skills, agents, hooks) lives user-scoped under `~/.claude/`, not
39+
per-project. Both commands are idempotent, so subsequent `lc init` calls are
40+
no-ops for the plugin. When `claude` isn't on PATH (Codex users, etc.), the
41+
plugin install is skipped and the manual commands above are printed — `lc init`
42+
still succeeds.
43+
3144
`lc init` refuses to run if `DIRECTORY/astra.yaml` already exists.
3245

3346
## Options

docs/cli/update.md

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,19 @@ tooling:
77
pip install --upgrade lightcone-cli # or: uv pip install -U lightcone-cli
88
```
99

10-
To pull updated plugin files into an existing project (`lc init` refuses to
11-
run if `astra.yaml` already exists, so we copy by hand):
10+
The lightcone plugin (skills, agents, hooks) lives user-scoped under
11+
`~/.claude/plugins/` — installed once by `lc init` via `claude plugin
12+
install lightcone@lightcone-cli`, not duplicated per project. To pull in
13+
plugin changes after a `pip install --upgrade`:
1214

1315
```bash
14-
python - <<'PY'
15-
import shutil
16-
from pathlib import Path
17-
from lightcone.cli.plugin import get_plugin_source_dir
18-
19-
src = get_plugin_source_dir()
20-
dst = Path(".claude")
21-
for sub in ("skills", "agents", "scripts", "guides", "templates"):
22-
s, d = src / sub, dst / sub
23-
if d.exists():
24-
shutil.rmtree(d)
25-
if s.exists():
26-
shutil.copytree(s, d)
27-
print("synced from", src)
28-
PY
16+
# Re-register the marketplace at its new wheel-installed location, then
17+
# re-install the plugin so Claude Code reads from the updated source.
18+
python -c "from lightcone.cli.plugin import get_marketplace_root; print(get_marketplace_root())" \
19+
| xargs claude plugin marketplace add
20+
claude plugin install lightcone@lightcone-cli
2921
```
3022

31-
A short `bin/lc-sync` helper or a `lc init --sync` flag would make this
32-
nicer — see the issue tracker if interested.
23+
Both commands are idempotent. `claude plugin marketplace remove
24+
lightcone-cli` then `add` again is the heaviest hammer, and rarely
25+
necessary.

docs/contributing/setup.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,26 +61,34 @@ just build # uv build
6161
just version # current version (from git tags via hatch-vcs)
6262
```
6363

64-
The plugin (`claude/lightcone/`) is force-included into the wheel:
64+
The plugin (`claude/lightcone/`) and the repo-root marketplace manifest
65+
(`.claude-plugin/marketplace.json`) are both force-included into the wheel:
6566

6667
```toml
6768
[tool.hatch.build.targets.wheel]
6869
packages = ["src/lightcone", "src/snakemake_executor_plugin_dask"]
6970

7071
[tool.hatch.build.targets.wheel.force-include]
7172
"claude/lightcone" = "lightcone/cli/claude/lightcone"
73+
".claude-plugin/marketplace.json" = "lightcone/cli/.claude-plugin/marketplace.json"
7274
```
7375

74-
That layout is what `lightcone.cli.plugin.get_plugin_source_dir()`
75-
walks — it tries the bundled location first, then the dev location
76-
relative to the repo root.
76+
That layout is what `lightcone.cli.plugin.get_marketplace_root()` walks —
77+
it returns the directory containing `.claude-plugin/marketplace.json` (the
78+
wheel-installed package root in a normal install, or the dev repo root
79+
when running from a checkout). `lc init` shells out to
80+
`claude plugin marketplace add <root>` and `claude plugin install
81+
lightcone@lightcone-cli` against that root.
7782

7883
## Repo layout
7984

8085
```text
8186
src/lightcone/ # main namespace (PEP 420; no __init__.py at the package root)
8287
src/snakemake_executor_plugin_dask/ # Snakemake → Dask executor plugin
88+
.claude-plugin/marketplace.json # marketplace manifest (force-included into the wheel)
8389
claude/lightcone/ # Claude Code plugin (force-included into the wheel)
90+
.claude-plugin/plugin.json # plugin manifest
91+
skills/ agents/ hooks/ scripts/ templates/
8492
tests/ # pytest tree, mirrors src/
8593
evals/ # eval task fixtures (tasks/snae/)
8694
docs/ # docs site

docs/index.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,18 @@ src/lightcone/ # PEP 420 namespace package — NO __init__.py
7171
7272
src/snakemake_executor_plugin_dask/ # Snakemake executor → dask.distributed
7373
74+
.claude-plugin/ # marketplace manifest (force-included into the wheel)
75+
└── marketplace.json # declares the `lightcone` plugin sourced from ./claude/lightcone
76+
7477
claude/lightcone/ # Claude Code plugin (force-included into the wheel)
78+
├── .claude-plugin/plugin.json # plugin manifest
7579
├── skills/ # lc-new, lc-from-code, lc-from-paper,
7680
│ # lc-feedback, ralph (+ bundle siblings);
7781
│ # reference skills: astra, lc-cli
7882
├── agents/ # lc-extractor (literature subagent)
79-
├── templates/ # project CLAUDE.md template
80-
└── scripts/ # session hooks (bash): venv, validate-on-save, session-start primer
83+
├── hooks/hooks.json # hook config (${CLAUDE_PLUGIN_ROOT}-rooted commands)
84+
├── scripts/ # hook scripts: venv, validate-on-save, session-start primer
85+
└── templates/ # project CLAUDE.md template
8186
8287
tests/ # pytest, mirrors src/
8388
pyproject.toml # hatchling + hatch-vcs; ASTRA + Snakemake as deps

docs/skills/authoring.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Skills are markdown files with YAML frontmatter. Each one lives in
77

88
## File layout
99

10-
```text
10+
```
1111
claude/lightcone/skills/
1212
└── my-skill/
1313
├── SKILL.md
@@ -40,9 +40,9 @@ argument-hint: "[OPTIONAL ARG] [--flag VALUE]"
4040

4141
- `##` for phase headings; lead with a "Stage banner" line that the
4242
skill prints to the chat.
43-
- `✓ / ○ / ✗` for status. Skip emoji elsewhere — they belong only
44-
inside the agent's own branded banner output.
45-
- Action prompts in blockquotes (`> "What are you trying to learn?"`).
43+
- `✓ / ○ / ✗` for status; never emojis except inside the agent's own
44+
branded output.
45+
- Action prompts in bold sentences (`> "What are you trying to learn?"`).
4646
- A `## Restrictions` (or `## Hard rules`) section at the end listing
4747
invariants Claude must not break.
4848

@@ -62,7 +62,7 @@ call when a specific section is load-bearing for that skill's work.
6262

6363
## Spawning subagents
6464

65-
Use `Agent` with `subagent_type` to delegate work. The
65+
Use `Task` with `subagent_type` to delegate work. The
6666
`lc-extractor` subagent in `agents/` is the canonical example:
6767

6868
```python
@@ -90,9 +90,21 @@ from lightcone.eval.cli import run_cmd
9090
# or invoke `lightcone.eval.harness.run_eval(...)` directly
9191
```
9292

93-
## Installing changes into an existing project
93+
## Picking up edits during development
94+
95+
The `lightcone` plugin lives user-scoped under `~/.claude/plugins/`, installed
96+
via `claude plugin install lightcone@lightcone-cli`. When you're working
97+
inside a `lightcone-cli` checkout and want Claude Code to pick up your
98+
edits, register the marketplace from the repo root (it takes precedence
99+
over any other registration of the same name):
100+
101+
```bash
102+
claude plugin marketplace add /path/to/lightcone-cli
103+
claude plugin install lightcone@lightcone-cli
104+
```
105+
106+
Restart Claude Code; the plugin now loads from your checkout's
107+
`claude/lightcone/` directly. Edits to `SKILL.md` files take effect on
108+
the next session start.
94109

95-
`lc init` copies the plugin once and refuses to run a second time on
96-
the same directory. See [Updating an existing project](../cli/update.md)
97-
for the Python heredoc that resyncs all the plugin subdirs (`skills`,
98-
`agents`, `scripts`, `guides`, `templates`) into an existing project.
110+
(See [`lc update`](../cli/update.md) for the upgrade-from-PyPI story.)

0 commit comments

Comments
 (0)