feat(gemini): add Gemini CLI as supported target with integration tests#917
feat(gemini): add Gemini CLI as supported target with integration tests#917danielmeppiel merged 11 commits intomicrosoft:mainfrom
Conversation
|
@microsoft-github-policy-service agree company="Red Hat" |
|
@danielmeppiel @sergio-sisternes-epam Hey folks, this is a great project. <3 One barrier for me currently is the lack of Gemini CLI support. Because it's a significant addition and I see several other active PRs that might conflict, I wanted to check in first if this a feature you’re interested in? If so, I’m happy to manage the rebasing and keep it up-to-date against the main branch so it’s an easy lift when you get to it. I just didn't want to spin my wheels if you won't have time to get to this. |
|
Let's get Gemini CLI supported! |
APM Review Panel VerdictDisposition: REQUEST_CHANGES (four mechanical pre-merge fixes; architecture is approved) Per-persona findingsPython Architect: The PR is a clean, additive extension of the data-driven Class diagram (integration subsystem, touched classes in bold): classDiagram
direction TB
class CopilotClientAdapter {
+get_config_path() str
+update_config(updates)
+configure_mcp_server(url, name, ...) bool
+_format_server_config(info, env, vars) dict
}
class GeminiClientAdapter {
<<ConcreteStrategy>>
+supports_user_scope bool
+get_config_path() str
+update_config(updates)
+get_current_config() dict
+configure_mcp_server(url, name, ...) bool
}
note for GeminiClientAdapter "Reuses mcpServers schema;\nopt-in: writes only if .gemini/ exists"
class ClientFactory {
<<StaticFactory>>
+create_client(target) adapter
-_client_map dict
}
class BaseIntegrator {
<<Abstract>>
+check_collision(target, rel, managed, force)
+find_files_by_glob(path, pattern)
+resolve_links(content, src, tgt)
+sync_remove_files(root, managed, ...)
}
class CommandIntegrator {
<<TemplateMethod>>
+integrate_commands_for_target(info, root, target, force, managed)
+_write_gemini_command(src, tgt)$
}
class InstructionIntegrator {
<<TemplateMethod>>
+integrate_instructions_for_target(...)
+copy_instruction_gemini(src, tgt) int
+_convert_to_gemini_rules(content) str$
}
class MCPIntegrator {
+remove_stale_mcp_servers(stale, runtime, logger)
+_detect_runtimes(scripts) set
}
class TargetProfile {
<<ValueObject>>
+name str
+root_dir str
+primitives dict
+auto_create bool
+detect_by_dir bool
+user_supported bool
}
CopilotClientAdapter <|-- GeminiClientAdapter : extends
ClientFactory ..> GeminiClientAdapter : creates
BaseIntegrator <|-- CommandIntegrator : extends
BaseIntegrator <|-- InstructionIntegrator : extends
CommandIntegrator ..> TargetProfile : reads primitives
InstructionIntegrator ..> TargetProfile : reads primitives
MCPIntegrator ..> ClientFactory : delegates
Execution flow diagram (install path for a gemini target): flowchart TD
A[apm install] --> B[detect_target / active_targets]
B --> C{.gemini/ exists?}
C -- yes --> D[KNOWN_TARGETS gemini TargetProfile]
C -- no --> E[other targets / copilot fallback]
D --> F[install/phases/targets.py run]
F --> G[resolve_targets -> TargetProfile gemini]
G --> H[dispatch.get_dispatch_table]
H --> I{primitive type}
I -- commands --> J[CommandIntegrator.integrate_commands_for_target]
J --> K{format_id == gemini_command?}
K -- yes --> L[_write_gemini_command: .prompt.md -> .toml]
K -- no --> M[integrate_command standard path]
I -- instructions --> N[InstructionIntegrator.integrate_instructions_for_target]
N --> O[copy_instruction_gemini: strip frontmatter, .md]
I -- hooks --> P[HookIntegrator: merge into settings.json]
I -- MCP --> Q[MCPIntegrator -> GeminiClientAdapter.configure_mcp_server]
Q --> R{.gemini/ dir exists?}
R -- no --> S[return True silently - opt-in]
R -- yes --> T[write .gemini/settings.json mcpServers]
Design patterns: Inheritance / Template Method ( Single issue (required): CLI Logging Expert: Two output hygiene issues.
All other output paths (script_runner.py runtime detection, hook_integrator, instruction_integrator) are clean and follow the pattern correctly. DevX UX Expert: The new Three gaps to close before merge:
Supply Chain Security Expert: No significant concerns.
Auth Expert: Not activated -- PR touches only file integration and runtime paths ( OSS Growth Hacker: Strong strategic addition. Gemini CLI is Google-backed, MCP-native, and growing fast — expanding APM's "one manifest, every AI tool" narrative to include a Google product materially broadens the addressable audience and the cross-tool credibility story. The README hero line update ( One required fix: CHANGELOG.md has no entry for this feature. Adding a 6th first-class runtime target is a significant
Side-channel note to CEO: consider leading the next release post with the Google Gemini angle — "APM now manages five AI coding tools natively including Google Gemini CLI" is a stronger headline than any individual feature. Updated CEO arbitrationAll five mandatory specialists agreed on the disposition and the blocking issues — no arbitration of disagreements needed. This PR is architecturally sound: the data-driven Required actions before merge
Optional follow-ups
|
danielmeppiel
left a comment
There was a problem hiding this comment.
Fix all required as well as the "optional" consistency issues. They are all required. Excited about this one!
Add full Gemini CLI support including target profile, runtime setup scripts, golden scenario E2E test, and offline integration tests verifying command/instruction/skill/MCP deployment to .gemini/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e docs Replace 4 bare print() calls in GeminiClientAdapter.configure_mcp_server with _rich_error/_rich_success from apm_cli.utils.console. Sanitize the exception handler so str(e) internals are not exposed to users. Add gemini to --target enumerations, runtime setup/remove synopses, and target-detection table in cli-commands.md and the shipped apm-usage skill resource. Add CHANGELOG entry under [Unreleased] > Added. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ccess for stale cleanup Add "+ .gemini/settings.json (MCP/hooks)" to get_target_description() so --help and diagnostic output accurately reflect Gemini's config path. Swap _rich_info() → _rich_success(symbol="check") for all 6 "Removed stale MCP server" messages in mcp_integrator.py cleanup paths — removal is a confirmed action, not informational. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Six should_integrate_{vscode,claude,opencode,cursor,codex,gemini}()
helpers were defined and tested but never called in production code.
Each target's integration decision is handled inline by the integrators
and compile pipeline. Remove the functions and their test classes to
prevent per-target maintenance drift.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f24e048 to
b56869a
Compare
|
Got it, thanks!
Done
Is this OK to remove? It is not called in the main code base, but it does have test coverage and is part of the API surface. I did add a commit that removes this dead code if you do want me to deal with it here.
This was pre-existing pattern for all assistants, but I have updated everyone to use
This was already done, unless I'm misunderstanding what the review panel asked for |
There was a problem hiding this comment.
Pull request overview
Adds Gemini CLI as a first-class APM target, expanding the integration layer to deploy primitives into .gemini/, wire MCP servers, and provide runtime setup plus new unit/integration/E2E coverage.
Changes:
- Add a new
geminitarget profile and runtime, including setup scripts and target auto-detection. - Implement Gemini-specific integration behavior for commands (
.prompt.md->.toml), instructions (frontmatter stripping), hooks, and MCP configuration. - Add extensive unit + offline integration tests, plus an E2E golden scenario for Gemini.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_runtime_manager.py | Updates runtime list expectations to include gemini. |
| tests/unit/test_global_mcp_scope.py | Adjusts MCP scope-filtering test to account for new registry ops usage/mocking. |
| tests/unit/test_gemini_mcp.py | New unit tests for GeminiClientAdapter and factory registration. |
| tests/unit/integration/test_targets.py | Adds .gemini/ target detection tests. |
| tests/unit/integration/test_instruction_integrator.py | Adds Gemini rules conversion + integration tests (frontmatter stripped, rename behavior). |
| tests/unit/integration/test_data_driven_dispatch.py | Extends dispatch bucket expectations for Gemini commands/instructions. |
| tests/unit/integration/test_command_integrator.py | Adds Gemini command integration tests and direct TOML writer unit tests. |
| tests/unit/core/test_target_detection.py | Updates target detection expectations and removes tests for deleted helpers. |
| tests/unit/core/test_scope.py | Updates known-target set to include gemini. |
| tests/integration/test_golden_scenario_e2e.py | Adds Gemini golden-scenario E2E flow and HOME/ADC credential handling. |
| tests/integration/test_gemini_integration.py | New offline integration test suite covering .gemini/ deploy behaviors. |
| src/apm_cli/runtime/manager.py | Adds Gemini runtime metadata + npm uninstall support + preference ordering. |
| src/apm_cli/integration/targets.py | Registers gemini as a TargetProfile with primitive mappings under .gemini/. |
| src/apm_cli/integration/mcp_integrator.py | Adds Gemini to runtime detection/filtering and stale MCP cleanup for .gemini/settings.json. |
| src/apm_cli/integration/instruction_integrator.py | Adds gemini_rules transform (strip frontmatter) + sync legacy handling. |
| src/apm_cli/integration/hook_integrator.py | Adds Gemini hook merge config targeting settings.json. |
| src/apm_cli/integration/command_integrator.py | Adds Gemini command transform path (.prompt.md -> .toml). |
| src/apm_cli/factory.py | Registers GeminiClientAdapter in ClientFactory. |
| src/apm_cli/core/target_detection.py | Adds .gemini/ auto-detection and includes gemini in canonical targets/descriptions. |
| src/apm_cli/core/script_runner.py | Adds Gemini runtime command detection/transform + execution path (-p content). |
| src/apm_cli/compilation/agents_compiler.py | Adjusts compile routing behavior to treat some targets as “no compilation needed”. |
| src/apm_cli/commands/runtime.py | Extends runtime CLI choices to include gemini. |
| src/apm_cli/adapters/client/gemini.py | New MCP adapter writing Gemini settings and configuring MCP servers. |
| scripts/runtime/setup-gemini.sh | New Unix setup script to install @google/gemini-cli and initialize settings. |
| scripts/runtime/setup-gemini.ps1 | New Windows setup script to install @google/gemini-cli and initialize settings. |
| packages/apm-guide/.apm/skills/apm-usage/commands.md | Updates guide docs for runtime setup/remove to include Gemini. |
| docs/src/content/docs/reference/cli-commands.md | Updates CLI reference to include Gemini target/runtime and related option lists. |
| docs/src/content/docs/introduction/why-apm.md | Updates narrative to include Gemini in the “native integration” set. |
| docs/src/content/docs/integrations/ide-tool-integration.md | Updates integration docs to reflect Gemini’s native per-file support and hooks coverage. |
| docs/src/content/docs/index.mdx | Updates landing page copy to include Gemini in supported tool list. |
| docs/src/content/docs/guides/mcp-servers.md | Updates MCP guide to include Gemini in supported clients list. |
| docs/src/content/docs/guides/compilation.md | Updates compilation guidance/table to reflect full Gemini integration. |
| docs/src/content/docs/getting-started/quick-start.md | Updates quick start narrative to include .gemini/ and Gemini in client list. |
| docs/src/content/docs/enterprise/making-the-case.md | Updates enterprise framing/examples to include Gemini as an additional tool. |
| README.md | Updates README supported-tools list and related copy to include Gemini. |
| CHANGELOG.md | Adds an Unreleased entry announcing Gemini target + runtime support. |
Copilot's findings
Comments suppressed due to low confidence (4)
src/apm_cli/adapters/client/gemini.py:60
- GeminiClientAdapter sets
supports_user_scope = True, butget_config_path()and related logic write toPath(os.getcwd())/.gemini/settings.json. That means a user-scope (--global) MCP install for Gemini would write to the current directory rather than~/.gemini/settings.json(which the runtime setup script initializes). Consider either (1) making the adapter write toPath.home()/.gemini/settings.jsonwhen used in user scope, or (2) settingsupports_user_scope = Falseuntil user-scope behavior is correctly implemented.
supports_user_scope: bool = True
def get_config_path(self):
"""Return the path to ``.gemini/settings.json`` in the repository root."""
return str(Path(os.getcwd()) / ".gemini" / "settings.json")
def update_config(self, config_updates):
"""Merge *config_updates* into the ``mcpServers`` section of settings.json.
The ``.gemini/`` directory must already exist; if it does not, this
method returns silently (opt-in behaviour).
Preserves all other top-level keys in settings.json (theme, tools,
hooks, etc.).
"""
gemini_dir = Path(os.getcwd()) / ".gemini"
if not gemini_dir.is_dir():
return
src/apm_cli/compilation/agents_compiler.py:251
- Returning success with an empty CompilationResult when no compilers ran makes
apm compile -t gemini/-t cursorsilently no-op (and can also hide accidental target typos that still pass_KNOWN_TARGETS). Consider either rejecting targets that don't produce compilation output, or emitting an explicit warning/summary indicating that compilation is not applicable for that target.
# Some targets (e.g. gemini, cursor) use the data-driven
# integration layer and don't need AGENTS.md/CLAUDE.md compilation.
if not results:
return CompilationResult(
success=True,
output_path="",
content="",
warnings=self.warnings.copy(),
errors=self.errors.copy(),
stats={},
)
src/apm_cli/adapters/client/gemini.py:31
_rich_infois imported but never used in this module. Please drop the unused import to keep linting clean.
from .copilot import CopilotClientAdapter
from ...utils.console import _rich_error, _rich_info, _rich_success
src/apm_cli/adapters/client/gemini.py:131
_rich_success(..., symbol="success")maps to the "success" entry inSTATUS_SYMBOLS, which currently renders as "[*]" (not the repo's[+]success/confirmed symbol). For a confirmed successful configuration, use the "check" symbol (or omit the symbol) so the output matches the documented status-symbol convention.
_rich_success(
f"Configured MCP server '{config_key}' for Gemini CLI", symbol="success"
)
- Files reviewed: 36/36 changed files
- Comments generated: 5
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GEMINI.md now generates a thin stub containing `@./AGENTS.md` which leverages Gemini CLI's native import preprocessor instead of duplicating the full instruction roll-up. This ensures AGENTS.md is always compiled alongside GEMINI.md via should_compile_agents_md(). Also fixes doc consistency: adds .gemini/ to CI drift checks, commit guides, and auto-detection lists; removes inaccurate "no compile step" claims for Gemini; clarifies compile vs install behavior; removes broken test referencing deleted .gemini/rules/ support; and cleans up an unused import. Reviewed-by: APM Review Panel (Python Architect, CLI Logging Expert, DevX UX Expert, Supply Chain Security Expert, OSS Growth Hacker, CEO Arbiter) Reviewed-by: CodeRabbit (coderabbit review --agent) Reviewed-by: Claude Opus 4.7 (standalone code reviewer) Reviewed-by: Gemini 2.5 Pro (gemini-cli --sandbox) Reviewed-by: Technical Writer (documentation consistency reviewer) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e4a593d to
04d4bfc
Compare
New target mandatory test requirement before merge:report back with a proof of integration test ran locally across all APM commands and functionalities touching the target, including:
The test results are to be passed to the review panel for approval and posted here as a comment that shows a table of all cases tested above and the results The integration tests in the repo should be extended to cover the above with Gemini (it is not guaranteed that current tests do cover all cases above) |
- Reimplement _format_server_config for Gemini (no type/tools/id fields, httpUrl for HTTP remotes, url for SSE) - Map hook event names per target (preToolUse->BeforeTool, Stop->SessionEnd) - Transform flat Copilot hook entries to nested Gemini format (bash->command, timeoutSec->timeout in ms, hooks[] nesting) - Add unit tests for MCP config format and hook transformations - Fix hallucinated documentation links in test report Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gemini CLI Integration Test ReportAll tests ran locally against Primitives supported by Gemini target
Manual test matrix
Automated test coverage5488 unit tests pass (0 failures).
Summary13/13 manual tests pass. All primitive types (commands, skills, hooks, MCP, instructions/compile), all package types (direct, transitive, local, marketplace), both scopes (project, user), and install/uninstall/compile all work correctly for the Gemini target. 47 automated Gemini tests across 6 test files cover commands, skills, MCP config format, hooks (event name mapping + structure transformation), opt-in, multi-target, uninstall cleanup, compilation, and global scope. |
APM Review Panel VerdictDisposition: REQUEST_CHANGES (one blocking bug: GitHub MCP server auth raises ValueError for Gemini target; all other findings are minor) Per-persona findingsPython Architect: The PR adds OO / class diagram classDiagram
direction TB
class CopilotClientAdapter {
<<Adapter>>
+_format_server_config(server_info) dict
+_select_best_package(packages) dict
+_is_github_server(name, url) bool
+_resolve_env_variable(name, value, overrides) str
}
class GeminiClientAdapter {
<<Adapter>>
+supports_user_scope bool
+get_config_path() str
+get_current_config() dict
+update_config(config_updates) None
+configure_mcp_server(server_url, ...) bool
+_format_server_config(server_info) dict
}
class ClientFactory {
<<Factory>>
+_registry dict
+create_client(name) BaseAdapter
}
class GeminiFormatter {
<<Formatter>>
+base_dir Path
+format_distributed(primitives) GeminiCompilationResult
+_generate_stub() str
}
class GeminiCompilationResult {
<<ValueObject>>
+success bool
+placements List
+content_map Dict
+warnings List
+errors List
+stats Dict
}
class GeminiPlacement {
<<ValueObject>>
+gemini_path Path
+instructions List
+coverage_patterns Set
+source_attribution Dict
}
class AgentsCompiler {
+_compile_gemini_md(config, primitives) CompilationResult
}
class HookIntegrator {
+integrate_hooks_for_target(target, ...) HookIntegrationResult
}
note for GeminiClientAdapter "Overrides _format_server_config:\nno type/tools/id; httpUrl vs url;\nBearer token via GitHubTokenManager"
note for GeminiFormatter "Template Method: _generate_stub()\nproduces thin @./AGENTS.md import stub"
CopilotClientAdapter <|-- GeminiClientAdapter : extends
ClientFactory ..> GeminiClientAdapter : creates
AgentsCompiler ..> GeminiFormatter : uses
GeminiFormatter ..> GeminiCompilationResult : returns
GeminiCompilationResult *-- GeminiPlacement : contains
class GeminiClientAdapter:::touched
class GeminiFormatter:::touched
class GeminiCompilationResult:::touched
class GeminiPlacement:::touched
class AgentsCompiler:::touched
classDef touched fill:#fff3b0,stroke:#d47600
Execution flow diagram flowchart TD
A["apm install --target gemini"] --> B["detect_target() -> 'gemini'"]
B --> C{"has .gemini/ dir?"}
C -- No --> D["[FS] skip Gemini integration"]
C -- Yes --> E["CommandIntegrator: .prompt.md -> .gemini/commands/*.toml"]
E --> F["_write_gemini_command(source, target)\n[FS] toml.dumps + target.write_text"]
C -- Yes --> G["HookIntegrator: _MERGE_HOOK_TARGETS['gemini']"]
G --> H["_integrate_merged_hooks()\n_HOOK_EVENT_MAP renaming\nPreToolUse->BeforeTool, Stop->SessionEnd"]
H --> I["_to_gemini_hook_entries()\nbash->command, timeoutSec->timeout(ms)\n[FS] .gemini/settings.json updated"]
C -- Yes --> J["MCPIntegrator: configure_mcp_server()\n[NET] registry lookup"]
J --> K{"_is_github_server?"}
K -- Yes --> L["GitHubTokenManager().get_token_for_purpose('gemini')\n[BUG] raises ValueError - not in TOKEN_PRECEDENCE"]
L --> M["Exception caught -> _rich_error 'Failed to configure MCP server'"]
K -- No --> N["_format_server_config: command/url/httpUrl transport\n[FS] .gemini/settings.json updated"]
A --> O["apm compile --target gemini"]
O --> P["should_compile_agents_md('gemini') -> True"]
P --> Q["_compile_agents_md()\n[FS] AGENTS.md written"]
O --> R["should_compile_gemini_md('gemini') -> True"]
R --> S["GeminiFormatter._generate_stub()\n[FS] GEMINI.md written with @./AGENTS.md import"]
Design patterns
CLI Logging Expert: Output paths are clean throughout. The stale-MCP-cleanup changes from One minor inconsistency: All output strings are printable ASCII. No bare DevX UX Expert:
One doc drift: in The quick-start callout explaining that Gemini needs Supply Chain Security Expert: No new path traversal surface. No credentials are logged or included in error messages. The token injection bug noted by Auth Expert means GitHub MCP server auth silently fails rather than leaking a token -- the failure mode is safe from a credential-exfiltration perspective, though the silent failure is a correctness bug. The Auth Expert: BLOCKING BUG -- required action before merge.
token = _tm.get_token_for_purpose("gemini") or os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")
Impact: configuring any GitHub-hosted MCP server for the Gemini target silently fails. Non-GitHub MCP servers (npm, pypi, docker, homebrew) are unaffected (that code path is only hit for remote endpoints flagged by Fix -- change line 151 in # Before (broken):
token = _tm.get_token_for_purpose("gemini") or os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")
# After (correct -- same GitHub token purpose as the Copilot adapter):
token = _tm.get_token_for_purpose("copilot") or os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")This matches OSS Growth Hacker: Gemini CLI is Google's open-source AI assistant (MIT license, 250+ GitHub stars in its first weeks, Node 20+ install via npm). Adding it as an APM target positions APM as the cross-ecosystem package manager for AI development -- not tied to any single vendor. This is a strong differentiation story. The opt-in The CHANGELOG entry is well-scoped and searchable. The quick-start note distinguishing Side-channel to CEO: This is the right time to update CEO arbitrationThe Gemini CLI target is strategically sound and architecturally consistent. Every specialist agrees the implementation follows established APM patterns. The Auth Expert surfaced one blocking bug ( Required actions before merge
Optional follow-ups
|
- Remove get_token_for_purpose("gemini") call that raises ValueError
(no "gemini" key in TOKEN_PRECEDENCE); Gemini adapter doesn't need
GitHub token injection
- Remove vestigial coverage_patterns/source_attribution from GeminiPlacement
- Fix _log("progress") call to match other call sites (no f-string, no [+])
- Add gemini to --runtime TEXT list in cli-commands.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
de3d587 to
fc0c63c
Compare
I removed this since it was just a port from Copilot, I don't think we need to special-case github token handling, no other provider does it
Done
Done
Done
This is already there |
|
re-running the panel. @stbenjam hint: you can run the panel locally, it's just a skill (apm-review-panel). |
Yup, I have been! I love the panel's review style. I pass it through Gemini CLI, coderabbit, apm-review-panel (with Opus 4.6, so I get different results than yours on Github), and Opus 4.7 with a "Technical Writer" persona (this helped surface some inconsistencies, similar to your doc writer but as a reviewer) |
APM Review Panel VerdictDisposition: APPROVE (one optional UX follow-up, no required pre-merge actions) Per-persona findingsPython Architect: This is a cross-cutting target addition spanning six layers (adapter, compilation, integration, runtime, detection, factory) that faithfully follows the established target-extension pattern used for Cursor and Codex. No new architectural patterns are introduced; existing patterns are extended cleanly. 1. OO / class diagramclassDiagram
direction LR
class CopilotClientAdapter {
<<Adapter>>
+configure_mcp_server(url, ...) bool
+_format_server_config(info, ...) dict
+get_config_path() str
+update_config(updates)
+get_current_config() dict
}
class GeminiClientAdapter {
<<Adapter>>
+supports_user_scope bool
+get_config_path() str
+update_config(updates)
+_format_server_config(info, ...) dict
+configure_mcp_server(url, ...) bool
}
class GeminiFormatter {
<<Pure>>
+base_dir Path
+format_distributed(primitives, ...) GeminiCompilationResult
-_generate_stub() str
}
class GeminiCompilationResult {
<<ValueObject>>
+success bool
+placements List
+content_map Dict
+warnings List
+errors List
+stats Dict
}
class GeminiPlacement {
<<ValueObject>>
+gemini_path Path
+instructions List
}
class AgentsCompiler {
+compile_package(config) CompilationResult
-_compile_gemini_md(config, primitives) CompilationResult
-_compile_agents_md(config, primitives) CompilationResult
-_compile_claude_md(config, primitives) CompilationResult
}
class ClientFactory {
<<Factory>>
+create_client(target) BaseClientAdapter
}
class RuntimeManager {
+runtimes Dict
+remove_runtime(name) bool
+get_runtime_preference() List
}
CopilotClientAdapter <|-- GeminiClientAdapter : extends
AgentsCompiler *-- GeminiFormatter : creates
GeminiFormatter ..> GeminiCompilationResult : returns
GeminiCompilationResult *-- GeminiPlacement : contains
ClientFactory ..> GeminiClientAdapter : creates
note for GeminiClientAdapter "Adapter: inherits Copilot helpers,\noverrides _format_server_config\nfor Gemini schema (no type/tools/id)"
class GeminiClientAdapter:::touched
class GeminiFormatter:::touched
class GeminiCompilationResult:::touched
class GeminiPlacement:::touched
class AgentsCompiler:::touched
class ClientFactory:::touched
class RuntimeManager:::touched
classDef touched fill:#fff3b0,stroke:#d47600
2. Execution flow diagramflowchart TD
A[apm install / apm compile --target gemini] --> B[target_detection.detect_target]
B --> C{.gemini/ dir exists?}
C -->|yes| D[target = gemini]
C -->|no| E[other target or minimal]
D --> F[GeminiClientAdapter.configure_mcp_server]
F --> G{.gemini/ dir check}
G -->|absent| H[return True silently -- opt-in guard]
G -->|present| I[NET: registry_client.find_server_by_reference]
I --> J[_format_server_config -- transport inferred from key]
J --> K[update_config]
K --> L[FS: write .gemini/settings.json mcpServers]
D --> M[hook_integrator.merge_hooks]
M --> N[_to_gemini_hook_entries -- flatten Copilot -> Gemini nested format]
N --> O[_copilot_keys_to_gemini -- rename bash->command, timeoutSec->timeout ms]
O --> P[FS: write .gemini/settings.json hooks]
D --> Q[command_integrator.integrate_package_commands]
Q --> R{format_id == gemini_command?}
R -->|yes| S[_write_gemini_command]
S --> T[FS: write .gemini/commands/*.toml via toml.dumps]
D --> U[AgentsCompiler: should_compile_gemini_md -- true]
U --> V[GeminiFormatter.format_distributed]
V --> W[_generate_stub: GEMINI.md with @./AGENTS.md import]
W --> X[FS: write GEMINI.md]
3. Design patternsDesign patterns
Additional observations:
CLI Logging Expert: Output paths are consistent with existing adapter conventions. DevX UX Expert: The CLI surface is clean and consistent. One UX gap: when Supply Chain Security Expert: No new attack surfaces introduced.
Auth Expert: Not activated -- no fast-path auth files ( OSS Growth Hacker: Strong growth signal. With Gemini CLI support, APM now integrates with all six major AI coding runtimes: Copilot, Claude, Cursor, Codex, OpenCode, and Gemini. This is the "universal cross-agent package manager" narrative made concrete -- a compelling one-liner for README, blog posts, and conference talks. Google's Side-channel to CEO: the README hero section and feature table list targets but do not yet lead with the "works across all six major AI coding tools" hook. That count (now six targets) is the most memorable differentiator in the package-manager space and could materially improve first-visit conversion if surfaced higher. Suggest a follow-up README polish pass. CEO arbitrationThe panel is aligned and the analysis is convergent. This is a well-scoped, cleanly executed Gemini integration that extends APM's existing multi-target architecture without bending it. Every specialist reviewed their domain and found no blocking issue: the adapter correctly inherits Copilot auth logic unchanged, logging follows established conventions, supply-chain exposure is bounded by the opt-in directory guard, and the CLI surface is unsurprising. The two items worth noting: (1) the silent no-op when From a positioning standpoint, six-target breadth is now APM's strongest differentiator. The Growth Hacker's side-channel is received: a README polish pass to lead with the six-runtime count is a quick follow-up with outsized conversion impact. Disposition: APPROVE. Merge when ready. Required actions before merge
Optional follow-ups
|
Hm, no other provider does it. It is a nice suggestion but maybe should apply to everyone? But then it'd get noisy.
This is there
This is probably true the comments can be removed everywhere but I need to look closer, I need to wrap up for the day so I can pick it up on Monday if needs to get addressed |
|
Those were really nits and don't make sense - LGTM! Great contribution @stbenjam ! |
Document apm runtime setup gemini and the Gemini CLI runtime introduced in #917. Updates: - Overview table: three -> four runtimes, add Gemini CLI row - Quick Setup: add gemini to runtime management examples - New 'Google Gemini CLI Runtime' section with setup, authentication options, usage examples, and MCP integration note - Troubleshooting: add gemini to runtime-not-found list and add 'Command not found: gemini' entry Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
Add full Gemini CLI support including target profile, runtime setup scripts, golden scenario E2E test, and offline integration tests verifying command/instruction/skill/MCP deployment to .gemini/.
I have tested this locally with a variety of packages including
microsoft/apm-sample-packageand various Claude Code-formatted plugins, and it works pretty well. I've also added integration "golden" tests and they pass against both Vertex AI and my personal Gemini accounts.Fixes # (issue)
N/A
Type of change
Testing