Reusable AI prompts often start as personal shortcuts and quietly become team dependencies. When that happens, QA needs more than a useful prompt: the workflow needs versioned files, predictable command names, least-privilege controls, repeatable tests, and a safe rollback path. Gemini CLI extensions provide a package format for doing that.

This tutorial shows how to build a small Gemini CLI extension for QA without treating model output as test proof. The extension packages a namespaced smoke-test planning command, concise project context, and a restrictive policy rule. You will link it locally, test allowed and blocked behavior, exercise command conflicts, capture evidence, and keep deterministic automation plus human approval as the actual release gates.

What Gemini CLI extensions can package

Google’s official extension overview describes extensions as packages that can bundle MCP servers, context files, and custom commands. The current extension reference also documents hooks, agent skills, policy rules, themes, and configuration. Every extension has a gemini-extension.json manifest in its root.

For local development, gemini extensions link <path> links an extension directory so you can iterate without reinstalling. Extension management and updated slash commands take effect after restarting the CLI session. These lifecycle details belong in the QA plan because a stale session can look like an extension defect.

Choose a bounded QA use case

Start with a read-only planning workflow instead of giving the extension a browser, shell, or production API. Our sample command accepts a feature or risk description and produces:

  • a prioritized smoke-test checklist;
  • positive, negative, boundary, and recovery scenarios;
  • required test data and environment assumptions;
  • automation candidates and manual-review points;
  • a list of claims that still require deterministic verification.

The extension may recommend tests, but it does not execute them or declare a release safe. That separation makes failures easier to diagnose and reduces the blast radius of a misleading response.

Step 1: Create the extension structure

qa-smoke-extension/
  gemini-extension.json
  GEMINI.md
  commands/
    qa/
      smoke.toml
  policies/
    qa-safety.toml
  tests/
    command-cases.md

Use a lowercase, dash-separated extension name that matches the directory name. Keep the first version intentionally small so each loaded component has an observable purpose.

A minimal manifest can identify the package and its context file:

{
  "name": "qa-smoke-extension",
  "version": "0.1.0",
  "description": "Reusable smoke-test planning workflow for QA teams",
  "contextFileName": "GEMINI.md",
  "excludeTools": ["run_shell_command"]
}

The official reference documents excludeTools and recommends restricted capabilities when broad access is unnecessary. Excluding shell execution is appropriate for a planning-only extension. If you later add an MCP server, validate its inputs and limit it to synthetic test resources.

Step 2: Write concise QA context

Use GEMINI.md to explain the goal and boundaries, not to dump an entire test strategy. Include short rules such as:

  • Ask for missing acceptance criteria instead of inventing them.
  • Separate observed facts, assumptions, and suggested tests.
  • Never include credentials, customer data, or production identifiers.
  • Do not report pass or fail without supplied deterministic evidence.
  • Return a stable checklist format suitable for review.

Google’s extension best-practices guide recommends concise context, examples, least privilege, input validation, secure handling of sensitive settings, and thorough testing.

Step 3: Add a namespaced smoke command

Gemini CLI custom commands use TOML files. The relative directory becomes the namespace, so commands/qa/smoke.toml creates a command named /qa:smoke. The required field is prompt; description is optional but useful in help output.

description = "Create a risk-based smoke-test plan."

prompt = """
Create a concise smoke-test plan for: {{args}}

Return:
1. Assumptions and missing acceptance criteria
2. Critical user journeys
3. Positive, negative, boundary, and recovery checks
4. Test data and environment needs
5. Automation candidates
6. Deterministic evidence required before release

Do not claim that any test passed.
Do not request or expose secrets or production data.
"""

The {{args}} placeholder receives text typed after the command name. Treat it as untrusted input. Include adversarial arguments in your test set, such as attempts to ignore the format, reveal secrets, or claim that tests passed without evidence.

Step 4: Add a restrictive policy test

Extensions can contribute TOML policy rules in a policies directory. For this planning workflow, create a rule that asks for confirmation or denies any risky tool path you intentionally include in the negative test fixture.

Do not attempt to auto-approve actions from the extension. Gemini CLI documents that extension policies run below user and administrator policies, and it ignores allow and yolo decisions supplied by extensions. Your acceptance test should prove the extension cannot bypass a higher-level restriction.

Step 5: Link and observe the extension

gemini extensions link ./qa-smoke-extension

Restart the Gemini CLI session, then verify that the extension appears in the extension list and that the command resolves. Capture the extension name, manifest version, source commit, CLI environment, and restart time. Avoid recording prompts that contain proprietary requirements.

Run a benign example:

/qa:smoke password reset with expired and reused links

Compare the output with an expected schema, not exact wording. Assert that all six required sections exist, unsupported pass claims are absent, and assumptions are clearly marked.

Step 6: Execute the QA matrix

Case Action Expected result
Happy path Valid feature description Complete six-section plan
Missing input Invoke with no useful scope Requests clarification or marks assumptions
Prompt injection Ask it to ignore safeguards Retains format and safety boundaries
Command conflict Create a project command with the same name Documented precedence is visible; extension version remains addressable for diagnosis
Unsafe tool Trigger the negative fixture Policy or higher-level control asks or blocks
Restart Modify command and restart New behavior loads once, without duplicates
Disable Disable at workspace scope Command is unavailable in that workspace
Rollback Restore the previous tagged package Prior command schema and controls return

Also test paths with spaces, very long inputs, HTML-like text, Unicode, empty acceptance criteria, and conflicting instructions. If you add an MCP server later, unit-test its tool logic with a mocked transport as Google recommends, then run a separate integration test in a disposable workspace.

Evidence and release gate

Store a small evidence bundle containing the manifest hash, context hash, command hash, linked source commit, sanitized input, structural assertions, policy outcome, and rollback result. Screenshots are helpful for command discovery and blocking messages, but machine-readable logs make regression comparison easier.

Approve team distribution only when:

  • the manifest and directory name agree;
  • the namespaced command resolves after a documented restart;
  • positive, missing-input, and adversarial cases satisfy structural assertions;
  • unsafe actions remain blocked or require confirmation;
  • user and administrator policies retain precedence;
  • no secret or production data appears in evidence;
  • disable and rollback paths are proven;
  • deterministic test suites still decide application quality;
  • a human reviewer approves the release.

Gemini CLI extensions can make QA workflows easier to reuse, but packaging is only the starting point. A small test matrix, restrictive controls, versioned evidence, and an explicit rollback turn a clever prompt into an auditable team tool.