Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@
"url": "https://nothingfancy.ai"
},
"source": "./plugins/gemini-tts-prompting"
},
{
"name": "launching-google-ai",
"version": "0.1.0",
"description": "Opens Google Gemini or Google Stitch in the browser with a pre-filled prompt and optional Gemini tool (image, video, music, deep research, canvas, guided learning). Use when asked to 'ask Gemini', 'open Gemini with', 'stitch this', 'use deep research on', 'generate a video in Gemini', or otherwise launch a prefilled Gemini or Stitch session via URL parameters from the shell. Does not auto-submit — only pre-fills the prompt box.",
"author": {
"name": "Wesley O. Nichols",
"email": "wes@nothingfancy.ai",
"url": "https://nothingfancy.ai"
},
"source": "./plugins/launching-google-ai"
}
]
}
1 change: 1 addition & 0 deletions .codex/skills/launching-google-ai
4 changes: 2 additions & 2 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v1
- uses: astral-sh/ruff-action@v3
with:
version: latest
args: check
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ evals/transcripts/*
evals/reports/*
!evals/reports/.gitkeep
evals/.promptfoo-cache/

scratchpad/
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/plugins/justfile/ @wesnick
/plugins/nano-banana-prompting/ @wesnick
/plugins/gemini-tts-prompting/ @wesnick
/plugins/launching-google-ai/ @wesnick

# Shared infrastructure
/.github/ @wesnick
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ This is the preferred mode when you want a narrow, focused session.
|--------|-------------|
| [nano-banana-prompting](plugins/nano-banana-prompting/) | Crafts and reviews prompts for Google's Nano Banana 2 (Gemini 3.1 Flash Image) and Nano Banana Pro (Gemini 3 Pro Image) image generation and editing models — frameworks, camera/lighting direction, and text rendering. |
| [gemini-tts-prompting](plugins/gemini-tts-prompting/) | Crafts and reviews prompts for Google's Gemini 3.1 Flash TTS using audio tags, voice style instructions, and pacing controls — narration, audiobooks, IVR, accessibility, multilingual content. |
| [launching-google-ai](plugins/launching-google-ai/) | Opens Google Gemini or Google Stitch in the browser with a pre-filled prompt and optional Gemini tool selection (image, video, music, deep research, canvas, guided learning) via URL parameters. |

## Philosophy

Expand Down
135 changes: 135 additions & 0 deletions evals/cases/launching-google-ai/cases.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Regression suite for launching-google-ai skill

description: "launching-google-ai skill regression cases"

tests:
# --- Positive: Gemini deep-research launch ---
- description: "Positive — 'ask gemini to research X' should build a Gemini deep-research URL"
vars:
prompt: |
ask gemini to research the history of LISP
assert:
- type: contains
value: "https://gemini.google.com/?prompt="
- type: contains
value: "tool=research"
- type: contains-any
value:
- "the%20history%20of%20LISP"
- "the+history+of+LISP"
- type: contains-any
value:
- "${BROWSER:-xdg-open}"
- "$BROWSER"
- type: llm-rubric
value: |
The response must: (1) build a URL on gemini.google.com (NOT
stitch.withgoogle.com, NOT any other Google surface), (2) use
?prompt= as the parameter (NOT ?q= or ?query=), (3) percent-encode
the prompt text, (4) include &tool=research because the user said
"research", using the SHORT alias "research" rather than the human
label "Deep research", and (5) open the URL via ${BROWSER:-xdg-open}
(or equivalent fallback) so a user-configured browser is honored.
The response must NOT attempt to auto-submit the prompt — pre-fill
only.

# --- Positive: Stitch design launch (no tool param) ---
- description: "Positive — 'stitch a pricing page' should build a Stitch URL with no tool parameter"
vars:
prompt: |
stitch a clean SaaS pricing page with three tiers
assert:
- type: contains
value: "https://stitch.withgoogle.com/?prompt="
- type: not-contains
value: "tool="
- type: llm-rubric
value: |
The response must: (1) target stitch.withgoogle.com, NOT
gemini.google.com, because the user explicitly said "stitch",
(2) NOT include any &tool=... parameter — Stitch does not accept a
tool parameter and adding one is wrong, (3) percent-encode the
design brief into the prompt= parameter verbatim (the user's words,
not paraphrased), (4) open via ${BROWSER:-xdg-open} or equivalent.

# --- Negative: prompt-craft request should NOT fire this skill ---
- description: "Negative — 'help me write a prompt for Gemini image gen' is a prompt-craft task, not a launch task"
vars:
prompt: |
Help me write a prompt for Gemini image generation of a vintage
bookstore at golden hour with reference photos I'll attach.
assert:
- type: not-contains
value: "gemini.google.com/?prompt="
- type: not-contains
value: "xdg-open"
- type: not-contains
value: "${BROWSER"
- type: llm-rubric
value: |
The response must address prompt-craft for Gemini image generation
on its own terms (subject + action + location + composition + style,
camera/lighting direction, treatment of reference images, etc.) —
this is the territory of the nano-banana-prompting skill, NOT
launching-google-ai. The response must NOT construct a
gemini.google.com URL, must NOT call xdg-open or $BROWSER, and must
NOT instruct the user to launch the Gemini web UI. The launching
skill should not fire because the user is asking how to write the
prompt, not how to open Gemini.

# --- Edge: multi-line prompt with special chars must encode newlines ---
- description: "Edge — multi-line prompt should encode newlines as %0A and preserve special chars"
vars:
prompt: |
Open Gemini with this multi-line prompt and use deep research:

Compare Rust and Zig for systems work.
Cover: memory model, async story, & C interop.
Cite sources.
assert:
- type: contains
value: "https://gemini.google.com/?prompt="
- type: contains
value: "tool=research"
- type: contains
value: "%0A"
- type: contains-any
value:
- "%26"
- "&"
- type: llm-rubric
value: |
The response must: (1) percent-encode every newline in the
multi-line prompt as %0A so the prompt arrives in the Gemini box
with line breaks intact, (2) percent-encode the literal "&"
character inside the prompt body as %26 so it is NOT interpreted as
a URL parameter separator (this is the historically-broken case —
an unencoded "&" silently truncates the prompt at the ampersand),
(3) still produce a single well-formed URL with ?prompt=... and
&tool=research, (4) open via ${BROWSER:-xdg-open}.

# --- Edge: ambiguous tool cue should default to omitting tool= ---
- description: "Edge — ambiguous request without a clear tool cue should omit the tool parameter"
vars:
prompt: |
open gemini and ask it what the weather will be like in Madrid this
weekend
assert:
- type: contains
value: "https://gemini.google.com/?prompt="
- type: not-contains
value: "tool=research"
- type: not-contains
value: "tool=image"
- type: not-contains
value: "tool=video"
- type: llm-rubric
value: |
The response must build a Gemini URL with ?prompt=... but must NOT
include any &tool=... parameter, because the user's request ("ask
it what the weather will be like") does not clearly match any of
the six known tool aliases (image, video, music, research, canvas,
learn). The skill's documented behavior is to omit tool= when the
intent is ambiguous and let Gemini pick a default. The response
must NOT fabricate an unsupported tool name like "weather",
"search", or "ask".
10 changes: 10 additions & 0 deletions plugins/launching-google-ai/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "launching-google-ai",
"version": "0.1.0",
"description": "Opens Google Gemini or Google Stitch in the browser with a pre-filled prompt and optional Gemini tool (image, video, music, deep research, canvas, guided learning). Use when asked to 'ask Gemini', 'open Gemini with', 'stitch this', 'use deep research on', 'generate a video in Gemini', or otherwise launch a prefilled Gemini or Stitch session via URL parameters from the shell. Does not auto-submit — only pre-fills the prompt box.",
"author": {
"name": "Wesley O. Nichols",
"email": "wes@nothingfancy.ai",
"url": "https://nothingfancy.ai"
}
}
52 changes: 52 additions & 0 deletions plugins/launching-google-ai/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# launching-google-ai

Opens Google Gemini or Google Stitch in the browser with a pre-filled prompt and optional Gemini tool selection (image, video, music, deep research, canvas, guided learning).

## What it does

- Builds the right URL for Gemini (`https://gemini.google.com/?prompt=...&tool=...`) or Stitch (`https://stitch.withgoogle.com/?prompt=...`).
- Picks the correct Gemini tool alias from natural-language cues — "research this" → `tool=research`, "make a video of" → `tool=video`, "generate an image of" → `tool=image`.
- URL-encodes the prompt safely, including newlines (`%0A`) and special characters.
- Honors `$BROWSER` (so users can route to a specific Chrome profile or browser binary), falling back to `xdg-open`.
- Stops at pre-fill — never auto-submits, so the user keeps a final-edit step.

## Usage

### Claude Code

```sh
claude --plugin-dir ./plugins/launching-google-ai
```

Or via the marketplace, once installed.

### pi

```sh
pi -e ./plugins/launching-google-ai # ephemeral
pi install ./plugins/launching-google-ai
```

### Codex

See the root [`.codex/INSTALL.md`](../../.codex/INSTALL.md).

## Harness support

| Feature | Claude Code | Codex | pi |
|---|---|---|---|
| Skill (SKILL.md) | ✅ | ✅ | ✅ |

Pure skill content — runs identically in all three harnesses. The only host requirement is a shell with `$BROWSER` or `xdg-open` available (Linux/macOS); on macOS, `open` works as a drop-in replacement for `xdg-open` and the skill will use it via `$BROWSER` if set.

## Evals

Regression cases live in [`../../evals/cases/launching-google-ai/cases.yaml`](../../evals/cases/launching-google-ai/cases.yaml).

```sh
uv run evals/framework/run.py --skill launching-google-ai
```

## License

[CC BY-SA 4.0](../../LICENSE) — made by [Nothing Fancy](https://nothingfancy.ai).
26 changes: 26 additions & 0 deletions plugins/launching-google-ai/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@nothingfancy/launching-google-ai",
"version": "0.1.0",
"description": "Opens Google Gemini or Google Stitch in the browser with a pre-filled prompt and optional Gemini tool selection.",
"keywords": [
"pi-package",
"agent-skill",
"gemini",
"stitch",
"google-ai",
"browser-launcher",
"url-prompt"
],
"author": {
"name": "Wesley O. Nichols",
"email": "wes@nothingfancy.ai",
"url": "https://nothingfancy.ai"
},
"license": "CC-BY-SA-4.0",
"pi": {
"skills": ["./skills"]
},
"peerDependencies": {
"@mariozechner/pi-coding-agent": "*"
}
}
109 changes: 109 additions & 0 deletions plugins/launching-google-ai/skills/launching-google-ai/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
name: launching-google-ai
description: Opens Google Gemini or Google Stitch in the browser with a pre-filled prompt and optional Gemini tool (image, video, music, deep research, canvas, guided learning). Use when asked to "ask Gemini", "open Gemini with", "stitch this", "use deep research on", "generate a video in Gemini", or otherwise launch a prefilled Gemini or Stitch session via URL parameters from the shell. Does not auto-submit — only pre-fills the prompt box.
---

# Launching Google AI

Opens a Google Gemini or Google Stitch session in the user's browser with a prompt already typed in the box and (for Gemini) a tool already selected. The skill exists because the user wants to hand off to a hosted UI for the next step — usually a multi-modal session, a deep-research run, or a Stitch design loop — without retyping context.

The guiding principle: **build the URL, open it, stop.** Don't auto-submit. The user owns the final edit and the send button, every time.

## When to Use

- The user says "ask Gemini …", "open Gemini with …", "in Gemini, …", "fire up Gemini for …".
- The user says "stitch …", "stitch this …", "open Stitch with …", or names a UI mockup task they want Stitch to handle.
- The user wants a specific Gemini tool: "deep research X", "use canvas to …", "generate a video of …", "generate an image of …", "make some music about …", "guided learning for …".
- The user wants to take prompt text already in the conversation and continue it in a hosted Google AI UI.

## When NOT to Use

- The user wants to **call the Gemini API or Vertex AI** programmatically — that's an SDK task, not a URL launcher.
- The user wants to **write or refine** a prompt for Gemini image generation — use `nano-banana-prompting`.
- The user wants to **write or refine** a prompt for Gemini TTS — use `gemini-tts-prompting`.
- The user wants the model's actual answer in this conversation — answer it here; don't bounce them to the web UI.
- The user wants Google AI Studio, NotebookLM, or another Google surface — those are not covered (Gemini and Stitch only).
- The user wants the browser to **submit** automatically — that's outside this skill's contract and the underlying URL parameters do not support it.

## URL Patterns

### Gemini (default)

```
https://gemini.google.com/?prompt=<encoded_text>
https://gemini.google.com/?prompt=<encoded_text>&tool=<tool_alias>
```

### Stitch

```
https://stitch.withgoogle.com/?prompt=<encoded_text>
```

Stitch does not accept a `tool` parameter. Adding one is a silent no-op at best; treat it as a hard error and omit it.

## Gemini Tool Aliases

Pick the alias from natural-language cues. The aliases on the right are what go in `&tool=<alias>` — use the short form, not the human label.

| User cue | Tool | Alias |
|---|---|---|
| "generate an image", "draw", "make a picture" | Create image | `image` |
| "make a video", "generate a video", "animate" | Create video | `video` |
| "write a song", "compose music", "make music" | Create music | `music` |
| "deep research", "research this thoroughly", "comprehensive report on" | Deep research | `research` |
| "open canvas", "iterate in canvas", "use canvas for …" | Canvas | `canvas` |
| "teach me", "guided learning", "walk me through learning …" | Guided learning | `learn` |

If the user's intent doesn't clearly match one of these, omit the `tool` parameter — Gemini will pick a sensible default.

## Building the URL

1. **Pick the surface.** Default to Gemini. Switch to Stitch only when the user explicitly says Stitch or describes a UI/mockup design task that fits Stitch's scope.
2. **Pick the tool** (Gemini only) using the alias table above. If unsure, omit it.
3. **URL-encode the prompt** using standard percent-encoding. Newlines become `%0A`. Spaces can be `%20` or `+` (prefer `%20` for readability). Pass raw text — the receiving page handles HTML escaping.
4. **Assemble**: `?prompt=<encoded>` first, then `&tool=<alias>` if present.

## Opening the URL

```sh
${BROWSER:-xdg-open} "<url>"
```

Honor `$BROWSER` so the user can route to a specific browser or profile. Common pattern:

```sh
export BROWSER="google-chrome --profile-directory='Profile 1'"
```

On macOS, users typically set `$BROWSER` to `open` or to a specific app bundle path. Don't hardcode `xdg-open` without the `${BROWSER:-…}` fallback — it breaks Mac users.

## Worked Example

User: *"ask gemini to research the history of LISP"*

1. Surface: Gemini (default).
2. Tool: "research" → `research`.
3. Encode prompt `the history of LISP` → `the%20history%20of%20LISP`.
4. URL: `https://gemini.google.com/?prompt=the%20history%20of%20LISP&tool=research`.
5. Open: `${BROWSER:-xdg-open} "https://gemini.google.com/?prompt=the%20history%20of%20LISP&tool=research"`.

User: *"stitch a clean SaaS pricing page with three tiers"*

1. Surface: Stitch (explicit).
2. Tool: omit (Stitch does not support `tool`).
3. Encode prompt `a clean SaaS pricing page with three tiers` → `a%20clean%20SaaS%20pricing%20page%20with%20three%20tiers`.
4. URL: `https://stitch.withgoogle.com/?prompt=a%20clean%20SaaS%20pricing%20page%20with%20three%20tiers`.
5. Open with `${BROWSER:-xdg-open}`.

## Anti-patterns

| Anti-pattern | Signal | Fix |
|---|---|---|
| Auto-submitting the prompt | The skill tries to script a click or send-key after opening the URL | Pre-fill is the contract. Stop at the URL — the user submits. |
| Using `?q=` instead of `?prompt=` | URL has `?q=…` | The Gemini/Stitch URL contract is `prompt=`. `q=` does not pre-fill. |
| Adding `tool=` to a Stitch URL | URL is `stitch.withgoogle.com/?prompt=…&tool=…` | Drop the `tool=` — Stitch ignores it (and "ignore" is a generous read). |
| Hardcoding the browser | `xdg-open` or `chromium` literal in the command | Use `${BROWSER:-xdg-open}` — Mac and per-profile users depend on it. |
| Translating tool names | `&tool=Create%20image` | Use the short alias (`image`, `video`, `research`, etc.), not the human label. |
| Re-typing prompt content into the URL | Prompt in URL diverges from what the user said | Encode the user's prompt verbatim; only normalize whitespace. |
| Fabricating an unsupported tool | `&tool=summarize`, `&tool=translate`, etc. | Only the six aliases in the table are real. If the user wants something else, omit `tool=` entirely. |
Loading
Loading