Planu — Gemini CLI Host Adapter
SPEC-591 | Gemini CLI integration with multimodal-first spec workflows
Overview
The Gemini CLI host adapter (src/hosts/gemini/) exposes Planu to Gemini CLI users. It handles:
- Workspace detection (
.gemini/dir orGEMINI_*env vars) - Zod ↔ Gemini function-calling schema translation
- Multimodal spec creation (image/PDF →
inject_component_context+ figma-tokens) .gemini/config scaffolding (conventions, skills, hook equivalents)- Graceful fallback for Claude-specific surfaces (Agent Teams, plan mode, subagents)
Installation
Add Planu to your Gemini CLI MCP configuration:
{
"mcpServers": {
"planu": {
"command": "npx",
"args": ["@planu/cli@latest"]
}
}
}Then initialize Planu for your project:
init_project projectPath=/path/to/your/projectThis auto-detects the Gemini workspace and scaffolds .gemini/ with conventions and skills.
Workspace Detection
Planu detects a Gemini workspace via:
- Presence of a
.gemini/directory at the project root - Any
GEMINI_*environment variable in the current process
When detected, the adapter activates automatically on server start.
Multimodal Spec Creation
Gemini CLI supports image and PDF attachments natively. When you attach a design file to a create_spec request, Planu automatically:
- Calls
inject_component_context— enriches the spec with visual component hints - Extracts Figma design tokens (if a
figma-tokens.json,design-tokens.json, or similar file is attached)
No manual tool chaining required. Just attach the image/PDF and describe the feature.
Supported attachment types
| Type | MIME | Trigger |
|---|---|---|
| Screenshot | image/png, image/jpeg, image/webp, image/gif, image/svg+xml | inject_component_context |
application/pdf | inject_component_context | |
| Figma tokens | application/json with filename hint (figma, design-tokens, tokens.json, variables.json) | figma-tokens extraction |
Scaffolded Files
After init_project with a Gemini workspace, the following files are created (idempotent):
.gemini/
├── conventions.md # Planu SDD conventions for this project
├── skills/
│ ├── planu-workflow.md # Core SDD workflow skill
│ └── planu-multimodal.md # Multimodal spec creation skill
└── hooks/
├── pre-tool.sh # Pre-tool hook placeholder
└── post-tool.sh # Post-tool hook placeholderNo .claude/ files are created when running in Gemini mode.
Tool Schema Translation
Planu translates its Zod tool schemas to Gemini's function-calling declaration format automatically. All basic Zod types are translated losslessly:
| Zod type | Gemini type |
|---|---|
z.string() | string |
z.number() | number |
z.boolean() | boolean |
z.enum([...]) | string with enum values |
z.array(T) | array with items |
z.object({...}) | object with properties |
z.optional(T) | field excluded from required |
Complex types (z.union, z.record) fall back to string with a warning logged once.
Graceful Degradation
The following Claude Code surfaces have no Gemini equivalent. Planu falls back gracefully and logs a single warning per session:
| Surface | Fallback |
|---|---|
| Agent Teams | Single-agent inline execution |
| Plan mode | Direct tool execution |
| Subagents | Sequential inline tool calls |
| Worktrees | Not applicable (no isolation) |
Isolation from Other Adapters
The Gemini adapter has zero shared runtime state with other host adapters (e.g., SPEC-592 Codex adapter). Each adapter is an independent module under src/hosts/. One adapter failing does not affect others.
Integration with init_project
To wire Gemini scaffolding into init_project, add the following to src/tools/init-project/scaffold-writer.ts after the conventionsMdWritten block (around line 197):
// SPEC-591: Scaffold .gemini/ config if Gemini workspace is detected (best-effort)
let geminiScaffoldCreated = false;
try {
const { detectGeminiWorkspace, scaffoldGeminiConfig } = await import('../../hosts/gemini/index.js');
const geminiMarker = await detectGeminiWorkspace(projectPath);
if (geminiMarker.detected) {
const geminiResult = await scaffoldGeminiConfig(projectPath);
geminiScaffoldCreated = geminiResult.modified;
}
} catch {
/* best-effort */
}Return geminiScaffoldCreated in the ScaffoldWriteResult object and add it to the result builder.
Architecture
src/hosts/gemini/
├── adapter.ts # Workspace detection + adapter activation
├── tool-schema-translator.ts # Zod ↔ Gemini schema translation
├── multimodal-spec-flow.ts # Image/PDF → inject_component_context + figma-tokens
├── config-scaffold.ts # .gemini/ directory scaffolding
└── index.ts # Barrel export
src/types/gemini.ts # Domain types (no imports from other src/ layers)
tests/hosts/gemini/
├── adapter.test.ts
├── tool-schema-translator.test.ts
├── multimodal-spec-flow.test.ts
└── config-scaffold.test.ts
tests/types/
└── gemini.test.ts