Skip to content

feat(tui): Add /skill lifecycle commands for installed AgentSkills#680

Open
sjathin wants to merge 1 commit intoOpenHands:mainfrom
sjathin:open-hands-cli-582
Open

feat(tui): Add /skill lifecycle commands for installed AgentSkills#680
sjathin wants to merge 1 commit intoOpenHands:mainfrom
sjathin:open-hands-cli-582

Conversation

@sjathin
Copy link
Copy Markdown
Contributor

@sjathin sjathin commented Apr 19, 2026

  • A human has tested these changes.

Why

The CLI exposes /skills for viewing loaded resources but has no command surface for managing installed AgentSkills. The SDK now has a public lifecycle API (install_skill, list_installed_skills, enable_skill, disable_skill, uninstall_skill, update_skill)
that the CLI should expose.

Summary

  • Add /skill command family with install, list, enable, disable, uninstall, and update subcommands wrapping the SDK's openhands.sdk.skills API
  • Add prefix-matching in command validation so /skill install foo is recognized as a valid command, and argument parsing in InputField._parse_command()
  • Bump openhands-sdk and openhands-tools from 1.17.0 to 1.18.1 to fix the end-to-end path where installed skills were not loaded by load_user_skills() (fixes software-agent-sdk#2882 ([Bug]: install_skill() installed skills not loaded by load_user_skills() — directory depth mismatch software-agent-sdk#2882))
  • Add 40 tests: unit tests (mocked success/error/not-found for all subcommands), command validation, argument parsing, a full lifecycle integration test, and a regression test verifying load_user_skills() sees installed skills

Issue Number

Closes #582 (#582)

How to Test

  1. Launch the TUI: uv run openhands
  2. Type /skill and press Enter → should show help with all subcommands
  3. Create a test skill:
 mkdir -p /tmp/pirate-mode
 cat > /tmp/pirate-mode/SKILL.md << 'EOF'
 ---
 name: pirate-mode
 description: Forces the agent to respond like a pirate
 ---
 # Pirate Mode Skill
 You MUST respond in pirate speak. Start every response with "Ahoy, matey!" and end with "Arrr!".
 EOF
  1. In the TUI:
    - /skill install /tmp/pirate-mode → "Installed skill 'pirate-mode'"
    - /skill list → shows "✓ enabled pirate-mode"
    - /skill disable pirate-mode → "Disabled skill 'pirate-mode'"
    - /skill list → shows "✗ disabled pirate-mode"
    - /skill enable pirate-mode → "Enabled skill 'pirate-mode'"
    - /skill uninstall pirate-mode → "Uninstalled skill 'pirate-mode'"
    - /skill list → "No installed skills"

Video/Screenshots

Manual TUI testing performed with a local pirate-mode test skill:

Screenshot 2026-04-19 at 14 52 58 Screenshot 2026-04-19 at 14 53 12

Verification

make lint # passes
make test # 1068 passed (1 pre-existing failure unrelated to this PR)
uv run pytest tests/tui/core/test_skill_commands.py -v # 40/40 passed

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

@enyst
Copy link
Copy Markdown
Collaborator

enyst commented Apr 22, 2026

Thank you! Lets see what my agent thinks too

@OpenHands Do a /codereview /codereview-roasted on this PR. Post your feedback as a review with gh api and event.

@openhands-ai
Copy link
Copy Markdown

openhands-ai Bot commented Apr 22, 2026

I'm on it! enyst can track my progress at all-hands.dev

Copy link
Copy Markdown
Collaborator

@enyst enyst left a comment

Choose a reason for hiding this comment

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

🔴 Needs improvement

[CRITICAL ISSUES]

  • [openhands_cli/tui/core/skill_commands.py] Breaking user expectation: with the SDK version currently locked in this repo, install_skill() writes to ~/.openhands/skills/installed/<name> but load_user_skills() still does not load from there. I reproduced this in a temp HOME: after install, list_installed_skills() returned [("pirate-mode", True)] while load_user_skills() returned []. That means /skill install succeeds on paper but the installed skill never becomes active, and the new success text (Restart your session to load/apply) is false today.

[TESTING GAPS]

  • [tests/tui/core/test_skill_commands.py] Real code path not covered: the integration test only checks the installed-skill metadata APIs with a custom installed_dir; it never exercises load_user_skills() or the CLI's actual loaded-resource path, so it misses the regression above.

[RISK ASSESSMENT]

  • [Overall PR] ⚠️ Risk Assessment: 🟡 MEDIUM
    This is a small, localized TUI change, but it exposes a new user-facing command family whose success path currently does not produce a usable installed skill with the SDK version under test. That is a behavior-risk issue, not just a test gap.

VERDICT:
Needs rework: either pair this with the SDK loader fix / version bump, or make the CLI explicitly detect and warn about the current incompatibility instead of claiming restart will apply the skill.

KEY INSIGHT:
The command surface is fine; the broken piece is the end-to-end data path — installed skills are written to one place and loaded from another.

This review was generated by an AI assistant (OpenHands) on behalf of the user.

Comment thread openhands_cli/tui/core/skill_commands.py
Comment thread tests/tui/core/test_skill_commands.py
@openhands-ai
Copy link
Copy Markdown

openhands-ai Bot commented Apr 22, 2026

Done — I completed the requested PR review workflow.

Conciseness check:

  • No code changes were made.
  • No extraneous repository modifications were introduced.
  • The work was limited to analysis, local reproduction, and posting the requested review.

Net result:

  • The user’s request was fully addressed.
  • The review was submitted as CHANGES_REQUESTED because the feature currently has a real user-visible gap with the SDK version under test, and the existing integration test does not catch it.

@sjathin sjathin force-pushed the open-hands-cli-582 branch from 5cf64dc to ccbdba6 Compare April 26, 2026 18:47
@sjathin
Copy link
Copy Markdown
Contributor Author

sjathin commented Apr 26, 2026

@enyst

Thanks for the comments. I have addressed the following:

  1. Bumped openhands-sdk and openhands-tools to v1.18.1 which includes the loader fix (software-agent-sdk#2884). load_user_skills() now calls load_installed_skills() internally, so the end-to-end path works.
  2. Added a regression test (test_load_user_skills_sees_installed_skill) that installs a skill to a temp dir, mocks USER_SKILLS_DIRS and DEFAULT_INSTALLED_SKILLS_DIR, then asserts load_user_skills() returns the installed skill.

@sjathin sjathin requested a review from enyst April 26, 2026 18:55
@sjathin sjathin force-pushed the open-hands-cli-582 branch 2 times, most recently from c2c6139 to dd6a13f Compare April 26, 2026 18:58
@cbagwell
Copy link
Copy Markdown
Contributor

If you merge in main/rebase on top of main, it will now get even newer SDK v1.19.0.

Add /skill command family with install, list, enable, disable,
uninstall, and update subcommands wrapping the SDK's skills API.
Add prefix-matching in command validation and argument parsing in
InputField._parse_command().

Bump openhands-sdk and openhands-tools from 1.17.0 to 1.18.1 to fix
the end-to-end path where installed skills were not loaded by
load_user_skills().

Add 40 tests: unit tests for all subcommands, command validation,
argument parsing, a full lifecycle integration test, and a regression
test verifying load_user_skills() sees installed skills.

Closes OpenHands#582
@sjathin sjathin force-pushed the open-hands-cli-582 branch from dd6a13f to 598f27d Compare April 30, 2026 22:36
@sjathin
Copy link
Copy Markdown
Contributor Author

sjathin commented Apr 30, 2026

@cbagwell @enyst - Thanks for letting me know. Updated the PR.

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.

[CLI] Feature Request: Support /skill lifecycle commands for installed AgentSkills

3 participants