AI Image Generation with FLUX and OpenClaw: Building a Custom Skill

AI Image Generation with FLUX and OpenClaw: Building a Custom Skill

OpenClaw's extensible skill system lets you integrate any tool or API into your AI assistant workflow. In this tutorial, we'll walk through creating a custom skill that brings Black Forest Labs' FLUX image generation directly into OpenClaw.

What is FLUX?

FLUX is a family of state-of-the-art text-to-image models from Black Forest Labs (BFL), the team behind Stable Diffusion. The FLUX.2 lineup offers several models optimized for different use cases:

  • flux-2-pro — Best balance of quality and speed (recommended)
  • flux-2-max — Highest quality output, slower generation
  • flux-2-klein-4b — Fastest generation, good for iteration
  • flux-dev — Open model for experimentation

FLUX excels at photorealistic images, accurate text rendering, and following complex prompts with remarkable fidelity.

Prerequisites

Before we begin, you'll need:

  1. OpenClaw installed — Get it from openclaw.ai
  2. BFL API key — Sign up at api.bfl.ai
  3. Node.js 20+ — For the generation script

Step 1: Store Your API Key

First, let's securely store the BFL API key. Create a secrets directory in your OpenClaw workspace:

mkdir -p ~/.openclaw/workspace/.secrets
echo "your-api-key-here" > ~/.openclaw/workspace/.secrets/bfl.key
chmod 600 ~/.openclaw/workspace/.secrets/bfl.key

Step 2: Create the Skill Structure

OpenClaw skills follow a simple directory structure:

~/.openclaw/skills/flux/
├── SKILL.md              # Main skill file (required)
├── scripts/
│   └── flux-gen.js       # Generation script
└── references/
    └── prompting.md      # Prompting best practices

Create the directories:

mkdir -p ~/.openclaw/skills/flux/{scripts,references}

Step 3: Write the Generation Script

Create scripts/flux-gen.js:

#!/usr/bin/env node
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';

const API_BASE = 'https://api.bfl.ai/v1';
const MODELS = ['flux-2-pro', 'flux-2-max', 'flux-2-klein-4b', 'flux-dev'];

// Load API key
const keyPath = join(homedir(), '.openclaw/workspace/.secrets/bfl.key');
if (!existsSync(keyPath)) {
    console.error('Error: BFL API key not found at', keyPath);
    process.exit(1);
}
const API_KEY = readFileSync(keyPath, 'utf8').trim();

async function generateImage(prompt, width = 1024, height = 1024, model = 'flux-2-pro') {
    // Validate model
    if (!MODELS.includes(model)) {
        console.error(`Invalid model. Choose from: `);
        process.exit(1);
    }

    console.log(`Submitting to …`);
    
    // Submit request
    const submitRes = await fetch(`/`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-Key': API_KEY
        },
        body: JSON.stringify({
            prompt,
            width: Math.round(width / 32) * 32,  // Must be multiple of 32
            height: Math.round(height / 32) * 32
        })
    });

    if (!submitRes.ok) {
        const err = await submitRes.text();
        console.error('Submit failed:', err);
        process.exit(1);
    }

    const { id } = await submitRes.json();
    console.log('Request ID:', id);

    // Poll for result
    let result;
    while (true) {
        const pollRes = await fetch(`/get_result?id=`, {
            headers: { 'X-Key': API_KEY }
        });
        result = await pollRes.json();
        console.log('Status:', result.status);
        
        if (result.status === 'Ready') break;
        if (result.status === 'Error') {
            console.error('Generation failed:', result.error);
            process.exit(1);
        }
        await new Promise(r => setTimeout(r, 1000));
    }

    // Download and save
    console.log('Downloading…');
    const imgRes = await fetch(result.result.sample);
    const buffer = Buffer.from(await imgRes.arrayBuffer());
    
    const outDir = join(homedir(), '.openclaw/workspace/generated');
    mkdirSync(outDir, { recursive: true });
    
    const outPath = join(outDir, `flux_.jpg`);
    writeFileSync(outPath, buffer);
    console.log(outPath);
    
    return outPath;
}

// CLI
const [,, prompt, width, height, model] = process.argv;
if (!prompt) {
    console.log('Usage: flux-gen.js "prompt" [width] [height] [model]');
    console.log(`Models: `);
    process.exit(1);
}

generateImage(prompt, parseInt(width) || 1024, parseInt(height) || 1024, model || 'flux-2-pro');

Make it executable:

chmod +x ~/.openclaw/skills/flux/scripts/flux-gen.js

Step 4: Create the SKILL.md

The SKILL.md file tells OpenClaw when and how to use the skill. Create ~/.openclaw/skills/flux/SKILL.md:

—
name: flux
description: Generate images using FLUX AI models from Black Forest Labs. Use when asked to create, generate, or make images, artwork, illustrations, or visual content.
—

# FLUX Image Generation

Generate high-quality images using Black Forest Labs' FLUX models.

## Quick Usage

```bash
node ~/.openclaw/skills/flux/scripts/flux-gen.js "your prompt" [width] [height] [model]

Available Models

Model Best For Speed
flux-2-pro General use, balanced quality/speed Medium
flux-2-max Highest quality output Slow
flux-2-klein-4b Quick iterations, drafts Fast
flux-dev Experimentation Medium

Prompting Tips

  • Be specific and descriptive
  • Include style cues: "photorealistic", "digital art", "watercolor"
  • Specify lighting: "golden hour", "studio lighting", "dramatic shadows"
  • Define composition: "centered", "wide shot", "close-up portrait"
  • For dark backgrounds, specify hex colors: "#0d1117"

Dimensions

  • Width and height must be multiples of 32
  • Common sizes: 1024×1024, 1920×1080, 1024×1792 (portrait)
  • Max dimensions vary by model

Output

Generated images are saved to: ~/.openclaw/workspace/generated/flux_[timestamp].jpg


## Step 5: Add Prompting References

Create `references/prompting.md` with best practices:

```markdown
# FLUX Prompting Best Practices

## Structure Your Prompts

1. **Subject** — What is the main focus?
2. **Style** — Photorealistic, illustration, oil painting?
3. **Lighting** — Natural, studio, dramatic?
4. **Composition** — Close-up, wide shot, centered?
5. **Details** — Colors, textures, mood

## Example Prompts

**Tech visualization:**
> Abstract digital cloud computing visualization, flowing data streams, 
> network nodes connected by glowing blue lines (#58a6ff), dark background 
> (#0d1117), minimalist tech aesthetic, cinematic depth

**Portrait:**
> Professional headshot of a software developer, natural lighting, 
> neutral background, sharp focus, confident expression

**Product shot:**
> Modern laptop on minimal desk, soft window light from left, 
> clean white background, commercial photography style

Step 6: Register the Skill

Add your skills directory to OpenClaw's configuration. Edit ~/.openclaw/openclaw.json:

{
  "skills": {
    "load": {
      "extraDirs": ["/home/yourusername/.openclaw/skills"]
    },
    "entries": {
      "flux": {
        "enabled": true
      }
    }
  }
}

Restart OpenClaw to load the skill:

openclaw gateway restart

Using the Skill

Now you can simply ask OpenClaw to generate images:

"Generate an image of a futuristic city skyline at sunset"

OpenClaw will automatically invoke the FLUX skill, run the generation script, and return the path to your image.

Advanced: Banner Images

For website hero images, use wide aspect ratios:

node ~/.openclaw/skills/flux/scripts/flux-gen.js \
  "Abstract cloud computing visualization, blue glow on dark background" \
  1920 600 flux-2-pro

Conclusion

Custom skills transform OpenClaw from a chatbot into a powerful automation platform. The FLUX skill we built demonstrates the pattern:

  1. Secure credentials — Store API keys safely
  2. Wrapper script — Handle API calls and file I/O
  3. SKILL.md — Describe when to trigger and how to use
  4. References — Document best practices for the AI

This same pattern works for any API or CLI tool you want to integrate. OpenClaw's skill system is your gateway to infinite extensibility.


Ready to create more skills? Check out the OpenClaw documentation and share your creations on ClawHub.