ワンクリックで
ai
Add AI to a workflow — smart model routing, multi-provider support, BYOK billing. Helps pick the right model tier and billing config.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Add AI to a workflow — smart model routing, multi-provider support, BYOK billing. Helps pick the right model tier and billing config.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Build a custom AI agent — autonomous multi-step work with tools, brain memory, skills, and structured output. Scaffolds the agent folder with agent.json, SOUL.md, and skills.
Create a portal surface — tabbed, section-based pages that query workspace data. Sections include tables (with detail pages + actions), stats cards, progress bars, charts, galleries, text blocks, and accordions. Used for dashboards, employee portals, approval inboxes, status trackers.
Create a new workflow — multi-step automation with data queries, AI classification, and notifications. Scaffolds the file and tests locally.
Build a connector for an external API. Walks through the full pipeline — research, discover, gather, verify, scaffold — and wires it into the workspace. Supports read-only sources and bidirectional connectors with write actions.
Run Mug CLI developer workflow commands — dev server, update, deploy, clone, shutdown, workspaces.
Build Slack integrations — configure slack.json, send Block Kit messages, slash commands, interactive buttons, Home Tab, shortcuts, and two-way workflows.
| name | ai |
| description | Add AI to a workflow — smart model routing, multi-provider support, BYOK billing. Helps pick the right model tier and billing config. |
| argument-hint | <what the AI step should do> |
Add an AI-powered step to a workflow using ctx.ai(). Smart routing automatically picks the cheapest model that handles the task well. Multi-provider support lets you route to OpenAI, Anthropic, Workers AI, or any Cloudflare AI Gateway provider. BYOK lets you bring your own API key for unlimited AI.
For full API reference (all parameters, architecture, model catalog, error handling), see .mug/docs/ai.md. For workflow setup, see the /workflow skill.
Description of what the AI step should do: $ARGUMENTS
If no argument provided, ask the user:
Based on the task, recommend the right tier. You set the prompt (user message) and system (system prompt) — these control what the AI does.
| Task | Model tier | Why |
|---|---|---|
| Classify into categories | "fast" + maxTokens: 10 | Cheapest, constrained output |
| Extract structured data | "fast" | Cheap, pair with a JSON system prompt |
| Summarize long text | "balanced" | Mid-tier handles comprehension |
| Analyze and compare | "balanced" or "powerful" | Depends on complexity |
| Generate text/content | "balanced" | Mid-tier for most generation |
| Complex reasoning | "powerful" | Strongest model |
Present the recommendation and wait for user confirmation.
Add the ctx.ai() call to the workflow. Follow these patterns:
const result = await ctx.ai("fast", {
prompt: `Classify this ${itemType}:\n\n${item.text}`,
system: "Reply with exactly one word: billing, technical, or general.",
maxTokens: 10,
});
const category = result.text.trim().toLowerCase();
const result = await ctx.ai("fast", {
prompt: `Extract the following from this email:\n\n${email.body}\n\nReturn JSON: { "name": "", "email": "", "issue": "" }`,
system: "Return valid JSON only. No other text.",
maxTokens: 200,
});
const extracted = JSON.parse(result.text);
const result = await ctx.ai("balanced", {
prompt: `Summarize this report in 2-3 sentences:\n\n${report.body}`,
system: "Be concise. Focus on key findings and actions.",
maxTokens: 200,
});
const result = await ctx.ai("balanced", {
prompt: `Analyze these metrics and identify the top 3 issues:\n\n${JSON.stringify(metrics)}`,
system: "Be specific. Reference actual numbers. Prioritize by impact.",
maxTokens: 500,
});
const result = await ctx.ai("powerful", {
prompt: `Given this context:\n${context}\n\nEvaluate whether we should ${decision}. Consider risks, costs, and timeline.`,
system: "Think step by step. Weigh pros and cons. End with a clear recommendation.",
maxTokens: 1000,
});
const result = await ctx.ai("fast", {
prompt: `Should this expense be approved?\n\nAmount: $${expense.amount}\nCategory: ${expense.category}\nPolicy limit: $${policy.limit}\nBudget remaining: $${budget.remaining}`,
system: "Reply with JSON: { \"approved\": true/false, \"reason\": \"one sentence\" }",
maxTokens: 50,
});
const decision = JSON.parse(result.text);
Set maxTokens tight. Default is 1024. If you expect a one-word answer, set it to 10. This affects routing — low maxTokens biases toward the fast tier.
Use tier names directly — "fast" for classification/extraction, "balanced" for summarization/analysis, "powerful" for complex reasoning. More predictable than "auto".
Check result.routing during development to verify the tier selection:
const result = await ctx.ai("fast", { prompt, system: "Reply with one word.", maxTokens: 10 });
console.log(result.routing);
// { tier: "fast", model: "gpt-5.4-nano", provider: "openai", reason: "tier:fast" }
For unlimited AI without consuming Mug credits, bring your own API key:
mug secret set ai.anthropic=sk-ant-xxx
Then configure which tiers use your key in mug.json:
{
"ai": {
"billing": {
"fast": "mug-metered",
"balanced": "mug-metered",
"powerful": "ai.anthropic"
}
}
}
Or set billing per-workflow:
workflow("expensive-analysis", handler, { billing: "ai.anthropic" });
Or per-call:
await ctx.ai("powerful", { prompt, system: "...", billing: "ai.anthropic" });
"fast", "balanced", "powerful")Pick the tier directly — uses your workspace's configured model for that tier. "fast" = cheapest (default: gpt-5.4-nano). "balanced" = mid-tier (default: kimi-k2.6). "powerful" = strongest (default: claude-sonnet-4-6). Recommended approach. Response includes routing: { tier, model, provider, reason }.
"auto")Mug picks the tier based on prompt complexity. Uses token count, keyword markers, and maxTokens. Less predictable than choosing the tier yourself — prefer explicit tier names.
Any Cloudflare AI Gateway model: "openai/gpt-5.4-nano", "anthropic/claude-sonnet-4-6", "@cf/moonshotai/kimi-k2.6". Configure defaults per tier in mug.json ai.routing. Override per-call with routing: { fast: "...", balanced: "..." }.
Store your key with mug secret set ai.<provider>=<key>. Reference in mug.json ai.billing per tier, or override per-call/per-workflow with billing: "ai.anthropic". Zero Mug credit consumption.
"haiku", "sonnet", "opus" still work — mapped to Anthropic models. Prefer tier names for new code.
await ctx.ai("powerful", {
prompt,
system: "...",
routing: { powerful: "anthropic/claude-opus-4-7" },
});
Skip smart routing entirely:
await ctx.ai("openai/gpt-4.1", { prompt, system });
import { workflow } from "@mugwork/mug";
workflow("lead-scoring", async (ctx) => {
const leads = await ctx.query("crm", `
SELECT id, name, email, company, notes, source
FROM leads WHERE scored_at IS NULL LIMIT 50
`);
let hot = 0, warm = 0, cold = 0;
for (const lead of leads) {
const score = await ctx.ai("fast", {
prompt: `Score this lead as hot, warm, or cold:\n\nName: ${lead.name}\nCompany: ${lead.company}\nSource: ${lead.source}\nNotes: ${lead.notes}`,
system: "Reply with exactly one word: hot, warm, or cold. Hot = ready to buy. Warm = interested. Cold = unlikely.",
maxTokens: 5,
});
const tier = score.text.trim().toLowerCase();
if (tier === "hot") hot++;
else if (tier === "warm") warm++;
else cold++;
await ctx.exec("crm", "UPDATE leads SET score = ?, scored_at = datetime('now') WHERE id = ?",
[tier, lead.id as number]);
// Hot leads get a personalized outreach draft
if (tier === "hot") {
const draft = await ctx.ai("balanced", {
prompt: `Write a brief, personalized outreach email for:\n\nName: ${lead.name}\nCompany: ${lead.company}\nNotes: ${lead.notes}`,
system: "Keep it under 100 words. Professional but warm. Reference something specific from their notes.",
maxTokens: 200,
});
await ctx.notify.email({
to: "sales@company.com",
subject: `Hot lead: ${lead.name} (${lead.company})`,
message: `**Score:** ${tier}\n\n**Draft outreach:**\n\n${draft.text}`,
});
}
}
return { scored: leads.length, hot, warm, cold };
});