Skip to content

feat(cli): support skill activation via /skill-name in non-interactive mode - #29546

Open
Hariharanpugazh wants to merge 2 commits into
google-gemini:mainfrom
Hariharanpugazh:feat/skill-activation-non-interactive
Open

Hariharanpugazh wants to merge 2 commits into
google-gemini:mainfrom
Hariharanpugazh:feat/skill-activation-non-interactive

Conversation

@Hariharanpugazh

Copy link
Copy Markdown

Registers SkillCommandLoader in the non-interactive slash command path and handles the tool action result so that typing /skill-name activates a skill outside the interactive UI. Previously the loader was not registered (command was unknown) and the tool result type was unhandled (threw FatalInputError).

Also adds a [Skill] suffix tag to skill-backed slash commands in the autocomplete suggestion menu, mirroring the existing [MCP] and [Agent] tags.

Adds unit tests for the non-interactive handler and the [Skill] tag rendering.

Refs #21165

Summary

Skills already appear in the / completion menu and can be activated via /skill-name in the interactive UI (via SkillCommandLoader and the activate_skill tool). This PR closes two remaining gaps:

  1. Non-interactive skill activation. In nonInteractiveCliCommands.ts, SkillCommandLoader was not registered, so /skill-name was treated as unknown text. Even if it had been registered, the result handler only understood submit_prompt and confirm_shell_commands — a skill command returns type: 'tool', which fell through to the default case and threw FatalInputError.
  2. Visual distinction. Skill commands had no tag in the autocomplete menu, unlike [MCP] and [Agent].

Details

  • packages/cli/src/nonInteractiveCliCommands.ts
    • Register SkillCommandLoader alongside the Builtin, MCP, and File loaders.
    • Handle case 'tool': forward the command's postSubmitPrompt to the model (which then invokes activate_skill). Returns undefined when no prompt is present, so nothing is sent.
  • packages/cli/src/ui/components/SuggestionsDisplay.tsx
    • Add [CommandKind.SKILL]: ' [Skill]' to COMMAND_KIND_SUFFIX.
  • Tests
    • packages/cli/src/nonInteractiveCliCommands.test.ts (new): covers submit_prompt, tool/skill activation, tool-without-prompt, and confirm_shell_commands.
    • packages/cli/src/ui/components/SuggestionsDisplay.test.tsx: new test asserting the [Skill] tag renders, plus snapshot.

Related Issues

Refs #21165

How to Validate

  • npm run test --workspace @google/gemini-cli — the affected suites pass (non-interactive handler, SuggestionsDisplay, SkillCommandLoader).
  • npm run typecheck --workspace @google/gemini-cli — clean.
  • npm run lint --workspace @google/gemini-cli — clean.
  • Manual: with a skill installed, run node packages/cli/dist/index.js -p "/your-skill-name" and confirm the skill activates instead of the command being echoed as plain text.

…e mode

Registers SkillCommandLoader in the non-interactive slash command path and handles the 'tool' action result so that typing /skill-name activates a skill outside the interactive UI. Previously the loader was not registered (command was unknown) and the tool result type was unhandled (threw FatalInputError).

Also adds a [Skill] suffix tag to skill-backed slash commands in the autocomplete suggestion menu, mirroring the existing [MCP] and [Agent] tags.

Adds unit tests for the non-interactive handler and the [Skill] tag rendering.

Refs google-gemini#21165
@Hariharanpugazh
Hariharanpugazh requested a review from a team as a code owner September 29, 2026 02:32
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 enables skill activation in non-interactive CLI sessions by registering the necessary command loader and correctly processing tool-based command results. Additionally, it improves the user experience by adding a visual tag to skill commands in the autocomplete menu, ensuring consistency across different command types.

Highlights

  • Non-interactive Skill Activation: Registered the SkillCommandLoader in the non-interactive CLI path and added handling for 'tool' action results to enable skill activation via '/skill-name' outside the interactive UI.
  • UI Improvements: Added a '[Skill]' suffix tag to skill-backed commands in the autocomplete suggestion menu for better visual consistency with existing [MCP] and [Agent] tags.
  • Testing: Introduced comprehensive unit tests for the non-interactive command handler and verified the new UI tag rendering with snapshot tests.
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 the 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 counterproductive. 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.

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. ↩

@github-actions github-actions Bot added the size/m A medium sized PR label Sep 29, 2026
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

📊 PR Size: size/M

  • Lines changed: 207
  • Additions: +207
  • Deletions: -0
  • Files changed: 5

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

Copy link
Copy Markdown
Contributor

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 integrates SkillCommandLoader into the non-interactive CLI command handler and adds support for displaying [Skill] tags in suggestions. It also implements handling for tool action types in non-interactive mode by forwarding the postSubmitPrompt to the model. The review feedback suggests throwing a FatalInputError instead of silently returning undefined when a tool action lacks a postSubmitPrompt in non-interactive mode, and updating the corresponding unit test to assert this behavior.

Comment on lines +95 to +101
case 'tool':
// Commands such as skill activation (`/skill-name`) resolve to a
// tool call. Non-interactive mode cannot schedule a UI tool call,
// so we forward the command's follow-up prompt to the model, which
// then invokes the tool (e.g. `activate_skill`) itself. If no
// follow-up prompt is provided there is nothing to send.
return result.postSubmitPrompt;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

When a command resolves to a tool action in non-interactive mode, it cannot schedule a UI tool call. Therefore, it must rely on a postSubmitPrompt to forward the request to the model. If postSubmitPrompt is missing or undefined, the command cannot be executed and will silently fail (returning undefined).

Following the general rule to handle undefined cases for optional properties and avoid relying on implementation details of specific loaders, we should explicitly throw a FatalInputError if postSubmitPrompt is not provided, consistent with how other unsupported actions are handled in non-interactive mode.

Suggested change
case 'tool':
// Commands such as skill activation (`/skill-name`) resolve to a
// tool call. Non-interactive mode cannot schedule a UI tool call,
// so we forward the command's follow-up prompt to the model, which
// then invokes the tool (e.g. `activate_skill`) itself. If no
// follow-up prompt is provided there is nothing to send.
return result.postSubmitPrompt;
case 'tool':
// Commands such as skill activation (`/skill-name`) resolve to a
// tool call. Non-interactive mode cannot schedule a UI tool call,
// so we forward the command's follow-up prompt to the model, which
// then invokes the tool (e.g. `activate_skill`) itself.
if (!result.postSubmitPrompt) {
throw new FatalInputError(
'Exiting due to a tool action without a follow-up prompt, which is not supported in non-interactive mode.',
);
}
return result.postSubmitPrompt;
References
  1. When consuming an object, if a property is optional in its type definition (interface), callers must handle the undefined case (e.g., by providing a default with ?? or throwing an error). Do not rely on the implementation details of the function that creates the object to always provide a value.

Comment on lines +114 to +135
it('returns undefined for a tool action without a postSubmitPrompt', async () => {
mockCommands([
{
name: 'bare-tool',
description: 'bare',
kind: CommandKind.SKILL,
action: async () => ({
type: 'tool',
toolName: 'activate_skill',
toolArgs: { name: 'bare' },
}),
},
]);

const result = await handleSlashCommand(
'/bare-tool',
abortController,
mockConfig,
mockSettings,
);
expect(result).toBeUndefined();
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Since we are now throwing a FatalInputError when a tool action lacks a postSubmitPrompt in non-interactive mode, we should update this test to assert that it throws the expected error instead of returning undefined.

  it('throws for a tool action without a postSubmitPrompt', async () => {
    mockCommands([
      {
        name: 'bare-tool',
        description: 'bare',
        kind: CommandKind.SKILL,
        action: async () => ({
          type: 'tool',
          toolName: 'activate_skill',
          toolArgs: { name: 'bare' },
        }),
      },
    ]);

    await expect(
      handleSlashCommand(
        '/bare-tool',
        abortController,
        mockConfig,
        mockSettings,
      ),
    ).rejects.toThrow(FatalInputError);
  });

@gemini-cli gemini-cli Bot added priority/p2 Important but can be addressed in a future release. area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels Sep 29, 2026
…ompt

Addresses review feedback on google-gemini#29546: instead of silently returning undefined when a tool action has no postSubmitPrompt in non-interactive mode, throw a FatalInputError so the failure is explicit, consistent with other unsupported non-interactive actions. Updates the corresponding test.
@Hariharanpugazh

Copy link
Copy Markdown
Author

Code Review

This pull request integrates SkillCommandLoader into the non-interactive CLI command handler and adds support for displaying [Skill] tags in suggestions. It also implements handling for tool action types in non-interactive mode by forwarding the postSubmitPrompt to the model. The review feedback suggests throwing a FatalInputError instead of silently returning undefined when a tool action lacks a postSubmitPrompt in non-interactive mode, and updating the corresponding unit test to assert this behavior.

Good call updated to throw FatalInputError when a tool action has no postSubmitPrompt, and adjusted the test to assert it. Pushed in 538458b.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p2 Important but can be addressed in a future release. size/m A medium sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant