How to Perform Prompt Chaining for Complex Workflows with GPT-Image2

GPT-Image2 enables complex prompt chaining by treating prompts as reusable code fragments that can be composed, executed sequentially, and persisted via local state management, allowing the output of one generation to become the input reference for the next.

Prompt chaining in the freestylefly/awesome-gpt-image-2 repository leverages a Prompt-as-Code engine to build sophisticated, multi-step image generation workflows. By combining atomic prompt fragments from the style library with asynchronous generation clients, you can create linear pipelines, branching paths, and conditional logic that transform simple text prompts into elaborate visual productions.

Understanding the Prompt-as-Code Architecture

The repository implements a modular system where prompts are constructed programmatically rather than handwritten as monolithic strings. This architecture separates concerns between content definition, generation orchestration, and state persistence.

The Style Library System

All atomic prompt fragments—spanning subjects, lighting conditions, materials, and layout specifications—reside in data/style-library.json. These fragments are exposed through the Style Library Skill located at agents/skills/gpt-image-2-style-library, allowing programmatic concatenation of prompt components.

// Example: Building a composite prompt from the style library
const basePrompt = `${style.library['photo'].subject} ${style.library['photo'].lighting}`;

This approach eliminates repetitive typing and ensures consistency across chain steps, as each fragment can be reused and referenced by key.

The APIMart Generation Client

The core interaction layer lives in src/apimartClient.js, which wraps the APIMart asynchronous image API. Key functions include:

  • submitPersonalGeneration(prompt, apiKey, lang) – Initiates generation and returns a taskId
  • fetchPersonalTask(taskId, apiKey, lang) – Retrieves current task status
  • pollApimartTask(fetchFn) – Polls until completion, returning the final result object containing the image URL

These functions return stable CDN URLs (accessible per provider_result_expires_at) that serve as the linkage mechanism between chain steps.

Implementing Basic Prompt Chains

A simple two-step chain demonstrates the fundamental pattern: generate a base image, store the result, and reference it in a subsequent prompt.

import {
  submitPersonalGeneration,
  fetchPersonalTask,
  pollApimartTask,
  saveGeneratedTest,
  getSavedGeneration
} from './apimartClient.js';

const API_KEY = 'your-apimart-key';

// Step 1: Generate base image
const firstPrompt = 'portrait of a futuristic engineer, cinematic lighting, high detail';
const { taskId: id1 } = await submitPersonalGeneration(firstPrompt, API_KEY, 'en');
const result1 = await pollApimartTask(() => fetchPersonalTask(id1, API_KEY, 'en'));

// Step 2: Persist and reference in next generation
await saveGeneratedTest('step-1', { image: result1.image, savedAt: Date.now() });

const secondPrompt = `
  Create a close-up of the face from the previous image,
  emphasizing eyes and neon reflections.
  Reference image: ${result1.image}
`;

const { taskId: id2 } = await submitPersonalGeneration(secondPrompt, API_KEY, 'en');
const result2 = await pollApimartTask(() => fetchPersonalTask(id2, API_KEY, 'en'));
console.log('Final output:', result2.image);

The saveGeneratedTest function stores intermediate results using the localStorage key gpt-image-2-generated-tests:v1, making the workflow resilient to page reloads.

Building Advanced Workflow Patterns

Beyond linear sequences, the client supports complex control flow patterns including loops, branching, and conditional execution.

Loop-Based Sequential Processing

For workflows requiring consistent transformation across multiple stages, implement a generic chain runner that iterates over an array of prompt templates:

async function runChain(prompts, apiKey, lang = 'en') {
  let previousImage = null;
  
  for (let i = 0; i < prompts.length; i++) {
    // Append previous image reference if available
    const prompt = previousImage
      ? `${prompts[i]}\nReference image: ${previousImage}`
      : prompts[i];
      
    const { taskId } = await submitPersonalGeneration(prompt, apiKey, lang);
    const task = await pollApimartTask(() => fetchPersonalTask(taskId, apiKey, lang));
    
    previousImage = task.image;
    await saveGeneratedTest(`step-${i + 1}`, { 
      image: previousImage, 
      savedAt: Date.now() 
    });
  }
  
  return previousImage;
}

// Usage: Progressive zoom into a cyberpunk scene
const prompts = [
  'A cyber-punk city skyline at dusk, wide angle',
  'Zoom into a street level view, focus on neon signs',
  'Add a rain-slick surface and reflective puddles'
];

const finalImage = await runChain(prompts, API_KEY);

Branching and Parallel Generation

The system supports non-linear workflows by allowing multiple chains to fork from a single intermediate result. After retrieving a stored generation via getSavedGeneration, you can spawn parallel processes:

// Retrieve base generation from storage
const baseResult = await getSavedGeneration('step-1');
const baseImage = baseResult.image;

// Branch A: Add fiery elements
const variantA = await submitPersonalGeneration(
  `Add fiery breath to the dragon\nReference image: ${baseImage}`,
  API_KEY,
  'en'
);

// Branch B: Add icy elements  
const variantB = await submitPersonalGeneration(
  `Add icy crystals to the dragon\nReference image: ${baseImage}`,
  API_KEY,
  'en'
);

// Resolve both branches concurrently
const [resultA, resultB] = await Promise.all([
  pollApimartTask(() => fetchPersonalTask(variantA.taskId, API_KEY, 'en')),
  pollApimartTask(() => fetchPersonalTask(variantB.taskId, API_KEY, 'en'))
]);

State Management with Local Storage

Long-running workflows rely on helper functions defined in src/apimartClient.js (lines 54-99) to maintain state across sessions:

  • savePendingGeneration(id, data) – Stores in-flight tasks using key gpt-image-2-pending-tests:v1
  • getPendingGeneration(id) – Retrieves pending task data
  • saveGeneratedTest(id, data) – Archives completed results
  • getSavedGeneration(id) – Retrieves historical generations for chain resumption

This persistence layer enables complex workflows that span multiple browser sessions or survive network interruptions.

Complete Implementation Examples

The following production-ready pattern combines error handling, conditional logic, and multi-step refinement:

async function advancedWorkflow(initialConcept, apiKey) {
  const steps = [];
  
  try {
    // Step 1: Concept generation
    const conceptPrompt = `Generate base concept art: ${initialConcept}`;
    const { taskId: t1 } = await submitPersonalGeneration(conceptPrompt, apiKey, 'en');
    const result1 = await pollApimartTask(() => fetchPersonalTask(t1, apiKey, 'en'));
    
    if (result1.status !== 'completed') throw new Error('Step 1 failed');
    await saveGeneratedTest('concept', { image: result1.image, savedAt: Date.now() });
    steps.push(result1.image);
    
    // Step 2: Detail enhancement
    const detailPrompt = `Enhance details and add texture to: ${result1.image}`;
    const { taskId: t2 } = await submitPersonalGeneration(detailPrompt, apiKey, 'en');
    const result2 = await pollApimartTask(() => fetchPersonalTask(t2, apiKey, 'en'));
    
    steps.push(result2.image);
    
    // Step 3: Final lighting pass
    const finalPrompt = `Apply cinematic lighting to previous result: ${result2.image}`;
    const { taskId: t3 } = await submitPersonalGeneration(finalPrompt, apiKey, 'en');
    const result3 = await pollApimartTask(() => fetchPersonalTask(t3, apiKey, 'en'));
    
    return {
      success: true,
      images: [...steps, result3.image],
      finalImage: result3.image
    };
    
  } catch (error) {
    console.error('Chain interrupted:', error);
    return { success: false, completedSteps: steps };
  }
}

Summary

  • Prompt-as-Code Architecture: The data/style-library.json file and Style Library Skill enable programmatic construction of complex prompts from reusable atomic fragments.

  • Async Generation Pattern: Functions in src/apimartClient.js (submitPersonalGeneration, pollApimartTask, fetchPersonalTask) handle the APIMart API communication and return stable CDN URLs for chain linkage.

  • State Persistence: Local storage helpers (saveGeneratedTest, getSavedGeneration) using keys gpt-image-2-generated-tests:v1 and gpt-image-2-pending-tests:v1 maintain workflow continuity across sessions.

  • Flexible Control Flow: The client imposes no hard limits on chain length, supporting linear sequences, branching paths, and conditional logic based on task.status values.

  • Reference Mechanics: Each generation's image URL can be embedded in subsequent prompts using natural language references, enabling true image-to-image chaining.

Frequently Asked Questions

How does GPT-Image2 handle failures in the middle of a prompt chain?

The pollApimartTask function returns a status field that indicates completed or failed. You should wrap each generation step in try-catch blocks and inspect the status before proceeding. The local storage helpers allow you to resume from the last successful step by retrieving the previous image URL with getSavedGeneration.

Can I run multiple prompt chains simultaneously?

Yes. The APIMart client supports concurrent submissions. You can initiate multiple submitPersonalGeneration calls and resolve them with Promise.all(), or create branching workflows where a single base image feeds into multiple parallel refinement prompts, as each chain maintains independent taskId tracking.

What is the maximum length for a prompt chain in GPT-Image2?

The repository imposes no artificial limit on chain length. The only constraints are the async polling duration and the provider_result_expires_at timestamp on image URLs. As long as you persist intermediate results using saveGeneratedTest before the CDN links expire, chains can theoretically extend indefinitely.

Where are the intermediate images stored during a chain workflow?

Intermediate images remain hosted on the APIMart CDN, while their metadata and URLs are cached in browser localStorage under the keys gpt-image-2-generated-tests:v1 and gpt-image-2-pending-tests:v1. The src/apimartClient.js file provides abstraction functions to read and write these storage locations reliably.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →