feat: update Bob integration to skills-based layout for Bob 2.0#3415
feat: update Bob integration to skills-based layout for Bob 2.0#3415davidebibm wants to merge 20 commits into
Conversation
Bob 2.0 replaces the command-based workflow (.bob/commands/*.md) with a skills-based layout (.bob/skills/speckit-<name>/SKILL.md), matching the pattern used by Claude Code, Codex, and other skills-first agents. - Switch BobIntegration from MarkdownIntegration to SkillsIntegration - Update folder/dir from .bob/commands to .bob/skills - Change extension from .md to /SKILL.md (skills layout) - Add --skills option (default: True) consistent with Codex pattern - Update tests to inherit from SkillsIntegrationTests (28 tests pass) - Bump catalog entry to version 2.0.0 with updated description Assisted-by: IBM Bob (model: claude-sonnet-4-5, autonomous)
|
@mnriem please review, we need to make this work with new Bob... Thankyou so much |
There was a problem hiding this comment.
Pull request overview
This PR updates the built-in IBM Bob integration to align with Bob 2.0’s skills-based layout, switching installation output from command files to speckit-<name>/SKILL.md skills directories and bumping the integration’s catalog version accordingly.
Changes:
- Migrate
BobIntegrationfromMarkdownIntegrationtoSkillsIntegrationand update output paths to.bob/skills/.../SKILL.md. - Update Bob integration tests to use the shared
SkillsIntegrationTestsmixin. - Bump the Bob entry in
integrations/catalog.jsonto2.0.0with an updated description.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/integrations/bob/__init__.py |
Switch Bob to SkillsIntegration and update registrar/config output to .bob/skills + /SKILL.md. |
tests/integrations/test_integration_bob.py |
Update base test mixin and expected output directories for the skills layout. |
integrations/catalog.json |
Bump Bob integration version/description to reflect the 2.0.0 skills-based update. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Low
mnriem
left a comment
There was a problem hiding this comment.
As this fundamentally changes the layout for any Bob users what is the migration strategy? This will break them once they adopt a new version of Spec Kit so you need to make sure this goes through a deprecation cycle so they can migrate to the new Bob version. E.g make it an opt-in to the new version of Bob first and then in 2 minor releases (X.Y.Z where Y is minor) you can then remove the non-skill variant
Hi @mnriem |
|
Thanks @davidebibm — but I think we're talking about two different layers, and this still needs to change before it can land. Your point is about Bob the tool — that Bob 1.x can already read the skills layout. My concern is about Spec Kit's generated output: this PR changes what A hard cutover isn't acceptable here — we shouldn't catch existing users off guard. This needs to go through a proper deprecation cycle:
As it stands the Can you rework it along those lines — genuine dual-mode with skills opt-in first — so we phase this in without breaking anyone? |
|
Ok, thankyou @mnriem i'll do that |
|
@mnriem Done, hope this is what you are expecting |
|
Please address Copilot feedback. You will need to update the description to reflect the reality |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@mnriem Addressed Copilot comments and aligned with main |
|
Please address Copilot feedback and resolve conflicts |
…te legacy commands to opt-in
6b3a18c to
674a8db
Compare
…to ALWAYS_SLASH_AGENTS - init.py: suppress ai_skills=True when --legacy-commands is passed so extensions and presets target .bob/commands, not .bob/skills - _invocation_style.py: add 'bob' to ALWAYS_SLASH_AGENTS so init next-steps and hook invocations always show /speckit-<name> (skills is the default layout; no ai_skills flag required)
|
@mnriem Solved Copilot fb and rebased to avoid get Copilot feedback on other devs code 👍 |
mnriem
left a comment
There was a problem hiding this comment.
Address Copilot feedback. If not applicable, please explain why
|
@mnriem Applied Copilot suggestion |
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback. Note we want to make sure we deliver the correct guidance here so please bear with me on these reviews. Thanks so much!
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback. If not applicable, please explain why
|
@mnriem Applied Copilot suggestion |
| registrar_config = { | ||
| "dir": ".bob/commands", | ||
| "format": "markdown", | ||
| "args": "$ARGUMENTS", | ||
| "extension": ".md", | ||
| } |
There was a problem hiding this comment.
@mnriem Hahhahah oh my gosh, that is the line i have removed to address the previous comment of Copilot.
What it will do if i accept this suggestion? i'll get same comment i've got before :-)
Please do a human check on this.
|
Please address Copilot feedback. If not applicable, please explain why |
|
@mnriem Explained in the comment why do this is will be stupid and useless |
…-ref separators Rework the dual-mode handling introduced for Bob 2.0 so an integration's internal representation never leaks into shared init/install/upgrade code, and fix the legacy command-reference separator surfaced in review. Base-class contract: - Add IntegrationBase.is_skills_mode(parsed_options) — the single hook the shared machinery consults to decide whether to persist ai_skills and render skill invocations. SkillsIntegration returns True; Copilot honors --skills / self._skills_mode; Bob returns `not legacy_commands`. - Add IntegrationBase.invoke_separator_for_mode(skills_enabled) — resolves the command-ref separator from a project's persisted mode for registration paths that only have the ai_skills flag (no CLI parsed_options). Default is behavior-preserving; Bob maps skills->"-", legacy->".". - BobIntegration stays on IntegrationBase (mirroring Copilot, the other dual-mode agent) and delegates setup() to internal _BobSkillsHelper / _BobMarkdownHelper. Removes the _skills_mode method and all isinstance(SkillsIntegration) / callable(_skills_mode) probing from _helpers.py and init.py. Fix legacy separator (review feedback): CommandRegistrar.register_commands and PresetManager._resolve_skill_command_refs previously read the single static AGENT_CONFIGS[key]["invoke_separator"], so legacy .bob/commands/ extension and preset command refs rendered /speckit-<cmd> instead of Bob 1.x /speckit.<cmd>. Both now resolve the separator per project mode via invoke_separator_for_mode. Tests: add regression coverage for the is_skills_mode / invoke_separator_for_mode hooks and legacy extension command-ref separators; normalize a width-sensitive workflow assertion to match its siblings. Full suite green. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 63f93544-a77f-4f01-bf04-c88806a97dbf
|
@davidebibm I hope you do not mind me taking it over. I realized there is some additional work that needs to be done to do this cleanly. Stay tuned! |
1d792d9 to
5a8cb61
Compare
|
Pushed a revision to this branch (force-update of my own earlier commit, tip now What changed since the previous push:
Testing: full suite green both on the branch tip (4494 passed, 5 skipped) and merged with current Posted on behalf of @mnriem by GitHub Copilot (model: Claude Opus 4.8), acting autonomously. |
| def is_skills_mode(self, parsed_options: dict[str, Any] | None = None) -> bool: | ||
| """Bob is skills-first; ``--legacy-commands`` opts out.""" | ||
| return not (parsed_options or {}).get("legacy_commands", False) |
| def is_skills_mode(self, parsed_options: dict[str, Any] | None = None) -> bool: | ||
| """Copilot is skills mode when ``--skills`` was requested. | ||
|
|
||
| On the init path ``setup()`` has already recorded the choice in | ||
| ``self._skills_mode``; on the ``use``/``install`` path (where no | ||
| ``setup()`` runs) the signal comes from *parsed_options* (#3550). | ||
| """ | ||
| if parsed_options and parsed_options.get("skills"): | ||
| return True | ||
| return self._skills_mode |
| get the correct separator despite sharing one static ``AGENT_CONFIGS`` | ||
| entry. | ||
| """ | ||
| return "-" if skills_enabled else "." |
Bob 2.0 replaces the command-based workflow with a skills-based layout.
https://bob.ibm.com/blog/bob-v2-release-announcement
Description
Testing
uv run specify --helpuv sync && uv run pytestAI Disclosure
Very simple code generated by Bob but verified by me