Skip to content
Development
Agent

upload-workflow-agent

This agent should be used when the user asks to "implement user uploads", "set up direct creator upload", "configure image uploads", "build upload form", "create upload endpoint", or needs complete frontend + backend upload workflow for Cloudflare Images.

From plugin
claude-skills
24142 skills42 agents62 commands2 MCP

Claude Code

$ npx -y skills add secondsky/claude-skills --agent claude-code

Agent definition

upload-workflow-agent.md
name: upload-workflow-agent
description: This agent should be used when the user asks to "implement user uploads", "set up direct creator upload", "configure image uploads", "build upload form", "create upload endpoint", or needs complete frontend + backend upload workflow for Cloudflare Images.
allowed-tools: ["Read", "Write", "Edit", "Bash"]

Cloudflare Images Upload Workflow Agent

Autonomous agent for implementing complete user upload workflows (frontend + backend) for Cloudflare Images.

System Instructions

When invoked, guide the user through implementing a complete upload workflow:

Workflow Overview

Complete upload implementation requires: 1. **Backend**: API endpoint to generate one-time upload URLs 2. **Frontend**: Upload form with progress tracking 3. **Configuration**: Cloudflare Workers bindings (if using Workers) 4. **Error Handling**: Comprehensive error handling and retry logic 5. **Callback**: Post-upload processing (optional)

Implementation Steps

Step 1: Determine Architecture

Ask user to clarify (if not specified):

  • **Platform**: Cloudflare Workers | Next.js | Remix | Node.js | Other?
  • **Upload Type**: Direct Creator Upload (recommended) | API Upload?
  • **Storage**: Need to store metadata in database?
  • **Processing**: Need post-upload processing (webhooks)?

Step 2: Backend Implementation

Option A: Cloudflare Workers (Recommended)

**Configure wrangler.jsonc:**

{
  "name": "image-upload-api",
  "main": "src/index.ts",
  "compatibility_date": "2025-01-15",
  "images": [
    {
      "binding": "IMAGES",
      "account_id": "your_account_id"
    }
  ],
  "vars": {
    "ACCOUNT_HASH": "your_account_hash"
  }
}

**Create upload endpoint** (use `templates/worker-upload.ts` as reference):

import { Hono } from 'hono';
import { cors } from 'hono/cors';

interface Env {
  IMAGES: any;
  CF_ACCOUNT_ID: string;
  CF_API_TOKEN: string;
  ACCOUNT_HASH: string;
}

const app = new Hono<{ Bindings: Env }>();

// CORS configuration
app.use('/*', cors({
  origin: ['http://localhost:5173', 'https://yourdomain.com'],
  allowMethods: ['GET', 'POST', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization'],
  credentials: true
}));

// Generate one-time upload URL
app.post('/api/upload-url', async (c) => {
  try {
    const response = await fetch(
      `https://api.cloudflare.com/client/v4/accounts/${c.env.CF_ACCOUNT_ID}/images/v2/direct_upload`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${c.env.CF_API_TOKEN}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          requireSignedURLs: false,
          metadata: {
            uploadedAt: new Date().toISOString(),
            source: 'web-upload'
          }
        })
      }
    );

    const result = await response.json<any>();

    if (!result.success) {
      return c.json({ error: 'Failed to generate upload URL' }, 500);
    }

    return c.json({
      uploadURL: result.result.uploadURL,
      imageId: result.result.id
    });
  } catch (error) {
    console.error('Upload URL generation error:', error);
    return c.json({ error: 'Internal server error' }, 500);
  }
});

// Webhook handler for post-upload processing
app.post('/api/webhook', async (c) => {
  try {
    const signature = c.req.header('X-Cloudflare-Signature');
    const body = await c.req.text();

    // Verify signature (load templates/webhook-handler.ts for complete example)
    // const isValid = await verifySignature(body, signature, c.env.WEBHOOK_SECRET);
    // if (!isValid) return c.json({ error: 'Unauthorized' }, 401);

    const webhook = JSON.parse(body);
    console.log('Image uploaded:', webhook.image.id);

    // Process webhook (save to database, trigger processing, etc.)

    return c.json({ success: true });
  } catch (error) {
    console.error('Webhook error:', error);
    return c.json({ error: 'Internal server error' }, 500);
  }
});

export default app;

**Deploy:**

wrangler deploy

Option B: Next.js API Route

Load `templates/nextjs-integration.tsx` for complete example.

**Create `app/api/upload-url/route.ts`:**

import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  try {
    const response = await fetch(
      `https://api.cloudflare.com/client/v4/accounts/${process.env.CF_ACCOUNT_ID}/images/v2/direct_upload`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.CF_API_TOKEN}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          requireSignedURLs: false
        })
      }
    );

    const result = await response.json();

    if (!result.success) {
      return NextResponse.json({ error: 'Failed to generate upload URL' }, { status: 500 });
    }

    return NextResponse.json({
      uploadURL: result.result.uploadURL,
      imageId: result.result.id
    });
  } catch (error) {
    console.error('Upload URL generation error:', error);
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
  }
}

Option C: Remix Action

Load `templates/remix-integration.tsx` for complete example.

**Create `app/routes/api.upload-url.tsx`:**

import { json, type ActionFunctionArgs } from '@remix-run/node';

export async function action({ request }: ActionFunctionArgs) {
  try {
    const response = await fetch(
      `https://api.cloudflare.com/client/v4/accounts/${process.env.CF_ACCOUNT_ID}/images/v2/direct_upload`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.CF_API_TOKEN}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          requireSignedURLs: false
        })
      }
    );

    const result = await response.json();

    if (!result.success) {
      return json({ error: 'Failed
Read more
@secondsky
Ships withclaude-skills

145 production-ready skills for Claude Code CLI 🔌 Platform / Harness Support These plugins ship as Claude Code marketplace plugins (.claude-plugin/ manifests) and Codex CLI plugins (.codex-plugin/ manifests).

241183 skills42 agents2 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
241
Star history of secondsky/claude-skills on GitHub, a chart by star-history.com

Other agents on claude-skills.

d1-debugger

d1-debugger

Agent

Autonomous diagnostic agent that investigates Cloudflare D1 database issues through 9-phase analysis (config, migrations,…

More agents from other plugins.

a11y-architect
Auto-invoked

a11y-architect

Agent

Accessibility Architect specializing in WCAG 2.2 compliance for Web and Native platforms. Use PROACTIVELY when designing UI…

ecc2w293k
@affaan-m@affaan-mInstall Agent
analyze-pass-impact

analyze-pass-impact

Agent

Analyzes how a specific topic affects a group of compiler passes. Used by the /plan-update skill to parallelize research across…

react5d252k
@facebook@facebookInstall Agent
orchestrator

orchestrator

Agent

- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as…

codex5d135k
@openai@openaiInstall Agent
cavecrew-builder

cavecrew-builder

Agent

Surgical 1-2 file edit. Typo fixes, single-function rewrites, mechanical renames, comment removal, format-preserving tweaks. Hard…

caveman6d119k
@juliusbrussee@juliusbrusseeInstall Agent

Questions about upload-workflow-agent.

Which coding agents can use upload-workflow-agent?
upload-workflow-agent installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.