Files
paperclip-docs/docs/reference/adapters/gemini-cli.md
Aron PrinsandClaude Opus 5 325c9eb819 seo: hand-write titles and descriptions for all 192 pages (#115)
## Why

The build derived `<title>` from the **sidebar label** and the
description from the **first paragraph clipped to 220 characters**. Both
are the wrong source. A sidebar label is written for a 240px-wide nav
that supplies its own context; a search result has none.

On production that produced:

- **7 pages titled "Overview"**, and 32 pages sharing a title with
another page
- **109 of 193 descriptions cut off mid-word**, and 174 over 160
characters (where Google truncates)

```
/guides/welcome/key-concepts/
  BEFORE (220):  ...and if you misunderstand them early, the product wi
```

Near-identical titles are the weak-differentiation signal behind
"crawled — currently not indexed", which is the exact symptom on this
property.

## What changed

`seo_title` and `seo_description` frontmatter on **every one of the 192
pages**, written by hand against each page's real content and optimised
for the click — lead with what the reader can do, name the concrete
things covered, no keyword stuffing, no repeating the title.

| | Before | After |
|---|---|---|
| Duplicate titles | 32 pages | **0** |
| Duplicate descriptions | — | **0** |
| Descriptions cut mid-word | 109 | **0** |
| Descriptions over 160 chars | 174 | **0** |
| Title length (incl. suffix) | up to "Overview" | **26–60** |
| Description length | 31–240 | **122–158** |

**No prose was rewritten.** I measured content overlap between the
colliding pairs first — only 17–23%, so these were always distinct pages
wearing the same label, not duplicate content. The `docs/` diff is **564
insertions, zero deletions**.

### Examples

```
BEFORE — all seven identical:  "Overview | Paperclip Docs"
AFTER:  "Adapters Overview"      "API Overview"        "CLI Overview"
        "Deployment Overview"    "Bundled Skills"      "Optional Skills"
        "Experimental Features"

BEFORE — both identical:  "Issues | Paperclip Docs"
AFTER:  "Issues: Creating and Tracking Work"   /guides/day-to-day/issues/
        "Issues API"                           /reference/api/issues/
```

```
/guides/getting-started/five-minute-path/
BEFORE (220):  The shortest route from a running Paperclip instance to an agent that has
               just completed work for you. After Paperclip is installed, the path takes
               about 5 minutes: create a company, hire a CEO agent, approve its first s
AFTER  (131):  Install Paperclip, create a company, hire a CEO agent, and approve its
               first strategy — a working AI company in about five minutes.
```

## Plumbing

- **`site/build-release.mjs`** prefers the authored fields; the derived
path stays only as a fallback the CI gate prevents ever reaching.
`<title>`, `<meta name="description">`, and the `TechArticle` JSON-LD
all read from the same source.
- **`site/app.js`** uses the same fields, so a client-side transition
cannot leave a different title on screen than the crawler was served.
Verified in-browser: navigating `/guides/day-to-day/issues/` →
`/reference/api/issues/` swaps to exactly the server-rendered values, no
JS errors.
- **`scripts/verify-seo-metadata.mjs`** (new) enforces presence,
uniqueness, length, complete-sentence endings, and the
frontmatter-safety rules. Wired into `docs:test` and CI as its own step.

I negative-tested the gate rather than assuming it works — it correctly
fails on a duplicate title, a mid-word description, and a missing field,
and passes again once restored.

## Automating it going forward

`skills/sync-docs/SKILL.md` now:

- gains an **"Authored SEO metadata"** section: why the fields exist,
the enforced rules as a table, and how to actually write them (title
names the subject not the nav position; description writes for the
click; never generate mechanically from the first paragraph — *that is
the fallback the gate exists to prevent*).
- requires both fields in the **page-authoring instruction** given to
every subagent, with guidance on when to update an existing description
versus leave it.
- runs `docs:test:seo-metadata` and `docs:test:crawlable-links` as
**fail-loud gates in Phase 7** before commit.
- documents all six build gates in the files/gates section.

So once this lands, a new page cannot ship without hand-written
metadata, and a title collision cannot reach production.

## Verified

All six verifiers pass:

```
Static route verification passed
Asset fingerprint verification passed
Hierarchical Skills nav verification passed
Skill source block verification passed (11 skill pages, 1 control page)
Crawlable-link contract passed: 40886 internal links across 194 pages resolve in one hop
Authored-SEO contract passed: 192 pages carry a unique, hand-written seo_title and seo_description
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-25 22:51:42 +02:00

155 lines
8.7 KiB
Markdown

---
paperclip_version: v2026.720.0
seo_title: Gemini CLI Adapter
seo_description: Run Google's Gemini CLI on the Paperclip host, with session resume across heartbeats and configurable sandboxing for each agent you point at it.
---
# Gemini CLI
`gemini_local` runs Google's Gemini CLI on the same machine as Paperclip. Use it when you want a local agent with session resume, configurable sandboxing, and Paperclip skills injected into Gemini's skills directory.
---
## When To Use
- Gemini CLI is installed on the host machine.
- You want the agent to resume the same Gemini session across heartbeats.
- You want Paperclip to manage skills locally without polluting the project directory.
- You want an adapter that can authenticate through API keys or Gemini CLI login.
## When Not To Use
- The agent runs behind a webhook or remote API. Use [HTTP](./http.md).
- You only need a command runner or script. Use [Process](./process.md).
- Gemini CLI is not installed or cannot reach the target working directory.
> **Running in Docker?** The official Paperclip image pre-bundles the Gemini CLI alongside the other local CLIs, so `gemini_local` works in-container without a manual install. The image also sets `GEMINI_SANDBOX=false` for safe in-container use. You still need to supply credentials — see [Docker](../deploy/docker.md).
---
## Common Fields
| Field | Required | Notes |
|---|---:|---|
| `cwd` | no | Absolute working directory for the agent. Recommended in practice. If omitted, the adapter falls back to the current process working directory. Paperclip creates the path when permissions allow. |
| `engine` | no | How Gemini is run: `auto` (the default — ACP preferred), `acp` (always the Agent Client Protocol), or `cli` (always the classic Gemini CLI). See [ACP Engine](#acp-engine). |
| `model` | no | Gemini model id. Defaults to `auto`. Common choices include `gemini-2.5-pro` and `gemini-2.5-flash`. |
| `promptTemplate` | no | Prompt template used for the run. |
| `instructionsFilePath` | no | Markdown instructions file prepended to the prompt. |
| `sandbox` | no | Enables Gemini sandbox mode. The adapter otherwise passes `--sandbox=none`. |
| `yolo` | no | Convenience toggle for unattended approval mode. |
| `approvalMode` | no | Advanced control for Gemini approval mode. |
| `command` | no | Defaults to `gemini`. |
| `extraArgs` | no | Extra CLI arguments appended to the Gemini invocation. |
| `env` | no | Environment variables passed to the runtime. Secret refs are supported. |
| `helloProbeTimeoutSec` | no | Timeout for the readiness probe. |
| `timeoutSec` | no | Run timeout in seconds. On local and SSH targets, `0` means no adapter wall-clock timeout. On a sandbox target, `0` or an unset value uses the 14,400-second sandbox default; use a positive value to override it or a negative value to opt out of the adapter timeout. |
| `graceSec` | no | Grace period before a forced stop. |
> **Note:** Gemini CLI uses `--output-format stream-json` for readiness checks and resumes sessions with `--resume` when the stored session cwd still matches the current cwd. It passes your prompt with `--prompt` for non-interactive runs (not through stdin), and it sets a headless-safe terminal and browser environment for the Gemini CLI child process so unattended runs never stall waiting on browser auth or a colour-terminal prompt.
---
## ACP Engine
Gemini can run through one of two engines — ACP or the classic Gemini CLI — selected by the `engine` field:
- **`auto` (default) — ACP preferred.** Paperclip runs Gemini through the Agent Client Protocol (ACP) when the host meets the prerequisites, and falls back to the Gemini CLI — with diagnostics explaining why — when it can't.
- **`acp` — always ACP.** Force the Agent Client Protocol path.
- **`cli` — always the Gemini CLI.** Force the classic CLI wrapper and skip ACP entirely.
ACP gives you a richer, structured live transcript: session identity, status with context-window usage, assistant and thinking token deltas, and tool-call updates that fold into a single card as they progress. That extra detail is most useful when you're watching a sandbox run stream in.
When the engine resolves to ACP (either `acp`, or `auto` on a capable host), these extra fields apply:
| Field | Default | Notes |
|---|---|---|
| `agentCommand` | `gemini --acp` | Optional override for the Gemini ACP server command. |
| `mode` | `persistent` | `persistent` keeps ACP session state between runs; `oneshot` starts fresh each run. |
| `nonInteractivePermissions` | `deny` | What to do if the ACP agent asks for input outside an interactive session — `deny` the request or `fail` the run. |
| `stateDir` | Paperclip-managed | Optional ACP session-state directory. Defaults to Paperclip's company- and agent-scoped storage. |
| `warmHandleIdleMs` | `0` | How long to keep the ACP process warm between runs, in milliseconds. `0` closes it after each run while still retaining persistent session state. |
> **Heads-up:** ACP is where the old standalone `acpx_local` adapter's capabilities now live. That adapter has been retired — pick `gemini_local` (or `claude_local` / `codex_local`) and leave `engine` on `auto` to get ACP by default.
### ACP in sandbox environments
You can keep `engine` on `auto` when this agent runs in a Paperclip sandbox environment. If that sandbox provides Paperclip's bidirectional process session, Paperclip keeps the ACP engine and its structured live transcript; you do not add a separate bridge setting to the adapter config.
An environment that only runs one-shot commands cannot host an ACP session, so `auto` falls back to the Gemini CLI with a diagnostic. The same fallback applies to non-sandbox remote targets such as SSH. Choose `engine: "acp"` when ACP is required and a failed prerequisite should stop the run, or `engine: "cli"` when you always want the CLI lane.
---
## Session Persistence
The adapter stores Gemini session ids between heartbeats and resumes them on the next wake.
If the working directory changed, the adapter starts a fresh session instead of trying to resume the old one.
If Gemini reports an unknown session error, Paperclip retries with a new session automatically.
If a resumed session grows past the model's token budget — Gemini reports that the input exceeds the maximum number of tokens — the adapter treats the old session as unrecoverable and retries once with a fresh session instead of failing the run. Expect this on long-running agents whose conversation history eventually outgrows the context window.
---
## Headless Auth
Gemini CLI refuses non-interactive runs unless an auth method is persisted in `~/.gemini/settings.json`, and the `GEMINI_DEFAULT_AUTH_TYPE` environment variable alone does not satisfy this. To keep headless runs from stalling on the interactive auth-method prompt, the adapter pre-selects the API-key auth method for you when it manages the run's home directory and an API key (`GEMINI_API_KEY` or `GOOGLE_API_KEY`) is present. It writes `selectedAuthType: "gemini-api-key"` to that `settings.json` and leaves any existing `settings.json` untouched.
This pre-selection only applies to runs where Paperclip provisions a managed home directory (remote execution targets). For ordinary local runs the adapter uses your real home directory, where your existing Gemini auth is already in place.
## Skills Injection
Gemini CLI symlinks Paperclip skills into `~/.gemini/skills`.
The adapter does not overwrite existing user skills. It only exposes the Paperclip-managed skills it needs for the run.
---
## Environment Test
The `Test Environment` button checks:
- Gemini CLI is installed and executable.
- The working directory is absolute and usable.
- Authentication is available through `GEMINI_API_KEY`, `GOOGLE_API_KEY`, Google account login, or Gemini's CLI auth.
- The hello probe can run `gemini --output-format json "Respond with hello."`
The test also detects auth and quota failures, so a passing install check does not automatically mean the account can still run work.
---
## Example
```json
{
"adapterType": "gemini_local",
"adapterConfig": {
"cwd": "/Users/me/projects/paperclip-workspace",
"model": "gemini-2.5-pro",
"instructionsFilePath": "/Users/me/projects/paperclip-workspace/INSTRUCTIONS.md",
"promptTemplate": "You are the product engineer for this company. Stay focused on the task.",
"sandbox": false,
"yolo": true,
"env": {
"GEMINI_API_KEY": {
"type": "secret_ref",
"secretId": "secret-id",
"version": "latest"
}
},
"helloProbeTimeoutSec": 10,
"timeoutSec": 300,
"graceSec": 15
}
}
```
---
## Next Steps
- [Creating an Adapter](./creating-an-adapter.md)
- [Adapter UI Parser Contract](./adapter-ui-parser.md)
- [External Adapters](./external-adapters.md)