Skip to content

feat(cli): add skills add command to install the /orchestrate skill#1205

Merged
willwashburn merged 4 commits into
mainfrom
claude/skills-command-tui-ebpmt1
Jun 27, 2026
Merged

feat(cli): add skills add command to install the /orchestrate skill#1205
willwashburn merged 4 commits into
mainfrom
claude/skills-command-tui-ebpmt1

Conversation

@willwashburn

@willwashburn willwashburn commented Jun 27, 2026

Copy link
Copy Markdown
Member

Summary

Adds agent-relay skills add, which downloads the /orchestrate skill from agentrelay.com/skill.md and installs it into one or more coding harnesses.

  • Interactive TUI (dependency-free, raw keypress — no prompt library added):
    1. Scope picker — install into this project or globally (home config).
    2. Harness multi-select — toggle Claude Code, Codex, Cursor, Gemini, OpenCode (space to toggle, a for all, enter to confirm).
  • Non-interactive flags for scripts/CI: --global/--local, --harness <ids>, --all. A non-TTY shell with missing flags errors with usage guidance instead of hanging.

Each harness maps onto its native custom-command / skill convention:

Harness Path Format
Claude Code .claude/skills/orchestrate/SKILL.md full skill + frontmatter
Codex .codex/prompts/orchestrate.md body-only prompt
Cursor .cursor/commands/orchestrate.md full (keeps description)
Gemini .gemini/commands/orchestrate.toml TOML prompt block (escaped)
OpenCode .opencode/command/orchestrate.md (project) / ~/.config/opencode/command/orchestrate.md (global) body-only prompt

Core install logic (lib/skills-install.ts), the TUI (lib/skills-tui.ts), and command wiring (commands/skills.ts) are split into separately unit-tested modules. Registered in bootstrap.ts; CHANGELOG.md updated under Added.

Test Plan

  • Tests added/updated — 29 tests across install logic, TUI pickers, command flows (flags, prompts, cancel, error paths), and bootstrap command registration
  • Manual testing completed — typecheck clean, build green, verified --help output and the --harness/scope validation guards via the built CLI

Note: the live skill.md fetch is blocked by the build sandbox's proxy, so the network path is covered by mocked tests; it resolves normally in a standard environment.

Screenshots

🤖 Generated with Claude Code


Generated by Claude Code

Review in cubic

`agent-relay skills add` downloads the /orchestrate skill from
agentrelay.com/skill.md and installs it into one or more coding harnesses.

An interactive TUI asks whether to install for the current project or
globally, then which harnesses to target. A dependency-free keypress
picker (single-select scope + multi-select harnesses) is used; no prompt
library is added. Non-interactive shells are driven by --global/--local,
--harness <ids>, and --all flags.

Each harness maps onto its native convention:
- Claude Code: .claude/skills/orchestrate/SKILL.md (full skill)
- Codex:       .codex/prompts/orchestrate.md (body-only prompt)
- Cursor:      .cursor/commands/orchestrate.md (full, frontmatter kept)
- Gemini:      .gemini/commands/orchestrate.toml (TOML prompt block)
- OpenCode:    .opencode/command/orchestrate.md (body-only prompt)

Core install logic, the TUI, and command wiring are split into separately
unit-tested modules (29 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012bgEtgqAsEJTLddt5ZuuBz
@willwashburn willwashburn requested a review from khaliqgant as a code owner June 27, 2026 04:53
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f6db83b-e426-4d16-ae1e-94d69b6e62a2

📥 Commits

Reviewing files that changed from the base of the PR and between 2e805e3 and d11825a.

📒 Files selected for processing (1)
  • packages/cli/src/cli/lib/skills-install.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/cli/lib/skills-install.test.ts

📝 Walkthrough

Walkthrough

Adds agent-relay skills add, which fetches /orchestrate, installs it per selected scope and harnesses, prompts through a raw-keypress TUI when flags are missing, and wires the command into CLI bootstrap with matching tests and release metadata.

Changes

Skills add command

Layer / File(s) Summary
Skill installation and fetch
packages/cli/src/cli/lib/skills-install.ts, packages/cli/src/cli/lib/skills-install.test.ts
Adds skill parsing, harness target rendering and path resolution, per-harness install results, and tests for parsing, overwrite handling, and fetch failures.
TUI pickers
packages/cli/src/cli/lib/skills-tui.ts, packages/cli/src/cli/lib/skills-tui.test.ts
Adds raw-keypress scope and harness pickers with navigation, selection, cancellation, and toggle-all behavior, plus picker tests.
CLI command wiring
packages/cli/src/cli/commands/skills.ts, packages/cli/src/cli/commands/skills.test.ts, packages/cli/src/cli/bootstrap.ts, packages/cli/src/cli/bootstrap.test.ts
Adds skills add flag parsing, interactive fallbacks, fetch/install orchestration, per-harness reporting, and bootstrap command-tree registration/tests.
Release metadata
CHANGELOG.md, .agentworkforce/trajectories/completed/2026-06/traj_813j4f2lfyff/summary.md, .agentworkforce/trajectories/completed/2026-06/traj_813j4f2lfyff/trajectory.json
Adds the changelog entry and trajectory records for the completed feature.

Sequence Diagram(s)

sequenceDiagram
  participant registerSkillsCommands
  participant selectScope
  participant selectHarnesses
  participant fetchSkill
  participant installSkill
  participant reportResults
  participant SkillWriter

  registerSkillsCommands->>selectScope: resolve scope when flags are missing
  registerSkillsCommands->>selectHarnesses: resolve harnesses when flags are missing
  registerSkillsCommands->>fetchSkill: download agentrelay.com/skill.md
  fetchSkill-->>registerSkillsCommands: raw markdown
  registerSkillsCommands->>installSkill: install /orchestrate
  installSkill->>SkillWriter: write rendered harness files
  installSkill-->>registerSkillsCommands: per-harness results
  registerSkillsCommands->>reportResults: log successes and failures
  reportResults-->>registerSkillsCommands: exit code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

I hopped through scopes with ears held high,
Then fetched /orchestrate from the sky.
A keypress winked, the harnesses lined up neat,
And every little burrow got a shiny new treat. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Clear, specific title matching the main change.
Description check ✅ Passed Matches the template with Summary, Test Plan, and Screenshots sections filled in.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/skills-command-tui-ebpmt1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the agent-relay skills add command, allowing users to install the /orchestrate skill from agentrelay.com/skill.md into coding harnesses like Claude Code, Codex, Cursor, Gemini, and OpenCode, either interactively via a dependency-free TUI or non-interactively using CLI flags. Feedback focuses on improving robustness, including adding a network timeout and unified error handling to fetchSkill, implementing defensive checks for getProjectPaths() and setRawMode to prevent runtime crashes, and supporting optional leading whitespace in the frontmatter regex parser.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

I am having trouble creating individual review comments. Click here to see my feedback.

packages/cli/src/cli/lib/skills-install.ts (243-259)

high

Wrap the entire network fetch and body reading in a single try-catch block to gracefully handle stream reading errors (e.g., from res.text()), and add a network timeout to prevent the CLI from hanging indefinitely on slow or unresponsive connections.

export async function fetchSkill(url: string = ORCHESTRATE_SKILL.url): Promise<string> {
  try {
    const res = await fetch(url, {
      headers: { accept: 'text/markdown, text/plain, */*' },
      signal: AbortSignal.timeout(10000),
    });
    if (!res.ok) {
      throw new Error(`HTTP ${res.status}`);
    }
    const text = await res.text();
    if (!text.trim()) {
      throw new Error('Response body was empty');
    }
    return text;
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    throw new Error(`Failed to download skill from ${url}: ${message}`);
  }
}

packages/cli/src/cli/commands/skills.ts (45-48)

medium

Add a defensive check for paths in case getProjectPaths() returns null or undefined to prevent potential runtime TypeError crashes.

function resolveProjectRoot(): string {
  const paths = getProjectPaths() as { projectRoot?: string } | null | undefined;
  return paths?.projectRoot ?? process.cwd();
}

packages/cli/src/cli/lib/skills-install.ts (57-62)

medium

Allow optional leading whitespace in the regex to support indented YAML frontmatter keys.

function readScalar(frontmatter: string, key: string): string | undefined {
  const re = new RegExp("`^\\\\s*\\${key}\\\\s*:\\\\s*(.+)$`", 'm');
  const m = re.exec(frontmatter);
  if (!m) return undefined;
  return m[1].trim().replace(/^["']|["']$/g, '');
}

packages/cli/src/cli/lib/skills-tui.ts (48-49)

medium

Check if setRawMode is a function before calling it to prevent runtime crashes in environments where input is a custom stream or mock that doesn't implement it.

  const wasRaw = input.isRaw ?? false;
  if (input.isTTY && typeof input.setRawMode === 'function') {
    input.setRawMode(true);
  }

packages/cli/src/cli/lib/skills-tui.ts (53-58)

medium

Check if setRawMode is a function before calling it in the cleanup handler to prevent runtime crashes.

    const cleanup = (): void => {
      input.off('keypress', handler);
      if (input.isTTY && typeof input.setRawMode === 'function') {
        input.setRawMode(wasRaw);
      }
      output.write(SHOW_CURSOR);
      input.pause();
    };

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9eb7aa1072

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +112 to +114
'.codex',
'prompts',
`${ORCHESTRATE_SKILL.slug}.md`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Install Codex skills in Codex skill directories

I checked the current Codex skills docs (https://developers.openai.com/codex/skills): Codex discovers repo/user skills under .agents/skills / $HOME/.agents/skills, while .codex/prompts is only the deprecated custom-prompt location and project-local .codex/prompts is not scanned. When a user selects the Codex harness—especially with the default project scope—the command reports success but Codex's /skills/skill mention flow will not find the installed /orchestrate skill; write the full SKILL.md into the Codex skill locations instead.

Useful? React with 👍 / 👎.

Comment on lines +156 to +157
? path.join(ctx.homeDir, '.config', 'opencode', 'command', `${ORCHESTRATE_SKILL.slug}.md`)
: path.join(ctx.projectRoot, '.opencode', 'command', `${ORCHESTRATE_SKILL.slug}.md`),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use OpenCode's plural commands directory

I checked the OpenCode commands docs (https://opencode.ai/docs/commands/), which load markdown commands from ~/.config/opencode/commands/ or .opencode/commands/. These paths use singular command, so choosing the OpenCode harness reports an install but OpenCode will not discover /orchestrate; change both global and project paths to commands.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/cli/commands/skills.ts`:
- Around line 41-43: The fallback in resolveProjectRoot() is unreachable because
getProjectPaths() throws before returning, so the current `?? process.cwd()`
never applies. Update resolveProjectRoot() to catch failures from
getProjectPaths() and only fall back to process.cwd() when the project lookup
fails, while still preserving the resolved projectRoot when available. Make sure
the skills command flow that uses deps.getContext() can reach this fallback for
global operations like `skills add --global` from outside an Agent Relay
project.

In `@packages/cli/src/cli/lib/skills-install.ts`:
- Line 44: The regex in skills-install’s normalization step currently contains a
literal BOM character, which triggers the irregular whitespace lint rule. Update
the `normalized` assignment in `skills-install.ts` to use an escaped Unicode
form in the `replace` pattern (for example, `^\uFEFF`) instead of the raw
character so the `replace` call remains equivalent and lint-safe.
- Around line 242-249: The fetchSkill download can hang indefinitely because
fetch() is currently unbounded; update fetchSkill to use an AbortController
timeout around the fetch call. Keep the existing error handling in fetchSkill,
and when the timeout triggers, abort the request and throw a clear
timeout-specific error message so stalled skill downloads fail fast in
agent-relay skills add.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ff8d043-d609-4b7b-8762-ae9d0d30d95c

📥 Commits

Reviewing files that changed from the base of the PR and between 80d6875 and 4607772.

📒 Files selected for processing (11)
  • .agentworkforce/trajectories/completed/2026-06/traj_813j4f2lfyff/summary.md
  • .agentworkforce/trajectories/completed/2026-06/traj_813j4f2lfyff/trajectory.json
  • CHANGELOG.md
  • packages/cli/src/cli/bootstrap.test.ts
  • packages/cli/src/cli/bootstrap.ts
  • packages/cli/src/cli/commands/skills.test.ts
  • packages/cli/src/cli/commands/skills.ts
  • packages/cli/src/cli/lib/skills-install.test.ts
  • packages/cli/src/cli/lib/skills-install.ts
  • packages/cli/src/cli/lib/skills-tui.test.ts
  • packages/cli/src/cli/lib/skills-tui.ts

Comment thread packages/cli/src/cli/commands/skills.ts Outdated
Comment thread packages/cli/src/cli/lib/skills-install.ts Outdated
Comment thread packages/cli/src/cli/lib/skills-install.ts Outdated
- Fix lint error: replace literal U+FEFF BOM in parseSkill's regex with the
  `` escape (no-irregular-whitespace).
- Codex: install to `.agents/skills/orchestrate/SKILL.md` (the portable
  SKILL.md standard Codex scans from cwd→repo root and $HOME), with the full
  skill, instead of the unscanned/deprecated `.codex/prompts`.
- OpenCode: use the plural `commands/` directory (`.opencode/commands/` and
  `~/.config/opencode/commands/`) so OpenCode discovers `/orchestrate`.
- Bound the skill download with an AbortController timeout so a stalled
  connection can't hang `skills add` in CI; report timeouts clearly.
- Defensive try/catch in resolveProjectRoot so a global install can't be
  blocked by project resolution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012bgEtgqAsEJTLddt5ZuuBz

Copy link
Copy Markdown
Member Author

Addressed the review feedback in 2e805e3 (lint is now green locally — 0 errors):

  • Lint failure (BOM): replaced the literal U+FEFF in parseSkill's regex with ``.
  • Codex path: verified against the Codex skills docs — Codex scans .agents/skills/<name>/SKILL.md (the portable SKILL.md standard) from cwd→repo root and from $HOME, not the deprecated/unscanned .codex/prompts. Switched to .agents/skills/orchestrate/SKILL.md with the full skill.
  • OpenCode path: verified against the OpenCode commands docs — the directory is plural commands/. Fixed both .opencode/commands/ and ~/.config/opencode/commands/.
  • Download timeout: fetchSkill is now bounded by an AbortController (15s default) and reports timeouts clearly, so a stalled connection can't hang skills add in CI.
  • resolveProjectRoot: added a defensive try/catch (the original premise that getProjectPaths() throws isn't accurate — it falls back to cwd — but the guard is harmless).

Tests updated for the new paths plus a timeout test; 30 tests pass.


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/cli/lib/skills-install.test.ts`:
- Around line 187-197: The fetch stub in skills-install.test.ts is not always
restored if the expectation fails, which can leave the global mocked for later
tests. Update the test around fetchSkill to ensure vi.unstubAllGlobals() always
runs by wrapping the assertion in a try/finally block, or move the cleanup into
a shared afterEach hook, so the stubbed fetch is reliably reset even when the
timeout assertion throws.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8541678e-08fe-43d1-a3e3-131755416cb8

📥 Commits

Reviewing files that changed from the base of the PR and between 4607772 and 2e805e3.

📒 Files selected for processing (3)
  • packages/cli/src/cli/commands/skills.ts
  • packages/cli/src/cli/lib/skills-install.test.ts
  • packages/cli/src/cli/lib/skills-install.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/cli/src/cli/lib/skills-install.ts
  • packages/cli/src/cli/commands/skills.ts

Comment thread packages/cli/src/cli/lib/skills-install.test.ts Outdated
Move `vi.unstubAllGlobals()` into an afterEach so the stubbed global
`fetch` is always restored, even if an assertion throws — preventing a
failed test from leaking the mock into later tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012bgEtgqAsEJTLddt5ZuuBz
@willwashburn willwashburn merged commit c7acdf9 into main Jun 27, 2026
47 checks passed
@willwashburn willwashburn deleted the claude/skills-command-tui-ebpmt1 branch June 27, 2026 13:44
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