Skip to content

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 or GEMINI_* 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:

json
{
  "mcpServers": {
    "planu": {
      "command": "npx",
      "args": ["@planu/cli@latest"]
    }
  }
}

Then initialize Planu for your project:

init_project projectPath=/path/to/your/project

This auto-detects the Gemini workspace and scaffolds .gemini/ with conventions and skills.

Workspace Detection

Planu detects a Gemini workspace via:

  1. Presence of a .gemini/ directory at the project root
  2. 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:

  1. Calls inject_component_context — enriches the spec with visual component hints
  2. 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

TypeMIMETrigger
Screenshotimage/png, image/jpeg, image/webp, image/gif, image/svg+xmlinject_component_context
PDFapplication/pdfinject_component_context
Figma tokensapplication/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 placeholder

No .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 typeGemini 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:

SurfaceFallback
Agent TeamsSingle-agent inline execution
Plan modeDirect tool execution
SubagentsSequential inline tool calls
WorktreesNot 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):

typescript
// 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
Join the communityAsk questions, share feedback, and connect with other developers using Planu.
Join Discord