Skip to content

fix(init): make the universal tool target findable in the picker - #1778

Open
clay-good wants to merge 3 commits into
mainfrom
claude/openspec-issue-triage-pr-5c7c51
Open

fix(init): make the universal tool target findable in the picker#1778
clay-good wants to merge 3 commits into
mainfrom
claude/openspec-issue-triage-pr-5c7c51

Conversation

@clay-good

@clay-good clay-good commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Status

LGTM. Closes #653

What was wrong

openspec init shows a searchable list of tool names. OpenSpec already ships the answer for an assistant that isn't on that list — the vendor-neutral agents target, which writes .agents/skills/openspec-*/SKILL.md and nothing tool-specific. But it was labeled "Shared .agents skills", after the directory it writes to.

Nobody in that position searches for a directory. The reporter — using a proprietary corporate VS Code plugin — typed the words that describe their situation and got back No matches:

They type Old behavior Why
universal No matches the filter reads only name and id
other No matches "
generic No matches "
.agents filters on agents the leading . was silently dropped
amazon-q filters on amazonq the - was silently dropped
claude code selects a random tool space toggles; the rest never arrives

Underneath were two separate defects on the same screen:

  1. The one entry that fits an unlisted tool carried no term a user would search for.
  2. The search box ignored every non-alphanumeric keystroke. Node's readline reports punctuation only in key.sequence and leaves key.name undefined, and the handler keyed off key.name alone — so ., - and / were swallowed with no feedback, and pasted text was dropped whole.

With no way to reach it, the user's only recourse was to file an issue. It sat unanswered for seven months.

What it does

Makes the entry findable

  • Renamed to Other / Universal (shared .agents skills), so it reads as the escape hatch and still says what it writes.
  • Added searchAliases to AIToolOption and to the picker's Choice; the filter matches name, id, or alias. The universal entry answers to universal, other, generic, custom, proprietary, unlisted, unsupported, vendor-neutral, agents.md. Aliases are never rendered — they only widen the search.

Fixes the search box

  • Character input reads key.sequence, falling back to a single-character key.name. Any sequence whose characters are all printable is accepted, which covers punctuation and pasted text — so a space can now reach the box and claude code filters.
  • Escape sequences (arrows, function keys) carry control characters and are rejected by the same rule; ctrl/meta chords return early; the name fallback stays single-character so readline names like 'tab' and 'escape' are never typed as words. The search term is trimmed, so a pasted " claude " still matches.

Closes the dead ends, everywhere the answer was withheld

  • No matches now names the fallback, via a generic emptyHint on the prompt so the component stays tool-agnostic:
  Search: [turingplugin]
  No matches
  Tool not listed? Clear the search and pick "Other / Universal (shared .agents skills)".
  • --tools <unknown> used to print a bare list of 42 ids. It now ends with the scripted counterpart of that hint:
$ openspec init . --tools turing-corp-plugin
✖ Error: Invalid tool(s): turing-corp-plugin. Available values: all, none, amazon-q, …, agents
Tool not listed? Use --tools agents — the vendor-neutral target that writes .agents/skills/ for any assistant.

Same line on the non-interactive "no tools detected" error. Both go through one universalToolFallbackHint() helper that returns nothing when the target isn't among the tools on offer, so the hint never names a choice the caller can't make.

  • openspec update builds its own choices for the legacy-tool picker and never passed aliases through. Now it does.
  • docs-lab taught the old label in two places; both updated, along with docs/supported-tools.md. No stale label remains anywhere in the repo.

Nothing else moves: no new tool, no new directory, no change to what agents installs, and --tools agents is untouched so scripts and CI keep working.

Proof it works

Both original defects fail first. On main, the new prompt tests report:

AssertionError: expected 'amazonq' to be 'amazon-q'
AssertionError: expected 'agents' to be '.agents'

plus the alias cases returning an empty list. All pass here.

Two bugs in my own first pass were caught by writing the tests, and are worth naming since they show the tests aren't decorative:

  • Broadening the name fallback to any printable string would have typed tab and escape into the search box as literal words. The fallback is now single-character, with a test that presses tab, escape, delete and F1 and asserts the box stays empty.
  • The --tools <unknown> hint was first placed in validateTools, on a branch unreachable from the flag. The test failed with the real message (Invalid tool(s): …), and the hint moved to the path users actually hit.

New coverage — 21 tests across three files:

  • test/prompts/searchable-multi-select.test.ts — alias matching (a term the name doesn't spell), prefix and case-insensitive alias matching, aliases never rendered, no false matches, name/id matching unchanged; punctuation, uppercase, paste, multi-word paste, trimmed padding; rejection of ctrl chords, meta chords, named control keys, arrow escape sequences and newline-bearing pastes; the empty-state hint appearing only when nothing matches.
  • test/core/init.test.ts — the picker really receives the aliases and the emptyHint (the wiring, not just the data), and both error paths name --tools agents.
  • test/core/tool-search-aliases.test.ts — the universal entry keeps its aliases and label, every alias everywhere stays single-word and lowercase (space toggles selection, so a multi-word alias would be unreachable), and the fallback hint stays silent when the target isn't offered.

End to end, unchanged output apart from the label:

$ openspec init . --tools agents
- Setting up Other / Universal (shared .agents skills)...
✔ Setup complete for Other / Universal (shared .agents skills)
Created: Other / Universal (shared .agents skills)
6 skills in .agents/

Full suite: 4449 passed, 2 failed. Those 2 (config-profile › "confirmed project apply…", artifact-workflow › "creates skills for Cursor tool") fail identically on a clean checkout of main at e062b95 — verified in a separate baseline worktree, same two names, same count. npm run lint and tsc --noEmit are clean.

Notes / nits

  • Existing expectations updated to the new label in test/core/init.test.ts and test/core/update.test.ts.
  • No spec delta: the picker label isn't normative anywhere. openspec/specs/cli-init/spec.md requires "a searchable multi-select … filtering by typing to search", which still holds, and the add-init-agents-target delta constrains skillsDir and detection only. Three of the last four merged fix PRs shipped no openspec/ files either.
  • One cosmetic wrinkle left alone: the shared-root arbitration message reads managed by another tool (Other / Universal (shared .agents skills)). Nested parens, rare path, and reshaping a message every tool shares belongs in its own change.
  • Unrelated find, not touched: AIToolOption.successLabel is populated for all ~42 tools and read by nothing (grep -rn successLabel src test scripts hits only its own declaration). It looks like it was meant for exactly these setup strings, and wiring it up would also fix the nested parens above. Worth its own PR.
  • Out of scope on purpose: the space bar can't be typed because it toggles selection — deliberate and pinned by tests — so multi-word search works by paste, not by typing. I also left every other tool's aliases empty rather than guessing vendor synonyms.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Updated the openspec init tool picker to display the vendor-neutral option as “Other / Universal (shared .agents skills).”
    • Expanded search matching with aliases for vendor-neutral and unlisted tools.
    • Added guidance when searches return no matches and when tool selection fails.
    • Search now supports punctuation, pasted text, whitespace trimming, and terms such as ., -, and /.
  • Documentation

    • Updated supported-tool guides and FAQs with the revised target name and search terms.
  • Bug Fixes

    • Improved tool-picker search input handling, including punctuation retention and control-key behavior.

Closes #653

`openspec init`'s tool picker is a searchable list of product names. The
vendor-neutral target every unlisted assistant is meant to use was named
"Shared .agents skills" — after the directory it writes, which is not a
word anyone in that position searches for. Typing "universal", "other" or
"generic" returned "No matches", so the escape hatch was unreachable and
the reporter had to open an issue to find it.

Rename the entry to "Other / Universal (shared .agents skills)" and give
choices optional `searchAliases` the filter also matches. The picker also
dropped every non-alphanumeric keystroke: readline reports punctuation
only in `key.sequence`, leaving `key.name` undefined, so ".agents" and
"amazon-q" could not be typed at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@clay-good
clay-good requested a review from a team as a code owner September 3, 2026 20:07
@clay-good
clay-good requested review from alfred-openspec and removed request for a team September 3, 2026 20:07
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying openspec-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: d36b78c
Status: ✅  Deploy successful!
Preview URL: https://76644796.openspec-docs.pages.dev
Branch Preview URL: https://claude-openspec-issue-triage-rste.openspec-docs.pages.dev

View logs

@coderabbitai

coderabbitai Bot commented Sep 3, 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 0bb1e68c-dc02-4420-8c51-51d2dd556f1a

📥 Commits

Reviewing files that changed from the base of the PR and between 30ccdb8 and fb777b9.

📒 Files selected for processing (10)
  • .changeset/universal-tool-picker-entry.md
  • docs-lab/help/faq.md
  • docs-lab/reference/supported-tools.md
  • src/core/config.ts
  • src/core/init.ts
  • src/core/update.ts
  • src/prompts/searchable-multi-select.ts
  • test/core/init.test.ts
  • test/core/tool-search-aliases.test.ts
  • test/prompts/searchable-multi-select.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/universal-tool-picker-entry.md

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The universal .agents target is renamed “Other / Universal.” The tool picker now supports aliases, no-match guidance, punctuation input, pasted text, and fallback error hints. Tests and documentation reflect the updated behavior.

Changes

Universal tool picker

Layer / File(s) Summary
Tool configuration and picker wiring
src/core/config.ts, src/core/init.ts, src/core/update.ts
The universal tool entry uses the “Other / Universal” label and search aliases. Init and update pass aliases to the picker. Init adds --tools agents guidance to applicable errors and empty-search results.
Alias filtering and punctuation input
src/prompts/searchable-multi-select.ts, test/prompts/searchable-multi-select.test.ts
Search matches trimmed names, values, and aliases. Printable punctuation and pasted text are accepted. Control input is ignored. No-match guidance is rendered when configured.
Labels, documentation, and regression coverage
docs/supported-tools.md, docs-lab/help/faq.md, docs-lab/reference/supported-tools.md, .changeset/universal-tool-picker-entry.md, test/core/*
Documentation and release notes describe the universal target and search terms. Tests cover aliases, fallback hints, picker behavior, and updated labels.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to fb777

The picker, alias, input-handling, guidance, test, and documentation changes are consistent and appear ready to merge.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant InitCommand
  participant searchableMultiSelect
  User->>InitCommand: Open tool selection
  InitCommand->>searchableMultiSelect: Provide choices with aliases and emptyHint
  User->>searchableMultiSelect: Enter alias, punctuation, or pasted text
  searchableMultiSelect-->>User: Display matching tools or universal-tool guidance
Loading

Suggested reviewers: tabishb

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 8 files. (3 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #653 by restoring a discoverable universal option for unlisted and proprietary assistants, adding searchable terms such as "universal," "other," and "generic," and documentin…
Out of Scope Changes check ✅ Passed The changes remain within scope. The picker input handling, update-picker alias support, unknown-tool guidance, tests, and documentation directly support the universal tool discovery objective and rel…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: making the universal tool target searchable in the initialization picker.
Full details: Linked Issues check

Explanation

The changes satisfy issue #653 by restoring a discoverable universal option for unlisted and proprietary assistants, adding searchable terms such as "universal," "other," and "generic," and documenting the selection and fallback behavior.

Full details: Out of Scope Changes check

Explanation

The changes remain within scope. The picker input handling, update-picker alias support, unknown-tool guidance, tests, and documentation directly support the universal tool discovery objective and related hardening described in the pull request.

Full details: Docstring Coverage

Explanation

Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 8 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/openspec-issue-triage-pr-5c7c51

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.

…othing

"No matches" is where someone whose assistant is not on the list gives
up — the picker knows the answer and does not say it. Add an optional
`emptyHint` to the searchable multi-select, and have init name the
vendor-neutral entry there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@openspec-cloud

openspec-cloud Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

No PR-relevant drift confirmed.

AI-generated · A citation proves the line exists, not that it makes the case — verify before acting.
No issue was confirmed at d36b78c; 2 requirements could not be verified.
This is not a full-repository clean result; see the check for coverage and any broader findings.
View results · Click Refresh, then Scan again in the check. Or comment /openspec-cloud.

Hardening pass over the same defect. Reviewing the first fix turned up
four more places the answer was withheld:

- `openspec update`'s tool picker builds its own choices and never
  passed searchAliases through, so the same search failed there.
- `--tools <unknown>` printed a bare list of ids. It now names the
  fallback, the scripted counterpart of the picker's empty hint. The
  hint I first put on validateTools sat on an unreachable branch; the
  path users actually hit is the "Invalid tool(s)" parse error, and a
  test now pins it.
- The search box dropped pasted text as well as punctuation. Any
  sequence whose characters are all printable is now accepted, which
  also lets a space reach the box so "claude code" filters. Escape
  sequences carry control characters and are still rejected, and the
  `name` fallback stays single-character so readline names like 'tab'
  are never typed.
- docs-lab still taught the old label in two places.

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

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The implementation and test coverage look sound, and CI is green. Please tighten the docs-lab changes before merge: help/faq.md is explicitly a one-line/router surface, but this answer now duplicates the seven-alias how-to detail already owned by reference/supported-tools.md. Keep the detailed search aliases on the supported-tools page and make the FAQ answer a short pointer to that canonical section. Also remove the em dash added to the FAQ; docs-lab/.agents/skills/write-openspec-docs/writing.md forbids em dashes. Since docs-lab changed, final approval from @TabishB is still required by the repository review policy.

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.

[v1.1.1] Missing "Universal / Other tools" option in init: How to configure for custom/proprietary AI plugins?

2 participants