skills/aayushbaniya2006/ai-handler/SKILL.md
Integrate Replicate AI models with background processing, S3 storage, and credit systems
npx skillsauth add aiskillstore/marketplace ai-handlerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides a production-ready pattern for integrating Replicate AI models. It handles long-running predictions using Inngest background jobs, stores results in S3, manages user credits, and updates database state.
/api/app/ai-images).status: "processing".status: "completed".failed.replicate package installed (npm install replicate).REPLICATE_API_TOKEN in .env.src/app/api/app/generate/route.ts
import withAuthRequired from "@/lib/auth/withAuthRequired";
import { db } from "@/db";
import { generations } from "@/db/schema";
import { inngest } from "@/lib/inngest/client";
import { checkCredits, deductCredits } from "@/lib/credits"; // Hypothetical helpers
export const POST = withAuthRequired(async (req, { session }) => {
const body = await req.json();
// 1. Check Credits
const hasCredits = await checkCredits(session.user.id, "image_generation", 1);
if (!hasCredits) return new Response("Insufficient credits", { status: 403 });
// 2. Create DB Record (Pending)
const [record] = await db.insert(generations).values({
userId: session.user.id,
prompt: body.prompt,
status: "processing",
}).returning();
// 3. Deduct Credits (Optimistic)
await deductCredits(session.user.id, "image_generation", 1, { source: "api", refId: record.id });
// 4. Trigger Background Job
await inngest.send({
name: "app/ai.generate",
data: {
generationId: record.id,
prompt: body.prompt,
userId: session.user.id
}
});
return Response.json({ id: record.id, status: "processing" });
});
src/lib/inngest/functions/app/ai/generate.ts
import { inngest } from "@/lib/inngest/client";
import Replicate from "replicate";
import uploadFromServer from "@/lib/s3/uploadFromServer";
import { db } from "@/db";
import { generations } from "@/db/schema";
import { eq } from "drizzle-orm";
const replicate = new Replicate({ auth: process.env.REPLICATE_API_TOKEN });
export const generateAI = inngest.createFunction(
{ id: "ai-generation-worker", concurrency: 5 },
{ event: "app/ai.generate" },
async ({ event, step }) => {
const { generationId, prompt } = event.data;
try {
// 1. Call Replicate (Step ensures retries on network error)
const prediction = await step.run("call-replicate", async () => {
return await replicate.predictions.create({
version: "model-version-hash",
input: { prompt }
});
});
// 2. Wait for completion
// Replicate usually takes time. We can use waitForEvent if using webhooks,
// or simple polling loop with sleep if webhooks aren't set up.
// For simplicity, here is a polling pattern using sleep:
let finalPrediction = prediction;
while (finalPrediction.status !== "succeeded" && finalPrediction.status !== "failed") {
await step.sleep("wait-for-gpu", "5s");
finalPrediction = await step.run("check-status", () =>
replicate.predictions.get(prediction.id)
);
}
if (finalPrediction.status === "failed") {
throw new Error(finalPrediction.error);
}
// 3. Upload to S3
// Replicate returns a temporary URL. We must persist it.
const outputUrl = finalPrediction.output[0]; // Adjust based on model output
const s3Url = await step.run("upload-to-s3", async () => {
// Fetch image buffer
const response = await fetch(outputUrl);
const arrayBuffer = await response.arrayBuffer();
const base64 = Buffer.from(arrayBuffer).toString("base64");
// Use existing S3 skill
return await uploadFromServer({
file: base64,
path: `generations/${generationId}.png`,
contentType: "image/png"
});
});
// 4. Update DB
await step.run("update-db", async () => {
await db.update(generations)
.set({ status: "completed", url: s3Url })
.where(eq(generations.id, generationId));
});
} catch (error) {
// Handle Failure
await step.run("mark-failed", async () => {
await db.update(generations)
.set({ status: "failed" })
.where(eq(generations.id, generationId));
// Optional: Refund credits here
});
throw error; // Re-throw to show failure in Inngest dashboard
}
}
);
development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.