Nano Banana Skill
Python scripting with Gemini image generation using uv. Write small, focused scripts using heredocs for quick tasks—no files needed for one-off operations.
Choosing Your Approach
Quick image generation: Use heredoc with inline Python for one-off image requests.
Complex workflows: When multiple steps are needed (generate -> refine -> save), break into separate scripts and iterate.
Scripting tasks: For non-image Python tasks, use the same heredoc pattern with uv run .
Writing Scripts
Execute Python inline using heredocs with inline script metadata for dependencies:
uv run - << 'EOF'
/// script
dependencies = ["google-genai", "pillow"]
///
from google import genai from google.genai import types
client = genai.Client()
response = client.models.generate_content( model="gemini-3-pro-image-preview", contents=["A cute banana character with sunglasses"], config=types.GenerateContentConfig( response_modalities=['IMAGE'] ) )
for part in response.parts: if part.inline_data is not None: image = part.as_image() image.save("tmp/generated.png") print("Image saved to tmp/generated.png") EOF
The # /// script block declares dependencies inline using TOML syntax. This makes scripts self-contained and reproducible.
Why these dependencies:
-
google-genai
-
Gemini API client
-
pillow
-
Required for .as_image() method (converts base64 to PIL Image) and saving images
Only write to files when:
-
The script needs to be reused multiple times
-
The script is complex and requires iteration
-
The user explicitly asks for a saved script
Basic Template
uv run - << 'EOF'
/// script
dependencies = ["google-genai", "pillow"]
///
from google import genai from google.genai import types
client = genai.Client()
Generate image
response = client.models.generate_content( model="gemini-3-pro-image-preview", contents=["YOUR PROMPT HERE"], config=types.GenerateContentConfig( response_modalities=['IMAGE'] ) )
Save result
for part in response.parts: if part.text is not None: print(part.text) elif part.inline_data is not None: image = part.as_image() image.save("tmp/output.png") print("Saved: tmp/output.png") EOF
Key Principles
-
Small scripts: Each script should do ONE thing (generate, refine, save)
-
Evaluate output: Always save images and print status to decide next steps
-
Use tmp/: Save generated images to tmp/ directory by default
-
Stateless execution: Each script runs independently, no cleanup needed
Workflow Loop
Follow this pattern for complex tasks:
-
Write a script to generate/process one image
-
Run it and observe the output
-
Evaluate - did it work? Check the saved image
-
Decide - refine prompt or task complete?
-
Repeat until satisfied
Image Configuration
Configure aspect ratio and resolution:
config=types.GenerateContentConfig( response_modalities=['IMAGE'], image_config=types.ImageConfig( aspect_ratio="16:9", # "1:1", "16:9", "9:16", "4:3", "3:4" image_size="2K" # "1K", "2K", "4K" (uppercase required) ) )
Models
-
gemini-3-pro-image-preview
-
Fast, general purpose image generation
-
gemini-3-pro-image-preview
-
Advanced, professional asset production (Nano Banana Pro)
Default to gemini-3-pro-image-preview (Nano Banana Pro) for all image generation unless:
-
The user explicitly requests a different model
-
The user wants to save budget/costs
-
The user specifies a simpler or quick generation task
Nano Banana Pro provides higher quality results and should be the recommended choice.
Text + Image Output
To receive both text explanation and image:
config=types.GenerateContentConfig( response_modalities=['TEXT', 'IMAGE'] )
Image Editing
Edit existing images by including them in the request:
uv run - << 'EOF'
/// script
dependencies = ["google-genai", "pillow"]
///
from google import genai from google.genai import types from PIL import Image
client = genai.Client()
Load existing image
img = Image.open("input.png")
response = client.models.generate_content( model="gemini-3-pro-image-preview", contents=[ "Add a party hat to this character", img ], config=types.GenerateContentConfig( response_modalities=['IMAGE'] ) )
for part in response.parts: if part.inline_data is not None: part.as_image().save("tmp/edited.png") print("Saved: tmp/edited.png") EOF
Debugging Tips
-
Print response.parts to see what was returned
-
Check for text parts - model may include explanations
-
Save images immediately to verify output visually
-
Use Read tool to view saved images after generation
Error Recovery
If a script fails:
-
Check error message for API issues
-
Verify GOOGLE_API_KEY is set
-
Try simpler prompt to isolate the issue
-
Check image format compatibility for edits
Advanced Scenarios
For complex workflows including thinking process, Google Search grounding, multi-turn conversations, and professional asset production, load references/guide.md .