Skip to content

feat(skills): implement linking for agent skills#18295

Merged
NTaylorMullen merged 6 commits intogoogle-gemini:mainfrom
MushuEE:skills/skills-linking
Feb 4, 2026
Merged

feat(skills): implement linking for agent skills#18295
NTaylorMullen merged 6 commits intogoogle-gemini:mainfrom
MushuEE:skills/skills-linking

Conversation

@MushuEE
Copy link
Contributor

@MushuEE MushuEE commented Feb 4, 2026

Summary

This PR implements the gemini skills link <path> command (and its interactive /skills link counterpart) to allow users to symlink agent skills from local directories. It also introduces automatic name sanitization to ensure skills with special characters (like :) can be safely managed on all filesystems.

Details

Key implementation details:

  • Name Sanitization: Skill names are now sanitized (e.g., replacing : with -) during discovery. This ensures that skills defined with names like foo:bar can be stored as valid directory/link names (foo-bar) without causing filesystem errors.
  • Conflict Detection: The linkSkill utility detects internal name collisions within the source path to prevent non-deterministic behavior during linking.
  • Atomic Overwrites: Existing directories or links at the destination are safely removed before creating new symlinks.
  • Shared Logic: Centralized the linking logic in skillUtils.ts to be used by both the yargs CLI and the interactive REPL.
  • Documentation: Updated docs/cli/skills.md and docs/cli/cli-reference.md to include the new command.

Related Issues

Fixes #18294

How to Validate

Terminal

  1. Create a directory structure with multiple skills, including one with a colon in the name:
    my-skills/
    ├── skill-a/SKILL.md
    └── foo:bar/SKILL.md (with name: "foo:bar" in frontmatter)
    
  2. Run gemini skills link /path/to/my-skills.
  3. Verify symlinks are created in ~/.gemini/skills/:
    • skill-a -> my-skills/skill-a
    • foo-bar -> my-skills/foo:bar (sanitized)

Interactive

  1. Start gemini.
  2. Run /skills link /path/to/my-skills.
  3. Confirm the consent prompt (verify it shows the sanitized names).
  4. Run /skills list and verify the skills appear correctly.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@MushuEE MushuEE requested review from a team as code owners February 4, 2026 06:42
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @MushuEE, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the agent skill management capabilities by introducing a new 'link' feature. This allows developers to easily integrate locally developed agent skills into the Gemini CLI and interactive environment using symbolic links. The change focuses on improving the developer workflow by enabling direct iteration on skills without requiring repeated installation steps, while also incorporating necessary safety checks and clear user consent for linking external code.

Highlights

  • New gemini skills link Command: Introduced a new CLI command (gemini skills link <path>) and an interactive counterpart (/skills link <path>) to allow users to symlink agent skills from local directories into their Gemini environment. This facilitates local development and testing of skills.
  • Recursive Skill Discovery: The loadSkillsFromDir utility now supports an optional recursive flag, enabling the link command to discover SKILL.md files within nested subdirectories of the specified source path. This behavior is distinct from install, which remains shallow.
  • Robust Linking Logic: The new linkSkill utility includes several safeguards: skill names are sanitized to be safe for file system use (e.g., replacing colons with hyphens), internal name collisions within the source path are detected to prevent non-deterministic behavior, and existing destination directories/links are atomically overwritten to ensure clean updates.
  • Consent and Security: The linking process incorporates a consent mechanism, prompting users to acknowledge security risks before creating symlinks. This can be bypassed in the CLI using a --consent flag for non-interactive use.
  • Documentation Updates: The CLI reference (docs/cli/cli-reference.md) and skills documentation (docs/cli/skills.md) have been updated to reflect the new link command and its usage.
Changelog
  • docs/cli/cli-reference.md
    • Added a new 'Skills management' section to the CLI reference.
    • Included the gemini skills link <path> command with its description and an example.
  • docs/cli/skills.md
    • Added /skills link <path> to the list of interactive slash commands.
    • Included examples for gemini skills link command, demonstrating both user and workspace scope linking.
  • package-lock.json
    • Updated several dependency entries by adding the "peer": true attribute, likely reflecting changes in how these packages are consumed or declared as peer dependencies.
  • packages/cli/src/commands/skills.tsx
    • Imported the new linkCommand.
    • Integrated linkCommand into the main skillsCommand builder, making it available as a subcommand.
  • packages/cli/src/commands/skills/link.test.ts
    • Added a new test file for the gemini skills link CLI command.
    • Included tests for command structure, successful linking, and error handling scenarios.
  • packages/cli/src/commands/skills/link.ts
    • Added a new file implementing the gemini skills link CLI command.
    • Defined LinkArgs interface for command arguments.
    • Implemented handleLink function to manage the linking process, including path resolution, scope handling, and consent interaction.
    • Exported linkCommand as a CommandModule with detailed command, describe, builder, and handler properties.
  • packages/cli/src/config/extensions/consent.ts
    • Modified skillsConsentString function to accept an isLink parameter.
    • Adjusted consent message generation to dynamically use 'Linking' or 'Installing' based on the isLink flag, providing more context to the user.
  • packages/cli/src/ui/commands/skillsCommand.test.ts
    • Added new test cases for the interactive /skills link command.
    • Verified successful skill linking, linking with workspace scope, and error handling for failed links or missing paths.
  • packages/cli/src/ui/commands/skillsCommand.ts
    • Imported linkSkill, requestConsentInteractive, and skillsConsentString.
    • Implemented linkAction function to handle the interactive /skills link command, including argument parsing, UI feedback, and consent flow.
    • Added the link subcommand to the skillsCommand definition for interactive use.
  • packages/cli/src/utils/skillUtils.test.ts
    • Added a new describe block for linkSkill tests.
    • Included tests for successfully linking from a local directory, overwriting existing skills, aborting linking on consent rejection, and detecting duplicate skill names.
  • packages/cli/src/utils/skillUtils.ts
    • Implemented the linkSkill function, which provides the core logic for symlinking local skills.
    • This function handles source path resolution, recursive skill discovery, internal name collision detection, consent requests, creation of target directories, and atomic symlink creation/overwriting.
  • packages/core/src/skills/skillLoader.test.ts
    • Added tests for recursive skill discovery in nested subdirectories.
    • Included tests to ensure skills are NOT recursively discovered by default.
    • Added tests to verify symlinks to directories are followed during recursive discovery.
    • Added tests for sanitizing skill names containing invalid filename characters (e.g., 'gke:prs-troubleshooter' becomes 'gke-prs-troubleshooter').
  • packages/core/src/skills/skillLoader.ts
    • Modified loadSkillsFromDir to accept an optional recursive boolean parameter, defaulting to false.
    • Updated glob pattern to use **/SKILL.md for recursive searches and added follow: recursive and ignore options to skip node_modules and .git directories.
    • Implemented skill name sanitization within loadSkillFromFile to replace invalid filename characters with hyphens.
Ignored Files
  • Ignored by pattern: .gemini/** (2)
    • .gemini/skills/skill1
    • .gemini/skills/skill2
Activity
  • The author has implemented the gemini skills link command for both the CLI and interactive REPL.
  • Documentation for the new command has been updated in docs/cli/cli-reference.md and docs/cli/skills.md.
  • Unit tests have been added for both the CLI command handler (packages/cli/src/commands/skills/link.test.ts) and the interactive command handler (packages/cli/src/ui/commands/skillsCommand.test.ts).
  • Comprehensive unit tests for the core linkSkill utility and skillLoader enhancements have been added/updated.
  • The author has validated the changes on Linux using npm run.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@MushuEE MushuEE force-pushed the skills/skills-linking branch from 34704cc to eefd5d2 Compare February 4, 2026 06:44
- Added support for recursive skill discovery in loadSkillsFromDir.
- Implemented centralized linkSkill utility in skillUtils.
- Added 'skills link' command to yargs CLI.
- Added '/skills link' action to interactive slash commands.
- Implemented skill name sanitization for filesystem safety.
- Added duplicate skill name detection during linking.
- Updated consent messaging to reflect linking vs installing.
- Updated documentation in docs/cli/skills.md and docs/cli/cli-reference.md.
@MushuEE MushuEE force-pushed the skills/skills-linking branch from eefd5d2 to f4ccb4f Compare February 4, 2026 06:46
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature for linking local agent skills, complete with recursive discovery, name sanitization, and documentation.

@gemini-cli gemini-cli bot added the area/core Issues related to User Interface, OS Support, Core Functionality label Feb 4, 2026
@MushuEE
Copy link
Contributor Author

MushuEE commented Feb 4, 2026

Different ways to implement "linking" for agent skills in Gemini CLI, comparing the native symlink approach with alternative "pointer" methods.


1. Native Filesystem Symlinks (Current Implementation)

The CLI creates an OS-level symbolic link in the target skills directory (~/.gemini/skills or .gemini/skills) that points directly to the source directory.

Pros

  • Zero Core Changes: The existing loadSkillsFromDir logic (using glob and fs) works out-of-the-box because Node.js follows symlinks by default.
  • Visual Transparency: Users can use standard OS tools (like ls -l or Finder/Explorer) to immediately see where a skill is linked from.
  • Tool Agnostic: Any future scripts or third-party tools that scan the skills directory will "see" the linked skills as regular folders.

Cons

  • OS Permissions: On Windows, creating symlinks often requires Developer Mode or Administrator privileges, which can be a friction point for some users.

2. Metadata "Pointer" Stubs (Extension Style)

Instead of a symlink, the CLI creates a small metadata file (e.g., my-skill.json or my-skill.link) in the skills directory that contains the absolute path to the source.

Pros

  • Cross-Platform Consistency: Avoids OS-specific symlink restrictions. Creating a small text file is a universal permission.
  • Enhanced Metadata: Allows storing additional link-specific info (like "linked on date" or "original author") without modifying the source SKILL.md.

Cons

  • Loader Complexity: Requires updating the core loadSkillsFromDir logic to detect these stubs and "jump" to the remote source path.
  • Invisible to Standard Tools: A simple directory listing won't show the link; you would need a specialized tool or the Gemini CLI itself to resolve the pointers.

3. Global Config Registry

The paths to linked skills are stored in the user's global config.yaml or a specialized .linked-skills registry file, rather than placing anything in the skills directory.

Pros

  • Extremely Clean: No "ghost" files or links are created in the background storage.
  • Centralized Management: Users can see all their linked sources in one single configuration file.

Cons

  • Split Discovery: The skill loader must now look in two completely different places (the storage folders AND the config file) to find skills.
  • Path Rot: If a directory is moved or deleted, the config file accumulates "dead" paths that need manual cleanup.

Conclusion: Why Symlinks for Phase 1?

The native symlink approach was chosen for the initial implementation because it provides the cleanest integration with the existing codebase. It treats "linked" skills as "first-class citizens" without requiring any logic changes to how the model activates, reads, or validates skill content.

If future telemetry indicates that Windows users are frequently hitting permission errors, the implementation can be migrated to the Metadata Stub approach with minimal changes to the user-facing CLI command.

@MushuEE
Copy link
Contributor Author

MushuEE commented Feb 4, 2026

Spoke off line, the recursive pattern is not broadly supported by other AI interfaces and I will revert that to only keep gemini skills link function in this change.

@MushuEE
Copy link
Contributor Author

MushuEE commented Feb 4, 2026

Also, I do not have access to update the title to remove the "recursive" element now that it is reverted. Please make that change for me if anyone has access.

@MushuEE MushuEE requested a review from iqbalbhatti49 February 4, 2026 18:56
@NTaylorMullen NTaylorMullen changed the title feat(skills): implement recursive linking for agent skills feat(skills): implement linking for agent skills Feb 4, 2026
auto-merge was automatically disabled February 4, 2026 21:30

Head branch was pushed to by a user without write access

@MushuEE
Copy link
Contributor Author

MushuEE commented Feb 4, 2026

  • packages/cli/src/ui/commands/types.ts: Added setConfirmationRequest to the CommandContext['ui'] interface.
  • packages/cli/src/ui/hooks/slashCommandProcessor.ts: Provided the interactive setConfirmationRequest state setter to the UI context.
  • packages/cli/src/ui/noninteractive/nonInteractiveUi.ts: Added a no-op implementation for non-interactive environments.

The project now builds successfully with npm run build --workspaces, and all unit tests are passing.

/retest

@NTaylorMullen NTaylorMullen added this pull request to the merge queue Feb 4, 2026
Merged via the queue into google-gemini:main with commit a3af4a8 Feb 4, 2026
25 of 26 checks passed
sidwan02 pushed a commit to sidwan02/gemini-cli-gemma that referenced this pull request Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: introduce 'skills link' for symlinking agent skills (like extensions link)

3 participants