Skip to content

Comments

feat(cli): Support multiple skill names in dotagents add#34

Merged
gricha merged 5 commits intomainfrom
feat/multi-skill-add
Feb 23, 2026
Merged

feat(cli): Support multiple skill names in dotagents add#34
gricha merged 5 commits intomainfrom
feat/multi-skill-add

Conversation

@gricha
Copy link
Member

@gricha gricha commented Feb 23, 2026

Allow users to specify multiple skills in a single dotagents add command
instead of running the command once per skill or going through the interactive
picker:

dotagents add getsentry/skills foo bar baz             # positional args
dotagents add getsentry/skills --skill foo --skill bar  # repeated flags

Both --skill and --name flags now accept multiple: true in parseArgs.
Positional skill names (args after the specifier) are also collected. Mixing
the two styles is rejected as ambiguous.

When multiple names are provided, runAdd validates every name exists in the
source repo before writing anything to agents.toml, so the command fails
fast without partial modifications. The repo is cloned/cached once and
install() runs once at the end.

Includes 12 integration tests covering single/multi name add, fail-fast
behavior, duplicate detection, --all conflict, auto-select for single-skill
repos, non-interactive multi-skill error, and CLI arg parsing (positional,
flags, mixed).

Agent transcript: https://claudescope.sentry.dev/share/19ET9OTfeJa25YBYiHPQ_LbdgfE7hYZY19AB0NkWm4M

Allow users to specify multiple skills in a single command via
positional args or repeated flags:

  dotagents add getsentry/skills foo bar baz
  dotagents add getsentry/skills --skill foo --skill bar

All names are validated before any are added, so the command fails
fast without partially modifying agents.toml. Mixing positional and
flag styles is rejected as ambiguous.

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

Agent transcript: https://claudescope.sentry.dev/share/MXM32cSDqKcIy1BXuoyD2rugHb-9BSGjQK9dFkbZVEE
@vercel
Copy link

vercel bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dotagents Ready Ready Preview, Comment Feb 23, 2026 11:18pm

Request Review

@gricha gricha marked this pull request as ready for review February 23, 2026 22:58
Separate the duplicate-check loop from the write loop so that adding
["review", "pdf"] when "pdf" already exists throws before "review" is
written. Strengthens the no-partial-writes test to verify this.

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

Agent transcript: https://claudescope.sentry.dev/share/eUGVONR7uFczu2YTLpOCf6BB_R8NjPTYXv3d9fdKVIU
…names

Local sources (`path:...`) silently dropped all but the first skill name
when multiple were specified. Now handles multiple names with the same
fail-fast pattern used by git sources.

Also validates user-provided skill names against VALID_SKILL_NAME regex
before filesystem operations to prevent path traversal.

Agent transcript: https://claudescope.sentry.dev/share/a9EaNPenz3RIDwLtbF9twJfshWmM91QsVqXmClvs2_o
const found = await discoverSkill(cached.repoDir, nameOverride);
if (!found) {
throw new AddError(
`Skill "${nameOverride}" not found in ${sourceForStorage}. ` +
Copy link

Choose a reason for hiding this comment

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

Local add mis-handles named skill paths

Medium Severity

For local sources with names provided, the code verifies existence via discoverSkill(localDir, name). If the specifier already points at a specific skill directory (common for local adds), localDir is the skill dir and discoverSkill may look for a nested skill and fail, rejecting valid inputs.

Fix in Cursor Fix in Web

const { join: pathJoin } = await import("node:path");
const meta = await loadSkillMd(pathJoin(localDir, "SKILL.md"));
skillName = meta.name;
}
Copy link

Choose a reason for hiding this comment

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

Local sources lack multi-skill selection flow

Medium Severity

When parsed.type === "local" and no names are provided, the implementation always reads SKILL.md from localDir and never runs the “discover all skills and pick/error” flow used for git sources. Local directories that contain multiple skills now have no way to auto-select/prompt/error consistently.

Fix in Cursor Fix in Web

Covers single skill, multiple skills, not-found, fail-fast, and
no-partial-writes scenarios for path: sources.

Agent transcript: https://claudescope.sentry.dev/share/YwI-sFYZtk86f7RWMZ6uRD9EHB0KnT0fDf3c4NDbfOU
@gricha gricha merged commit 3d9622f into main Feb 23, 2026
16 checks passed
@gricha gricha deleted the feat/multi-skill-add branch February 23, 2026 23:21
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

}
await runInstall({ scope });
return namesOverride;
}
Copy link

Choose a reason for hiding this comment

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

Multi-name write logic duplicated across source types

Low Severity

The multi-name duplicate-check-then-write block (iterate namesOverride to check config duplicates, iterate again to call addSkillToConfig, call runInstall, return) is copy-pasted identically between the local-source branch and the git-source branch. If the write/validation logic ever needs a fix (e.g., adjusting the duplicate check or adding ref handling), it would need to be applied in both places independently, risking divergence.

Additional Locations (1)

Fix in Cursor Fix in Web

// --all: add a wildcard entry
if (all) {
if (nameOverride) {
if (namesOverride?.length) {
Copy link

Choose a reason for hiding this comment

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

Error message references only --name despite broader triggers

Low Severity

The --all conflict error message still says "Cannot use --all with --name" but namesOverride is now populated from positional args and --skill flags too, not just --name. A user running dotagents add source foo --all (positional) gets told they used --name, which they didn't. The message at line 254 was already updated to mention all input methods, but this one was missed.

Additional Locations (1)

Fix in Cursor Fix in Web

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