# Claude Code vs Gemini: My Stateful Image Workflow

> Source: <https://promptcube3.com/en/threads/2817/>
> Published: 2026-07-24 16:50:14+00:00

# Claude Code vs Gemini: My Stateful Image Workflow

The problem with most image gen is that it's basically goldfish memory. You ask for a cyberpunk kitchen, it gives you one. You ask to add a ramen sign, and suddenly the kitchen is gone, the lighting changed, and the "cyberpunk" vibe shifted to "generic 90s sci-fi." It's stateless misery.

I've been using a setup that wraps `gemini-3.1-flash-lite-image`

(aka NB2Lite) into an [MCP](/en/tags/mcp/) server to feed it into Google Antigravity. Unlike the usual "prompt and pray" method, this uses the Interactions API, which actually maintains state. You generate an image, get an `interaction_id`

, and then you can just say "add a neon sign" without re-describing the entire room.

## The Technical Plumbing

The magic happens because the server handles the `interaction_id`

handoffs. If you're trying to build something similar, here is how the stateful loop actually functions:

1. Initial call: `client.interactions.create(prompt="...", store=True)`

2. Response: You get an `interaction_id`

.

3. Follow-up: You send the new prompt + `previous_interaction_id`

.

The server implementation I'm using (via FastMCP) basically abstracts this so the agent doesn't have to manage the IDs manually. Here is a snippet of how the tool definition looks in the `server.py`

logic:

```
# Example of how the stateful edit is handled in the MCP server
@mcp.tool()
async def edit_image(prompt: str, interaction_id: str):
    """Edits an existing image using its interaction ID to maintain visual state."""
    response = await client.interactions.create(
        prompt=prompt,
        previous_interaction_id=interaction_id,
        store=True
    )
    return {
        "image_url": response.url,
        "new_interaction_id": response.interaction_id
    }
```

## Real-World Constraints (The "Gotchas")

Since I'm the one actually dogfooding this while my team asks "why isn't it perfect yet," here are the specific technical walls you'll hit:

**The Aspect Ratio Trap:** You set the ratio (`1:1`

,`16:9`

, etc.) at the start. If you try to change it during a stateful edit, the pixel continuity falls apart. The server I'm using explicitly blocks aspect ratio changes during edits to prevent the model from hallucinating a new composition.**Thinking Levels:** The API documentation mentions`minimal`

and`medium`

thinking levels. In reality, if you send those to the flash-lite-image model, you get a crisp HTTP 400 error. Stick to`low`

for fast drafts and`high`

for when you actually need the text in the image to be readable.**ID Forking:** Every edit generates a*new*ID. If your agent accidentally references an ID from three turns ago, it doesn't error out—it just "forks" the image state back to that version, which is a nightmare to debug if you don't have logging enabled.

## Deployment Workflow

For those who want to stop wasting time with stateless prompts, the deployment is straightforward. You need the `nb2lite-skill-agy`

package, which acts as both the MCP server and the Antigravity skill definition.

1. Install the server dependencies.

2. Configure your [Gemini](/en/tags/gemini/) API key in the environment.

3. Link the MCP server to your Antigravity config.

Once that's done, the workflow changes from "Write a 50-word prompt describing every detail" to "Change the color of that chair to red." It's significantly faster, and I've managed to cut my "prompt tweaking" time by about 60% because I'm not fighting the model to keep the background consistent.

[Next System Design: Mastering Back-of-the-Envelope Estimation →](/en/threads/2801/)
