Repository navigation
Close the skill/binary bootstrap loop: let a CLI-only install set up agent skills #2368
Description
Relationship to #2146 — this is the third direction
#2146 ("One-line install: curl | sh bootstrap with optional GUI prompt, plus skill-triggered install") covered the install story broadly and is closed. It explicitly names two directions between the skill and the binary:
- skill → CLI — One-line install: curl | sh bootstrap with optional GUI prompt, plus skill-triggered install #2146 built this.
SKILL.md'scommand not found: nodespacerow now offers a guided install instead of dead-ending (its acceptance criteria, lines 116-118). - GUI → skill — pre-existing, described at One-line install: curl | sh bootstrap with optional GUI prompt, plus skill-triggered install #2146 line 100:
skill_setup.rsruns the installer on the app's first launch and recordsskill_installedin~/.nodespace/setup.json.
This issue is the third direction: CLI → skill, which neither covers. A user who installs CLI-only has no GUI first launch to trigger skill_setup.rs, and #2146's work runs the other way — it gets them the CLI from the skill, not the skill from the CLI.
#2146 line 102 already anticipates the reconciliation constraint this inherits: "the app's first-launch installer must not clobber a skill the user installed manually, and vice versa." A CLI-driven installer becomes a third writer to the same state and must not clobber either.
The new fact not present in #2146: nodespace-skill-installer is bundled only as a Tauri sidecar, so a CLI-only machine has no copy of it and no release asset to fetch one from. That is what makes this a distribution problem rather than a wiring one.
The loop does not close
The intended path, per nodespace-skill's README, is:
- User adds the skill to their agent harness
- The skill tells them the CLI and daemon are prerequisites:
curl -fsSL https://nodespace.ai/install.sh | sh - …and the thing they installed should then set the skill up properly
Step 3 does not happen. install.sh never touches skills — confirmed, it has no skill handling at all — and the CLI has no subcommand for it. A user who arrives from the skill, follows its own instruction, and installs CLI-only ends up with the skill still in whatever partial state they hand-copied it into.
GUI users do get this: skill_setup.rs::install_skill() runs the real installer during onboarding and reports which agents it installed into. CLI users get nothing — despite being, almost by definition, the people already living in a terminal with these harnesses installed.
The installer already exists — it just is not reachable
packages/skill/ is not a bare file copy. It already does everything a wizard would:
agents.tsdefines all four harnesses —claude-code,codex,antigravity,opencode— each with adetectionDir, aninstallDir, and its own shims- Detection is directory-presence based (see the test at
skill_setup.rs:848, which creates a fake~/.claude"so the installer detects claude-code") - Per-harness integration, not one generic folder: Claude Code gets
nodespace-hook.ts, Codex getsnodespace-plugin.ts, OpenCode getsnodespace-plugin.ts, and Antigravity gets its own shim (format TBD by Replace Gemini CLI with Antigravity CLI as a supported PTY agent #2473) parse_installer_outputalready reads back success lines like✓ claude-code: installed 2 file(s)
This is not a "build a wizard" issue. Start from packages/skill/, not a blank page.
Why a CLI user cannot reach it today
nodespace-skill-installer is bundled as a Tauri sidecar (tauri.conf.json:49, alongside resources/skill/**/*). It is built during the Tauri jobs and never uploaded as a standalone release asset. So a CLI-only machine has no copy of the installer, and nothing in the release publishes one it could fetch.
That is the actual blocker, and it is a distribution question rather than a coding one.
Design decision needed
Options, roughly in increasing order of effort:
- Upload
nodespace-skill-installeras a release asset, and haveinstall.shdownload and run it after the CLI install. Smallest change; matches how install.sh already fetches other artifacts. - A
nodespace skill installsubcommand on the CLI itself. Most discoverable — it shows up in--helpalongside the existinguninstall— and it is the only option that handles the re-run case below. Needs the installer available to the CLI, so it likely subsumes option 1. - Reimplement detection in
install.sh. Rejected: it would be a second copy ofagents.ts's harness table in another language, and this repo has been bitten by exactly that kind of duplicate-that-drifts more than once (see Install/release channel drift: GUI discovery, unsynced install.sh, pkg KeepAlive bug, incomplete cask zap #2366).
There is a real argument for option 2 beyond the initial install: today nothing handles a harness installed later. Add Codex a month after installing NodeSpace and nothing notices or offers to extend the skill to it — install_skill only runs during GUI onboarding. A subcommand makes that a one-liner.
Note the installer has a compiled-binary path (resolve_compiled_installer_path) with a script fallback, and a test asserting the compiled variant works with "zero runtime on PATH" — so a shell caller can likely invoke it without requiring Bun, but that should be verified rather than assumed.
Which repo each change lands in
Three repos are involved, and only two are editable:
| Repo | Role | Editable |
|---|---|---|
nodespace-core |
Source of truth: the CLI, the app, packages/skill/ (agents.ts, shims, the nodespace-skill-installer sidecar) |
Yes |
nodespace-skill |
Generated publish target. Rendered from packages/skill and pushed by this repo's release pipeline. A hand edit there is overwritten, not merged, on the next release |
No |
nodespace-website |
Hosts install.sh as a committed static file |
Yes |
This issue belongs in nodespace-core because everything it touches — the harness table, the shims, the sidecar bundling, any new subcommand — lives in packages/skill/. Nothing here changes SKILL.md, references/cli.md, or marketplace.json, which is all nodespace-skill holds.
Worth weighing when choosing between the options above: option 1 spans two repos (upload the asset from nodespace-core, add the fetch logic to nodespace-website's install.sh), while option 2 stays entirely within nodespace-core. Given that cross-repo sync is precisely what is already broken in #2366 item 2 — a missing token has left install.sh unsynced for five releases — keeping this change inside one repo is worth something.
Proposed UX
Detected agent harnesses:
- Claude Code
- Antigravity CLI
Install the NodeSpace skill into them? [Y/n]
Follow install.sh's existing conventions: ns_prompt_gui() already has the TTY-detection pattern, and the same no-TTY rule should apply — never prompt without a terminal, pick a documented default, and say which was chosen.
Acceptance criteria
- Decide between options 1 and 2 above (or both) and record why
- A CLI-only install can install the skill without the GUI app present
- Detection reuses
packages/skill'sagents.ts— no second copy of the harness table - All four harnesses supported, with their per-harness shims, matching what the GUI path installs
- Non-interactive behaviour defined: no prompt without a TTY, documented default, chosen default stated in output
- A flag for non-interactive use, mirroring the existing
--gui/--no-guipair - Re-running is safe and idempotent, and picks up harnesses installed since last time
- Output reports which harnesses were installed into, and which were detected but skipped
- Skipping is graceful when no harness is detected — no error, no empty prompt
- Verified end to end on a machine with more than one harness present
Context
Found while tracing how the skill and the binary are meant to bootstrap each other. Related to #2366 (install/release channel drift), but distinct: the four items there are artifacts that drifted out of sync, while this is a path that was never wired up, and it needs a design decision rather than a mechanical fix.
Harness table update: the fourth harness was Gemini CLI at the time this issue was filed; Google discontinued Gemini CLI for individual/consumer accounts, so #2473 replaces it with Antigravity CLI (agy) in packages/skill/src/agents.ts. This issue's harness table and example output above have been updated to match — implementation here should target whatever agents.ts contains once #2473 lands (or build the shim format alongside it if worked concurrently).
Activity
malibio commentedon Sep 8, 2026
Baseline (frontend, Happy-DOM): Test Files 238 passed (238), Tests 4925 passed (4925). Duration 144.51s.
Address review: report skipped harnesses on uninstall, test compiled-…