Authoring Tools for Dwizi
Dwizi tools are intentionally simple in structure, so they can be reliably executed by the platform and reliably called by LLMs.
A tool is just:
- One file
- One default export
- One async function
- One input object
- One JSON output
That's the contract.
⸻
The Only Valid Shape
✅ Required:
export defaultasync- Exactly one parameter
- That parameter is an object
export default async function run(input: { name: string }) {
return { greeting: `Hello, ${input.name}` };
}
Why we enforce this:
- Dwizi can infer the input schema
- MCP / JSON-RPC clients can call tools predictably
- LLMs don't guess what your function wants
⸻
Input Schema Inference
Dwizi reads your input schema from the first parameter type.
Best: Inline TypeScript object type
This produces the cleanest schema and best tool-call reliability.
export default async function run(input: { email: string; days?: number }) {
return { ok: true };
}
Also great: Destructuring (with an explicit type)
export default async function run(
{ email, days }: { email: string; days?: number }
) {
return { ok: true };
}
Works, but weaker: Plain JavaScript
Dwizi can infer from property usage, but it's heuristic.
export default async function run(input) {
const total = Number(input.amount);
return { total };
}
Use JavaScript only if you have a strong reason. For production tools, prefer TypeScript-first.
⸻
Runtime Examples: Deno vs Node
Dwizi supports multiple runtimes, but the tool contract stays identical.
Deno: TypeScript + URL imports (recommended)
import { z } from "https://esm.sh/zod@3.24.1";
export default async function run(input: { name: string }) {
const parsed = z.object({ name: z.string() }).parse(input);
return { greeting: `Hello, ${parsed.name}` };
}
Why Deno wins for tools:
- TypeScript runs natively
- URL imports remove package manager friction
- Great for "LLM-generated tooling" workflows
Node.js: Built-in APIs (legacy compatibility)
import crypto from "node:crypto";
export default async function run(input: { value: string }) {
const hash = crypto.createHash("sha256").update(input.value).digest("hex");
return { hash };
}
Use Node when you specifically need Node-only APIs or legacy code.
⸻
Output Rules
Your return value must be JSON-serializable:
✅ Allowed:
- Objects, arrays
- Strings, numbers, booleans
null
🚫 Avoid:
- Dates (convert to ISO strings)
- Class instances
- Functions
- Circular references
- BigInt (convert to string)
Example (good):
export default async function run() {
return { nowISO: new Date().toISOString() };
}
⸻
Common Failure Modes
- No default export → Dwizi can't load the tool
- Not async → you'll fight I/O immediately
- No parameters → schema inference breaks (LLMs won't know what to pass)
- Multiple parameters → only the first is used; the rest are ignored
- Non-JSON output → tool fails at serialization
⸻
LLM Authoring Pattern (This is the secret sauce)
LLMs should write the words, tools should do the work.
Examples:
- LLM writes the Slack summary → tool posts it to Slack
- LLM drafts the email → tool sends it via Resend
- LLM builds a table → tool appends it to Google Sheets
So when you prompt an LLM, your goal is: structured input + deterministic action.
⸻
Prompt Template for Tool-Ready Code
Use this template to get code that works on the first deploy:
Write a TypeScript tool as a single file.
Hard requirements:
- export default async function run(input: {...}) { ... }
- TypeScript
- Inline input type (object)
- Return JSON-serializable output only
- No external files, no package.json
- Target runtime: Deno (use URL imports if needed)
Tool intent:
- The LLM will generate text content (summaries/emails)
- The tool must perform the external action (API call) using that content
- Inputs must be explicit and minimal
Tool description:
"Post a list of bullet points to Slack using an Incoming Webhook."
⸻
Quick Checklist Before You Deploy
- One file
export default async function- One typed input object
- Return JSON-only
- Use Deno URL imports when you need dependencies
- Inputs are explicit enough for an LLM to call without guessing
Clear inputs create reliable tools. Reliable tools create real workflows.