Skip to content

feat(agent): add setup-skills command for AI assistant skills - #1881

Merged
simplesagar merged 17 commits into
mainfrom
feat/agent-setup-skills
Feb 15, 2026
Merged

feat(agent): add setup-skills command for AI assistant skills#1881
simplesagar merged 17 commits into
mainfrom
feat/agent-setup-skills

Conversation

@simplesagar

@simplesagar simplesagar commented Feb 12, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds speakeasy agent setup-skills command for installing Speakeasy companion skills for AI coding assistants (Claude Code, Cursor, etc.)
  • Skills are fetched directly from the GitHub API (no npx/Node.js dependency) and installed natively:
    • Catalog fetched from GitHub Contents API
    • SKILL.md files downloaded from raw.githubusercontent.com
    • Written to .agents/skills/<name>/SKILL.md (canonical), symlinked from all known agent directories
  • Supports --auto flag for non-interactive installation of default skills (speakeasy-context)
  • Hooks into install.sh as a post-install step, only prompting when running in an interactive terminal
CleanShot 2026-02-15 at 14 19 38@2x

Test plan

  • Run speakeasy agent setup-skills in a terminal — verify confirm prompt, then multi-select with speakeasy-context preselected
  • Run speakeasy agent setup-skills --auto — verify it installs speakeasy-context without prompts
  • Verify .agents/skills/speakeasy-context/SKILL.md exists and agent dirs (.claude/skills/, .cursor/skills/, etc.) have symlinks
  • Run echo | speakeasy agent setup-skills — verify no prompt, graceful skip
  • Run bash install.sh in an interactive terminal — verify the setup-skills prompt appears after ASCII art
  • Run cat install.sh | sh — verify setup-skills is NOT prompted (non-interactive stdin)

🤖 Generated with Claude Code

simplesagar and others added 3 commits February 12, 2026 11:10
Add `speakeasy agent setup-skills` with an interactive multi-select UI
for installing Speakeasy companion skills for AI coding assistants.
Hook into install.sh as a post-install step for interactive terminals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use --skill flags with single repo arg instead of per-skill repo paths.
Add --agent '*' -y to skip agent selection prompt. Remove
customize-sdk-runtime which doesn't exist in the skills repo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@simplesagar
simplesagar marked this pull request as ready for review February 12, 2026 19:44

@devin-ai-integration devin-ai-integration 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@vishalg0wda vishalg0wda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🚀

Delegate skill selection to the skills CLI instead of maintaining a
hardcoded catalog. Add confirmation prompt warning users that npx
(Node.js) will be used before running any commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration 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.

Devin Review found 2 new potential issues.

View 8 additional findings in Devin Review.

Open in Devin Review

Comment thread install.sh Outdated
# Offer to install agent skills if running in an interactive terminal
if [ -t 0 ] && [ -t 1 ]; then
echo ""
"$INSTALL_DIR/$BINARY_NAME" agent setup-skills 2>/dev/null || true

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.

🔴 install.sh 2>/dev/null suppresses bubbletea TUI rendering, causing invisible prompt and potential hang

When install.sh invokes the setup-skills command, it redirects stderr to /dev/null. However, bubbletea (v1.3.5, used by huh via charm.NewForm) renders its TUI to os.Stderr by default. This means the interactive confirm dialog at cmd/agent_setup_skills.go:107-111 is rendered to /dev/null and is invisible to the user.

Root Cause and Impact

The flow is:

  1. install.sh:284 checks [ -t 0 ] && [ -t 1 ] — stdin and stdout are terminals ✓
  2. install.sh:286 runs "$INSTALL_DIR/$BINARY_NAME" agent setup-skills 2>/dev/null
  3. Inside the binary, IsInteractive() at internal/model/command.go:181 checks os.Stdout — it's still a terminal → returns true
  4. runSetupSkillsInteractive is called, which shows fmt.Println messages on stdout (visible) then launches a bubbletea TUI confirm dialog
  5. Bubbletea renders the confirm dialog to stderr (its default output), which is /dev/nullinvisible to the user
  6. The program blocks reading stdin for the user's answer to a prompt they cannot see

The user sees:

Speakeasy offers companion skills for AI coding assistants ...
This will use npx (Node.js) to install skills from github.com/speakeasy-api/skills

Then the terminal appears to hang with no visible prompt. The user must blindly press keys or Ctrl+C to continue.

Impact: The install script hangs after the ASCII art banner, breaking the installation experience for all interactive users.

Suggested change
"$INSTALL_DIR/$BINARY_NAME" agent setup-skills 2>/dev/null || true
"$INSTALL_DIR/$BINARY_NAME" agent setup-skills || true
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — bubbletea renders the TUI to stderr, so 2>/dev/null would hide the interactive prompt and cause an apparent hang. Removed it; the || true alone is sufficient to prevent install.sh from failing. Fixed in 4bd15af.

Comment thread cmd/agent_setup_skills.go Outdated
func runNpxSkills(ctx context.Context, args ...string) error {
fullArgs := append([]string{"--yes", "skills"}, args...)

log.From(ctx).Infof("Running: npx %s", fmt.Sprintf("skills %s", joinArgs(args)))

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.

🟡 Log message omits --yes flag, misrepresenting the actual command executed

The runNpxSkills function logs a command that differs from the one it actually executes.

Detailed Explanation

At cmd/agent_setup_skills.go:47, fullArgs is constructed as ["--yes", "skills", ...args], so the actual command run is npx --yes skills <args>. However, at line 49, the log message is:

log.From(ctx).Infof("Running: npx %s", fmt.Sprintf("skills %s", joinArgs(args)))

This logs Running: npx skills <args>, omitting the --yes flag. The --yes flag is significant because it auto-confirms installing the npm package without user consent. If a user tries to reproduce the logged command, they'll get a different behavior (npx will prompt for confirmation).

Impact: Misleading debug output; users attempting to reproduce or troubleshoot see a different command than what was actually run.

Suggested change
log.From(ctx).Infof("Running: npx %s", fmt.Sprintf("skills %s", joinArgs(args)))
log.From(ctx).Infof("Running: npx --yes skills %s", joinArgs(args))
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed — log message now includes --yes to match the actual command being executed. Fixed in 4bd15af.

simplesagar and others added 2 commits February 13, 2026 08:34
Remove 2>/dev/null from install.sh that would hide the bubbletea TUI.
Fix log message to include the --yes flag matching the actual command.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@danielkov

Copy link
Copy Markdown
Contributor

Wonder if instead of depending on npx and downloading skills to the users' device just for this - if we should just copy/replicate the skill installation logic into here.

Pros:

  • Roughly same lines of code
  • No failure mode if node isn't installed
  • Faster
  • We can rip the skills from our repo directly, if whatever infra skills uses goes down, we still keep working

Cons:

  • We need to maintain this layer

What do you think?

@simplesagar

Copy link
Copy Markdown
Member Author

Good call — agree on all the pros. The install logic is pretty simple under the hood:

  1. Clone/fetch SKILL.md files from speakeasy-api/skills repo (we can use the GitHub API or embed them)
  2. Write to .agents/skills/<name>/SKILL.md (canonical location)
  3. Symlink from each agent's skills dir (.claude/skills/, .cursor/skills/, etc.) → ../../.agents/skills/<name>

We already have the skill content embedded via the speakeasy-agent-mode-content module, so we could potentially source from there too. Let me rewrite this to drop the npx dependency entirely.

…tion

Drop the npx/Node.js requirement entirely. Skills are now fetched
directly from the GitHub API and installed natively:
- Fetches skill catalog from GitHub Contents API
- Downloads SKILL.md via raw.githubusercontent.com
- Writes to .agents/skills/<name>/SKILL.md (canonical location)
- Creates symlinks from all known agent directories

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@simplesagar

Copy link
Copy Markdown
Member Author

@danielkov Rewrote this to drop the npx dependency entirely — skills are now installed natively in Go:

  • Catalog fetch: GitHub Contents API (GET /repos/speakeasy-api/skills/contents/skills) to list available skills
  • Skill download: raw.githubusercontent.com to grab each SKILL.md — one HTTP GET per skill
  • Installation: Writes to .agents/skills/<name>/SKILL.md (canonical), then creates relative symlinks from all 31 known agent dirs (.claude/skills/, .cursor/skills/, etc.)

No Node.js, no npx, no npm packages. Works even if the user has never installed Node. The interactive flow fetches the catalog live so there's no hardcoded skill list to maintain either.

devin-ai-integration[bot]

This comment was marked as resolved.

os.Remove fails silently on non-empty directories, which would cause
the subsequent os.Symlink to fail. Use os.RemoveAll instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread cmd/agent_setup_skills.go Outdated

// agentDirs lists well-known agent skill directory paths (relative to project root).
// .agents/skills is the canonical location; the rest are symlinked to it.
var agentDirs = []string{

@ThomasRooney ThomasRooney Feb 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Might be nice to just re-use this form https://github.com/vercel-labs/skills/blob/82dd76bda58bedde5ddbf8f86fe63a538db20c19/src/agents.ts#L13

Such that we can offer to install on specific agents (and by default, pick just a few like claude, windsurf, cursor, mistral etc).

Otherwise there's a lot of noise in the git repo but usually teams all use the same 2-3 agents.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good idea — added an agent selection step to the interactive flow. The flow is now:

  1. Confirm prompt ("Would you like to install agent skills?")
  2. Agent multi-select — Claude Code, Cursor, Windsurf, and Copilot preselected; all others available but unchecked
  3. Skill multi-select — speakeasy-context preselected

--auto mode installs for the same 4 default agents. Also updated agent directory paths to match the upstream registry (e.g. .codeium/windsurf/skills, .pi/agent/skills). Pushed in 8ec82ba.

Comment thread cmd/agent_setup_skills.go
Comment on lines +164 to +166
if err := os.MkdirAll(agentSkillsDir, 0o755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", agentSkillsDir, err)
}

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.

Is this what skills does right now? I'd probably go with existence check vs creating all of these directories by default.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done

simplesagar and others added 3 commits February 15, 2026 14:29
Address PR feedback from Thomas: let users pick which agents to install
for instead of creating dirs for all 31 agents. Claude Code, Cursor,
Windsurf, and Copilot are preselected by default. Also fixes agent
directory paths to match upstream skills registry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
simplesagar and others added 2 commits February 15, 2026 14:37
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
They all share the canonical .agents/skills directory, so show them
as one entry instead of three separate options.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@simplesagar
simplesagar enabled auto-merge (squash) February 15, 2026 22:44
@simplesagar
simplesagar merged commit 89688fa into main Feb 15, 2026
8 checks passed
@simplesagar
simplesagar deleted the feat/agent-setup-skills branch February 15, 2026 22:52
simplesagar added a commit that referenced this pull request Feb 16, 2026
)

## Summary

- After `speakeasy quickstart` configures the project but **before**
running SDK generation, prompts the user to install the
`speakeasy-context` agent skill for AI coding assistants
- Reuses the existing `speakeasy agent setup-skills --auto` command
(`runSetupSkills`) — no duplicated logic
- Skips the prompt if skills are already installed or running in
non-interactive mode

Resolves GEN-2504

Supersedes #1887 (rebased onto main to remove already-merged #1881
commits from the diff)

## How to verify locally

### 1. Build and run quickstart (interactive, accept skill install)
```bash
go build -o speakeasy . && ./speakeasy quickstart
```
After project setup (schema, target, output dir) but **before generation
starts**, you should see:
```
Install Speakeasy agent skills for AI coding assistants (Claude Code, Cursor, etc.)? (Y/n)
```
Press Enter (default yes) → verify
`.agents/skills/speakeasy-context/SKILL.md` and agent-specific symlinks
are created in the output directory, then generation proceeds normally.

### 2. Decline skill install
Run quickstart again in a fresh directory, select "no" at the prompt →
verify no `.agents/` directory is created and generation proceeds
normally.

### 3. Already-installed (idempotent)
Run quickstart in a directory that already has
`.agents/skills/speakeasy-context/` → the prompt should be **skipped
entirely**.

### 4. Non-interactive mode
```bash
go build -o speakeasy . && ./speakeasy quickstart --skip-compile --target typescript --schema https://petstore3.swagger.io/api/v3/openapi.json --out-dir /tmp/test-sdk --name TestSDK --package-name test-sdk
```
No skill install prompt should appear.

## Test plan

- [x] Interactive quickstart → accept → skill files and symlinks created
before generation runs
- [x] Interactive quickstart → decline → no files created, generation
proceeds
- [x] Re-run in same dir → prompt skipped (already installed)
- [x] Non-interactive mode → no prompt appears
- [x] `go build ./...` passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- devin-review-badge-begin -->

---

<a href="https://app.devin.ai/review/speakeasy-api/speakeasy/pull/1888"
target="_blank">
  <picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open with Devin">
  </picture>
</a>
<!-- devin-review-badge-end -->

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

4 participants