Upstash Qstash
davila7/claude-code-templates
Upstash QStash expert for serverless message queues, scheduled jobs, and reliable HTTP-based task delivery without managing infrastructure.
A skill your agent uses when developing, deploying, or debugging Butterbase serverless functions, or when the user needs to add backend logic like webhooks, scheduled jobs, or custom API endpoints
$ npx skills add butterbase-ai/butterbase-skills --skill function-dev -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install butterbase-ai/butterbase-skills function-dev --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/butterbase-ai/butterbase-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/function-dev .claude/skills/function-dev && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "function-dev" agent skill from https://github.com/butterbase-ai/butterbase-skills/tree/main/skills/function-dev into .claude/skills/function-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "function-dev", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/butterbase-ai/butterbase-skills/tree/main/skills/function-devType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add butterbase-ai/butterbase-skills --skill function-dev -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install butterbase-ai/butterbase-skills function-dev --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/butterbase-ai/butterbase-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/function-dev .agents/skills/function-dev && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "function-dev" agent skill from https://github.com/butterbase-ai/butterbase-skills/tree/main/skills/function-dev into .agents/skills/function-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "function-dev", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add butterbase-ai/butterbase-skills --skill function-dev -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install butterbase-ai/butterbase-skills function-dev --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/butterbase-ai/butterbase-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/function-dev .cursor/skills/function-dev && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "function-dev" agent skill from https://github.com/butterbase-ai/butterbase-skills/tree/main/skills/function-dev into .cursor/skills/function-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "function-dev", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/butterbase-ai/butterbase-skills.git --path skills/function-dev--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add butterbase-ai/butterbase-skills --skill function-dev -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install butterbase-ai/butterbase-skills function-dev --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/butterbase-ai/butterbase-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/function-dev .gemini/skills/function-dev && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "function-dev" agent skill from https://github.com/butterbase-ai/butterbase-skills/tree/main/skills/function-dev into .gemini/skills/function-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "function-dev", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install butterbase-ai/butterbase-skills function-devInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add butterbase-ai/butterbase-skills --skill function-dev -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/butterbase-ai/butterbase-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/function-dev .github/skills/function-dev && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "function-dev" agent skill from https://github.com/butterbase-ai/butterbase-skills/tree/main/skills/function-dev into .github/skills/function-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "function-dev", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add butterbase-ai/butterbase-skills --skill function-dev -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install butterbase-ai/butterbase-skills function-dev --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/butterbase-ai/butterbase-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/function-dev .opencode/skills/function-dev && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "function-dev" agent skill from https://github.com/butterbase-ai/butterbase-skills/tree/main/skills/function-dev into .opencode/skills/function-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "function-dev", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
function-devA skill your agent uses when developing, deploying, or debugging Butterbase serverless functions, or when the user needs to add backend logic like webhooks, scheduled jobs, or custom API endpoints
Function Dev is an agent skill from butterbase-ai/butterbase-skills. Use when developing, deploying, or debugging Butterbase serverless functions, or when the user needs to add backend logic like webhooks, scheduled jobs, or custom API endpoints
Its SKILL.md is about 2.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering Serverless, Webhooks and REST APIs. The repository describes itself as: Plugin for Butterbase.ai. The licence is MIT.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit aa8ae69. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript and json).
From the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
api.openai.comapi.butterbase.aiFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
OPENAI_API_KEYWEBHOOK_SECRETFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Function Dev loads about 2.8k tokens when it runs. Until then it costs about 47 tokens; SKILL.md has 619 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from butterbase-ai/butterbase-skills at commit aa8ae69, republished under its MIT licence (© butterbase-ai). 619 words, ~2,773 tokens.
.claude/skills/function-dev/SKILL.md (or your agent's skills folder).Guide for developing and deploying serverless functions on Butterbase's Deno runtime. Covers handler signatures, trigger types, database access, environment variables, and testing.
Every function exports a single handler function with this signature:
export async function handler(
request: Request,
context: {
db: PostgresClient, // RLS-aware DB client
env: Record<string, string>, // env vars set on the function
user: { id: string } | null, // present for HTTP+auth:required; null for cron
waitUntil: (p: Promise<unknown>) => void, // background work after Response (≤30s)
idempotency: {
claim: (key: string, opts?: { scope?: string; ttlSeconds?: number }) => Promise<boolean>
} // atomic dedup for webhook retries
}
): Promise<Response>CRITICAL: The handler MUST return new Response() (Web API standard). Do NOT return plain objects.
Correct:
return new Response(JSON.stringify({ message: "ok" }), {
status: 200,
headers: { "Content-Type": "application/json" }
});Wrong (will fail):
return { status: 200, body: "ok" }; // NOT a Response object!Invoke the function via an HTTP request.
{
"trigger": {
"type": "http",
"config": { "method": "POST", "path": "/my-endpoint", "auth": "required" }
}
}Auth options:
"required" — request must include a valid JWT; ctx.user is always set"optional" — JWT is parsed if present; ctx.user may be null"none" — public endpoint; no auth needed; ctx.user is always nullExecute the function on a schedule.
{
"trigger": {
"type": "cron",
"config": { "schedule": "0 9 * * *", "timezone": "UTC" }
}
}Uses standard 5-field cron expressions:
"*/5 * * * *" — every 5 minutes"0 0 * * 0" — weekly, Sunday at midnight"0 3 * * *" — daily at 3am UTC"0 9 * * 1-5" — weekdays at 9amCron functions run as butterbase_service (RLS bypassed). ctx.user is always null.
Fire when a connected client sends a matching event over the realtime WebSocket.
{
"trigger": {
"type": "websocket",
"config": { "event": "chat-message" }
}
}Fires when client sends matching event via realtime WebSocket connection. The request body contains the event payload sent by the client.
{
"trigger": {
"type": "s3_upload",
"config": { "prefix": "uploads/", "contentTypes": ["image/*"] }
}
}Use ctx.db.query(sql, params) for all database queries. Always use parameterized queries to prevent SQL injection — NEVER use string interpolation.
// Always use $1, $2 placeholders — never string interpolation
const { rows } = await ctx.db.query(
'SELECT * FROM posts WHERE author_id = $1',
[ctx.user.id] // params array
);const { rows } = await ctx.db.query(
'SELECT * FROM posts WHERE author_id = $1 AND published = true',
[ctx.user.id]
);await ctx.db.query(
'INSERT INTO logs (event, user_id) VALUES ($1, $2)',
['page_view', ctx.user.id]
);await ctx.db.query(
'UPDATE posts SET title = $1, updated_at = now() WHERE id = $2 AND author_id = $3',
[newTitle, postId, ctx.user.id]
);| Invocation | Role | RLS |
|---|---|---|
| End-user JWT | butterbase_user | Enforced — ctx.db queries filtered by policies |
API key (bb_sk_) | butterbase_service | Bypassed — sees all data |
| Cron trigger | butterbase_service | Bypassed — sees all data |
envVars parameter to deploy_functionupdate_function_envctx.env.VARIABLE_NAMECommon uses: API keys, webhook secrets, external service URLs.
const apiKey = ctx.env.OPENAI_API_KEY;
const webhookSecret = ctx.env.WEBHOOK_SECRET;
const serviceUrl = ctx.env.EXTERNAL_SERVICE_URL;Returns the authenticated user's posts.
export async function handler(req, ctx) {
const { rows } = await ctx.db.query(
'SELECT id, title, created_at FROM posts WHERE author_id = $1 ORDER BY created_at DESC',
[ctx.user.id]
);
return new Response(JSON.stringify(rows), {
headers: { "Content-Type": "application/json" }
});
}Deploy:
deploy_function(
app_id,
name: "my-posts",
code: ...,
trigger: {
type: "http",
config: { method: "GET", path: "/my-posts", auth: "required" }
}
)Accepts an incoming webhook, validates the signature, and stores the event.
export async function handler(req, ctx) {
const body = await req.json();
const signature = req.headers.get("x-webhook-signature");
// Validate signature against ctx.env.WEBHOOK_SECRET
await ctx.db.query(
'INSERT INTO webhook_events (event_type, payload) VALUES ($1, $2)',
[body.type, JSON.stringify(body)]
);
return new Response("ok", { status: 200 });
}Deploy with: trigger: { type: "http", config: { method: "POST", path: "/webhook", auth: "none" } }
Deletes expired sessions on a nightly schedule.
export async function handler(req, ctx) {
const result = await ctx.db.query(
"DELETE FROM sessions WHERE expires_at < now() RETURNING id"
);
return new Response(JSON.stringify({ deleted: result.rowCount }), {
headers: { "Content-Type": "application/json" }
});
}Deploy with: trigger: { type: "cron", config: { schedule: "0 3 * * *" } }
Proxies a request to an external AI service using a stored API key.
export async function handler(req, ctx) {
const { prompt } = await req.json();
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${ctx.env.OPENAI_API_KEY}`
},
body: JSON.stringify({
model: "gpt-4",
messages: [{ role: "user", content: prompt }]
})
});
const data = await response.json();
return new Response(JSON.stringify(data), {
headers: { "Content-Type": "application/json" }
});
}Deploy with envVars: { OPENAI_API_KEY: "sk-..." } and trigger: { type: "http", config: { method: "POST", auth: "required" } }
Always wrap handler logic in try/catch and return a proper error Response.
export async function handler(req, ctx) {
try {
const { id } = await req.json();
const { rows } = await ctx.db.query(
'SELECT * FROM items WHERE id = $1',
[id]
);
if (rows.length === 0) {
return new Response(JSON.stringify({ error: "Not found" }), {
status: 404,
headers: { "Content-Type": "application/json" }
});
}
return new Response(JSON.stringify(rows[0]), {
status: 200,
headers: { "Content-Type": "application/json" }
});
} catch (err) {
return new Response(JSON.stringify({ error: "Internal server error" }), {
status: 500,
headers: { "Content-Type": "application/json" }
});
}
}The standalone tools deploy_function and invoke_function are unchanged. Everything else (logs, env updates, listing, deletion) is handled by manage_function with an action parameter.
invoke_function(
app_id: "app_abc123",
function_name: "my-function",
method: "POST",
body: { key: "value" }
)Returns the full HTTP response (status, headers, body, duration_ms). Use this immediately after deploying to verify behavior.
manage_function(
app_id: "app_abc123",
action: "get_logs",
function_name: "my-function",
level: "error"
)Returns recent invocations with errors, stack traces, and captured console.log/warn/error output.
manage_function(
app_id: "app_abc123",
action: "get_logs",
function_name: "my-function",
limit: 100,
since: "2026-01-15T00:00:00Z"
)Filters: limit (default 100), since (ISO timestamp), level ("error" or "all").
manage_function(app_id: "app_abc123", action: "list")Returns each function's name, trigger, URL, status, and metrics (invocationCount, errorRate, avgDuration, lastInvoked).
| Mistake | Fix |
|---|---|
Returning plain object instead of Response | Always use new Response(JSON.stringify(data), { headers: {...} }) |
| SQL injection via string interpolation | Use parameterized queries: $1, $2 placeholders |
| Not wrapping in try/catch | Always catch errors and return a Response with error status |
Forgetting async on handler | Handler must be async function handler(...) |
| Exceeding timeout (30s default) | Increase timeoutMs in deploy_function or optimize the function |
| Not setting Content-Type header | Always include "Content-Type": "application/json" for JSON responses |
deploy_function(
app_id: "app_abc123",
name: "my-function",
code: "export async function handler(req, ctx) { ... }",
trigger: { type: "http", config: { method: "POST", auth: "required" } },
envVars: { MY_SECRET: "value" },
timeoutMs: 30000, // default: 30s, max: 300s
memoryLimitMb: 128 // default: 128MB
)manage_function(
app_id: "app_abc123",
action: "update_env",
function_name: "my-function",
env: { MY_SECRET: "new-value", DELETE_ME: null } // null deletes the key
)manage_function(
app_id: "app_abc123",
action: "delete",
function_name: "my-function"
)https://api.butterbase.ai/v1/{app_id}/fn/{function-name}For HTTP triggers, this is the URL clients call directly.
If a docs/butterbase/00-state.md exists in the working directory, prefer invoking via /butterbase-skills:journey-functions so the journey orchestrator stays in sync.
© butterbase-ai, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/function-dev of butterbase-ai/butterbase-skills.
Open the folder on GitHubat commit aa8ae69
Function Dev next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Function Dev this skillbutterbase-ai/butterbase-skills | 534 | — | ~2.8k | Automated safety check: Pass | MIT | |
| Upstash Qstashdavila7/claude-code-templates | 32k | 5 repos | ~597 | Automated safety check: Pass | MIT | |
| NubaseOtterMind/Nubase | 623 | — | ~2.2k | Automated safety check: Notes | Apache-2.0 | |
| Polylith Base CreationDavidVujic/python-polylith | 553 | — | ~757 | Automated safety check: Pass | MIT | |
| Frappe App Devfrappe/skills | 146 | — | ~943 | Automated safety check: Pass | None | |
| Workspace APIfriday-platform/friday-studio | 104 | — | ~9.3k | Automated safety check: Notes | Custom licence |
davila7/claude-code-templates
Upstash QStash expert for serverless message queues, scheduled jobs, and reliable HTTP-based task delivery without managing infrastructure.
OtterMind/Nubase
A skill your agent uses when the user mentions Nubase broadly, wants a backend for an AI-generated app, or needs to deploy/publish generated code online — across Database, Auth, Storage, Assets…
DavidVujic/python-polylith
Create a Polylith base with poly create base — the entry point of a deployable application (HTTP API, CLI, message-queue consumer, AWS Lambda handler, GCP Cloud Function, scheduled job).
frappe/skills
Builds full-stack Frappe Framework applications end-to-end. An agent skill from frappe/skills.
friday-platform/friday-studio
Create, list, update, delete, and clean up workspaces via the daemon HTTP API at $FRIDAYDURL.
neondatabase/agent-skills
Long-running, serverless Node.js HTTP functions deployed onto your Neon branch, with DATABASEURL injected automatically and compute that runs next to your data.
butterbase-ai/butterbase-skills
A skill your agent uses when calling the app's AI gateway from agent tools — chat completions, embeddings, listing models, configuring defaults or BYOK, reading token/cost usage
butterbase-ai/butterbase-skills
A skill your agent uses when configuring OAuth providers (Google/GitHub/Apple/X/etc.), setting up post-login auth hooks, tuning JWT lifetimes, or generating service API keys
butterbase-ai/butterbase-skills
A skill your agent uses when building a new Butterbase app from scratch, creating a full-stack application, or when the user asks to set up a complete backend with database, auth, and deployment
butterbase-ai/butterbase-skills
A skill your agent uses when contributing to the Butterbase codebase, adding new MCP tools, creating API routes, writing migrations, or understanding the monorepo architecture
butterbase-ai/butterbase-skills
A skill your agent uses when users report access denied errors, see wrong data, RLS policies are not working, or when troubleshooting Row-Level Security issues in Butterbase
butterbase-ai/butterbase-skills
A skill your agent uses when deploying a frontend (React, Next.js, or static HTML) to a live URL on Butterbase, or when troubleshooting deployment issues like MIME type errors or blank pages
Categories
A skill your agent uses when developing, deploying, or debugging Butterbase serverless functions, or when the user needs to add backend logic like webhooks, scheduled jobs, or custom API endpoints. Function Dev is an agent skill from butterbase-ai/butterbase-skills.
Function Dev fits situations like: debugging Butterbase serverless functions; the user needs to add backend logic like webhooks; custom API endpoints.
Run `npx skills add butterbase-ai/butterbase-skills --skill function-dev -a claude-code`. Or copy the skill folder (skills/function-dev in butterbase-ai/butterbase-skills) into .claude/skills/function-dev in your project. Claude Code loads it when a task matches its description.
Run `npx skills add butterbase-ai/butterbase-skills --skill function-dev -a codex`. Or copy the skill folder (skills/function-dev in butterbase-ai/butterbase-skills) into .agents/skills/function-dev in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add butterbase-ai/butterbase-skills --skill function-dev -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/function-dev, .gemini/skills/function-dev, .github/skills/function-dev and .opencode/skills/function-dev in your project.
Going by SKILL.md and its folder, Function Dev needs credentials named OPENAI_API_KEY and WEBHOOK_SECRET. Our summary lists: A credential in OPENAI_API_KEY; A credential in WEBHOOK_SECRET.
SKILL.md names 2 domains. In commands or code: api.openai.com and api.butterbase.ai; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Function Dev is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Function Dev: Upstash Qstash (davila7/claude-code-templates, 32k stars), Nubase (OtterMind/Nubase, 623 stars), Polylith Base Creation (DavidVujic/python-polylith, 553 stars) and Frappe App Dev (frappe/skills, 146 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
butterbase-ai (a GitHub organization) maintains it in butterbase-ai/butterbase-skills, which has 534 GitHub stars. The repository holds 39 skills in this directory. The repository was last updated on October 5, 2026.
Source: butterbase-ai/butterbase-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.