Skip to content

De-bundle the Claude Code plugin: skills ship from the agent-skills marketplace (LCR-181)#161

Open
cailmdaley wants to merge 12 commits into
mainfrom
cailmdaley/lcr-181-marketplace-skills
Open

De-bundle the Claude Code plugin: skills ship from the agent-skills marketplace (LCR-181)#161
cailmdaley wants to merge 12 commits into
mainfrom
cailmdaley/lcr-181-marketplace-skills

Conversation

@cailmdaley

Copy link
Copy Markdown
Member

LCR-181: skills move to the agent-skills marketplace

This PR de-bundles the Claude Code plugin from the wheel. Skills, hooks, and the lc-extractor subagent now ship from the LightconeResearch/agent-skills marketplace. The CLI keeps only what a CLI can own: the commands, the scaffold, and the compatibility surface the plugin talks to.

Why

The wheel and the plugin change at different speeds and through different channels. Bundling them coupled a Python release to every skill edit. It also gave projects a plugin frozen at install time. The marketplace gives the plugin its own channel: Claude Code refreshes it automatically, in every project at once.

The upgrade model

De-bundling creates two independent channels. uv upgrades the CLI. The marketplace upgrades the plugin. The channels move in any order. Neither side may assume the other has moved. Three rules make this safe (docs/user/upgrading.md carries the full version):

Skew is detected, not prevented. The plugin's SessionStart hook calls lc compat. The command prints the CLI version, the minimum plugin version the CLI expects, and the plugin name as JSON. The plugin compares its version to the floor and warns with the exact heal command on skew. Skew degrades; it never blocks.

Old plugins must not brick sessions. Pre-marketplace plugins gate Bash|Write|Edit|Skill behind exec lc hook pretool. Removing the subcommand makes click exit 2 — the code Claude Code reads as "block this tool call". Upgrading the CLI ahead of the plugin would wedge every gated tool call, including the edit that fixes the hook. A hidden lc hook stub therefore accepts any arguments, exits 0, and prints a deprecation notice to stderr. It stays until the next breaking release (TODO(next-breaking) marks it).

Layout migrations are convergent lc init. The command is idempotent. In a fresh directory it scaffolds a project. In a directory with an existing astra.yaml it layers on only the missing integration bits — .lightcone/, results/, the marketplace registration (merged non-destructively into any existing .claude/settings.json), the MyST report template — and never touches astra.yaml or an existing CLAUDE.md. It reports what it added and what it skipped. This transition is the motivating example: one lc init per existing project.

Also in this PR

  • uv tool install lightcone-cli now exposes astra alongside lc (the wheel re-exports astra-tools' entry point), so astra validate works out of the box.
  • The plugin-hint and permission-tier mechanisms are removed; the harness owns skill discovery and the user owns the trust level.
  • DOGFOOD PINS (tip commit + marketplace ref:) point at the open agent-skills PR for testing; revert before merge.

The upgrade model was exercised against a live project on a cluster before any of it was designed — the lc hook brick, the missing adoption path, and the unreachable astra executable were all hit in the wild first.

cailmdaley and others added 12 commits July 19, 2026 22:35
…-181)

Stop shipping Claude Code skills, hooks, agents, and scripts inside the
lightcone-cli wheel. They now live in the LightconeResearch/agent-skills
marketplace and install as the `lightcone` plugin.

- Remove the `claude/lightcone/` tree and its hatch force-include + sdist
  entries.
- Remove `cli/plugin.py` (`get_plugin_source_dir`); nothing else lived there.
- Rework `lc init`: instead of copying the bundle, write
  `.claude/settings.json` with the permission tier plus
  `extraKnownMarketplaces` + `enabledPlugins`. Claude Code offers to install
  the plugin when the user trusts the folder. Hooks no longer live in
  settings.json — the plugin carries them.
- Add `emit_plugin_hint()` on the CLI group callback: emit a
  `<claude-code-hint>` stderr marker when `CLAUDECODE` is set, so Claude Code
  can offer the plugin. Inert until `lightcone` is in the official
  marketplace; harmless before then.
- Eval sandbox: install the plugin headlessly after `lc init` (the trust
  prompt never fires under `claude -p`). Non-fatal, with a TODO(LCR-131).
- Drop `tests/test_paper_extraction_caption.py` (imported a bundled script);
  add tests for the settings shape and the hint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RqaG474qW2qV7cPxJcYYM
The skills no longer ship in the wheel. Update every doc that described the
bundle or used the old `/lc-*` command names.

- Delete the per-skill doc pages and the authoring page; their content lives
  in the agent-skills repo. Collapse the Skills nav to a single overview.
- Rewrite `skills/index.md` as a plugin/command map that points to
  agent-skills.
- `install.md`: add the marketplace install for Claude Code and Codex.
- `architecture.md`, `contributing/setup.md`, `api/cli.md`,
  `api/site_registry.md`, `cli/init.md`, `maintainer.md`: replace the
  force-include / `get_plugin_source_dir` / `_install_claude_plugin` story
  with the settings.json marketplace registration and the plugin hint.
- `troubleshooting.md`, `agent-workflow.md`, `getting-started.md`,
  `glossary.md`, `user/index.md`, README, root CLAUDE.md: rename `/lc-new`,
  `/lc-from-code`, `/lc-from-paper`, `/lc-feedback` to their namespaced
  `/lightcone:*` and `/lightcone-experimental:*` forms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RqaG474qW2qV7cPxJcYYM
The CLI should not impose a permission policy the user never chose.
Permissions belong to the harness, the same layer principle behind moving the
skills to a plugin.

- Delete PERMISSION_TIERS and the `--permissions` option on `lc init`.
- `.claude/settings.json` now holds only the marketplace registration
  (extraKnownMarketplaces + enabledPlugins) — no permissions block.
- Salvage the HPC wisdom into docs: `docs/user/troubleshooting.md` gains a
  "Recommended permissions for cluster work" section with a copy-paste ruleset
  (the //scratch and //pscratch `ask` guards, the secrets/dangerous-command
  deny list) and a note that auto-accept mode is there for frictionless runs.
  Framed as offered policy, never imposed.
- Sweep the tier story from architecture, cli/init, glossary, api/cli,
  api/site_registry, and contributing/hpc-sites; point them at the new section.
- The eval sandbox runs `claude -p --dangerously-skip-permissions`, so it never
  relied on the tier — no change needed there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RqaG474qW2qV7cPxJcYYM
Four defects from adversarial review.

- `_PROJECT_CLAUDE_MD` (scaffolded project CLAUDE.md) still named `/lc-new`,
  `/lc-from-code`, `/lc-from-paper`. Rename to `/lightcone:new`,
  `/lightcone-experimental:from-code`, `/lightcone-experimental:from-paper`, and
  note that from-code/from-paper need the `lightcone-experimental` plugin —
  `lc init` enables only `lightcone`.
- Eval `DEFAULT_LOOP_PROMPT` invoked `/lc-cli` and `/astra`; rename to
  `/lightcone:cli` and `/lightcone:astra`.
- Plugin hint reached only the group callback, which Click's eager
  `--help`/`--version` and an unknown-subcommand `UsageError` all short-circuit.
  Move emission into a `_HintGroup.main` override that runs ahead of dispatch,
  so `lc`, `lc --help`, and `lc bogus` all emit. Extend the test.
- `docs/user/glossary.md` Skill entry still said "bundled with the
  lightcone-cli plugin"; rewrite for the marketplace reality.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RqaG474qW2qV7cPxJcYYM
We are not shipping a dormant feature. Claude Code only acts on hints that
target the official Anthropic marketplace, and `lightcone` is not listed there,
so the hint never fired. The discovery story is the settings.json trust-prompt
(primary) plus the documented `claude plugin install` command.

- Delete `emit_plugin_hint()` and the `_HintGroup` group override; restore the
  plain `@click.group()`. Drop the now-unused `Any` import.
- Delete the two hint tests.
- Remove the hint paragraph from architecture.md and api/cli.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RqaG474qW2qV7cPxJcYYM
Temporary pins so this branch can be exercised against the two in-review PRs.
Kept in one dedicated commit so they revert cleanly.

- Marketplace: `lc init` writes the agent-skills source with
  `ref: astra-plugin-rework` (agent-skills#15) instead of the default branch.
- Eval sandbox: the headless `claude plugin marketplace add` appends the same
  `@astra-plugin-rework` ref, so trials exercise the PR too.
- astra-tools: pin the dependency to the `astra-spec-command` branch
  (astra-tools#94) via a git direct reference; hatch needs
  `allow-direct-references` for that, added alongside.

Each pin carries a DOGFOOD PIN comment naming the PR to revert against.
uv.lock is gitignored, so the resolved lock is not committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RqaG474qW2qV7cPxJcYYM
Stale plugins in the wild still exec `lc hook pretool` from a PreToolUse
hook. With the subcommand gone, click's usage error exits 2 — which Claude
Code reads as "block this tool call" — so upgrading the CLI ahead of the
plugin would wedge every session, and the gate would block the very command
that fixes it.

Re-add `hook` as a hidden, argument-swallowing no-op: it accepts any
subcommand and options, always exits 0, and prints a one-line deprecation
notice to stderr (never stdout, which the harness may parse). No gate
logic — the marketplace plugin owns that now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxWZM3a8NwozgUUHvX79NG
`lc init` hard-refuses when astra.yaml exists, so projects created before the
plugin era had no path onto it. Add `--adopt`: it requires astra.yaml to
exist, skips the scaffold/Containerfile/venv/git steps, and idempotently
layers on only the missing integration bits — `.lightcone/` + lightcone.yaml,
`results/`, the `.claude/` marketplace registration, and the MyST report.

The settings merge is non-destructive: it adds only the marketplace entry and
the enabled-plugin key, preserving any existing permissions or other content.
Each file is skipped if already present, and the run prints what it added
versus skipped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxWZM3a8NwozgUUHvX79NG
`uv tool install lightcone-cli` exposed only `lc`, leaving `astra validate`
unreachable post-install. Re-export astra-tools' own entry point
(`astra.cli:main`) from [project.scripts] so both `lc` and `astra` land on
PATH.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxWZM3a8NwozgUUHvX79NG
`lc init` refused to run when astra.yaml already existed, and the round-1
`--adopt` flag bolted the existing-project path onto the side. Fold the two
into one convergent command: `lc init` is now idempotent and safe to run
anywhere.

On a fresh directory it scaffolds the full project (unchanged). On a
directory that already holds an astra.yaml it layers on only the missing
integration files — never rewriting astra.yaml, merging `.claude/settings.json`
non-destructively, and skipping the Containerfile, git, and venv steps. Both
paths share one idempotent `_layer_integration` helper and report what they
added versus skipped, converging to "Nothing to do" once integrated.

The only refusal left is a genuine I/O error; an existing scaffold file (e.g.
index.md) is skipped, not a hard stop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxWZM3a8NwozgUUHvX79NG
The CLI and the lightcone plugin ship on independent channels (uv for the
CLI, the Claude Code marketplace for the plugin), so their versions drift.
Add the CLI half of a skew-detection handshake.

`lc compat` (hidden) prints a small JSON object to stdout: the CLI version,
the minimum plugin version this CLI expects (new module-level `PLUGIN_MIN`
constant), and the plugin name. The plugin's SessionStart hook (agent-skills
side, separate PR) reads this, compares its own version, and warns with a heal
command on skew. Skew degrades, never blocks; the comparison lives plugin-side,
so this command stays a dumb reporter.

Also mark the `lc hook` stub as the retroactive half of the same contract —
it covers plugins built before the handshake existed — with a
`TODO(next-breaking): drop lc hook stub` marker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxWZM3a8NwozgUUHvX79NG
Document how the CLI and plugin upgrade. Add docs/user/upgrading.md and wire
it into the User Guide nav.

The page covers three points. The CLI and plugin travel on two independent,
order-free channels; neither assumes the other has moved; both degrade
gracefully, the same way a MyST report degrades a missing reference to plain
text. Skew is detected, not prevented: the `lc compat` SessionStart handshake
warns with the exact heal command and never blocks, and the `lc hook` stub is
the retroactive instance for pre-handshake plugins. Layout migrations are
convergent `lc init`: idempotent, self-reporting, safe anywhere — the
marketplace transition is the motivating example.

Also fix a now-stale troubleshooting note that said `lc init` refuses inside an
existing project.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxWZM3a8NwozgUUHvX79NG
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
lightcone-cli e98d640 Commit Preview URL

Branch Preview URL
Jul 19 2026, 11:17 PM

@github-actions

Copy link
Copy Markdown

✅ Eval Results

Metric Value
Score 1.00
Build complete
Cost $2.00
Turns 48
Duration 341s
lightcone-cli 0.3.8.dev14+g72830fb63 (72830fb6)
Results Download

Graders

✅ spec_valid (1.00)
✅ all_materialized (1.00)

Full output
permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.
23:22:26 lightcone.eval.sandbox [sandbox build] #13 [10/11] WORKDIR /home/evaluser
23:22:26 lightcone.eval.sandbox [sandbox build] #14 [11/11] RUN mkdir -p ~/.claude && echo '{"hasCompletedOnboarding": true}' > ~/.claude.json
23:22:26 lightcone.eval.sandbox [sandbox build] #15 exporting to image
23:22:43 lightcone.eval.sandbox Created sandbox 99862493-c2a4-4467-afe9-c05ff400811d for trial build-snae-0
23:22:43 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/99862493-c2a4-4467-afe9-c05ff400811d/files/bulk-upload "HTTP/1.1 200 OK"
23:22:44 lightcone.eval.sandbox Installed wheels: ['lightcone_cli-0.3.8.dev14+g72830fb63-py3-none-any.whl']
23:22:45 lightcone.eval.sandbox Headless lightcone plugin install failed (exit 1); trial runs without plugin skills. See LCR-131.
Adding marketplace…✘ Failed to add marketplace: Failed to clone marketplace repository: SSH host key is not in your known_hosts file. To add it, connect once manually (this will show the fingerprint for you to verify):
  ssh -T git@github.com

Or use an HTTPS URL instead (recommended for public repos).

Original error: Cloning into '/home/evaluser/.claude/plugins/marketplaces/LightconeResearch-agent-skills'...
No ED25519 host key is known for github.com and you have requested strict checking.
Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.


23:22:45 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/99862493-c2a4-4467-afe9-c05ff400811d/files/bulk-upload "HTTP/1.1 200 OK"
23:22:45 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/99862493-c2a4-4467-afe9-c05ff400811d/files/bulk-upload "HTTP/1.1 200 OK"
23:22:45 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/99862493-c2a4-4467-afe9-c05ff400811d/files/bulk-upload "HTTP/1.1 200 OK"
23:22:45 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/99862493-c2a4-4467-afe9-c05ff400811d/files/bulk-upload "HTTP/1.1 200 OK"
23:28:28 lightcone.eval.sandbox Deleted sandbox for trial build-snae-0
  snae trial 0: score=1.00 complete

lightcone-cli: 0.3.8.dev14+g72830fb63 (HEAD 72830fb6)
ASTRA: 0.2.11.dev20+g2546fce55

  Eval Results: Scores  
┏━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Task ┃     Score     ┃
┡━━━━━━╇━━━━━━━━━━━━━━━┩
│ snae │ 1.00 +/- 0.00 │
│      │ pass@k: 100%  │
└──────┴───────────────┘

   Eval Results: Cost &   
         Duration         
┏━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Task ┃ Cost / Duration ┃
┡━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ snae │      $2.00      │
│      │      341s       │
└──────┴─────────────────┘

Total: 1 trials, $2.00, 341s

Results saved to: eval-results/build-72830fb6/results.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant