Custom Tools
Scheduling
Schedule code tools to run automatically at specific hours. Get results via email summaries with optional custom formatting.
Setup
Add a schedule to any active code tool:
tool(action="schedule",
tool_id="tool_abc123",
schedule={
enabled: true,
hours: [9],
timezone: "America/New_York"
})
This runs the tool every day at 9:00 AM Eastern.
Schedule Properties
| Property | Type | Default | Description |
|---|---|---|---|
enabled | boolean | — | Turn scheduling on/off without deleting the schedule |
hours | number[] | [9] | Hours to run (0-23), max 4 per day |
timezone | string | "UTC" | IANA timezone string (e.g., "America/New_York", "Europe/London") |
email_summary | boolean | false | Send results via email |
email_address | string | — | Override the default recipient email |
email_recipients | string | — | Comma-separated additional recipient emails |
args | object | — | Fixed arguments passed to the tool on every run |
Example: Multiple Hours with Args
tool(action="schedule",
tool_id="tool_abc123",
schedule={
enabled: true,
hours: [9, 17],
timezone: "America/Chicago",
email_summary: true,
args: { portfolio: "main", include_news: true }
})
Email Summaries
Enable email summaries to receive tool results in your inbox:
tool(action="schedule",
tool_id="tool_abc123",
schedule={
enabled: true,
hours: [8],
email_summary: true
})
By default, emails go to the email address on your Kyew account. Override with email_address or add additional recipients with email_recipients:
tool(action="schedule",
tool_id="tool_abc123",
schedule={
enabled: true,
hours: [8],
email_summary: true,
email_address: "[email protected]",
email_recipients: "[email protected], [email protected]"
})
Email Customization
By default, scheduled emails contain the raw JSON output from your tool. To customize the email content, return a _email property from your tool:
export default {
async fetch(request) {
const results = await getResults();
return Response.json({
data: results,
_email: {
html: "<h2>Daily Report</h2><table><tr><th>Metric</th><th>Value</th></tr>...</table>",
subject: "Daily Report — Mar 14",
text: "Plain text fallback for email clients that don't render HTML"
}
});
}
};
| Field | Required | Description |
|---|---|---|
_email.html | No | HTML content that replaces the raw JSON in the email body |
_email.subject | No | Custom email subject line (overrides default) |
_email.text | No | Plain text fallback |
The email header with status, execution time, and duration always renders regardless of customization.
Management
List All Schedules
tool(action="schedule", schedule_action="list")
View Execution History
tool(action="schedule", tool_id="tool_abc123", schedule_action="history")
Disable a Schedule
Disable without deleting — preserves the schedule config:
tool(action="schedule",
tool_id="tool_abc123",
schedule={ enabled: false })
Delete a Schedule
tool(action="schedule", tool_id="tool_abc123", schedule_action="delete")
Constraints
- Tool type: Only code tools can be scheduled
- Tool status: The tool must be active
- Max frequency: Up to 4 hours per day
- Timeout: 5-minute execution limit per scheduled run
- Auto-pause: Schedules pause automatically after 3 consecutive failures. Fix the issue and re-enable to resume.
Example: Daily Portfolio Summary
A code tool that runs at market open and close, emails a formatted summary:
tool(action="create",
name="portfolio_summary",
description="Generate portfolio performance summary",
tool_type="code",
code_config={
code: `
import { query, exec } from "./db.mjs";
export default {
async fetch(request) {
const { portfolio } = await request.json();
const holdings = await query(
"SELECT symbol, shares, cost_basis FROM holdings WHERE portfolio = ?",
portfolio || "main"
);
// Build summary
const rows = holdings.rows.map(h =>
\`<tr><td>\${h.symbol}</td><td>\${h.shares}</td><td>$\${h.cost_basis.toFixed(2)}</td></tr>\`
).join("");
return Response.json({
holdings: holdings.rows,
_email: {
subject: \`Portfolio Summary — \${new Date().toLocaleDateString()}\`,
html: \`
<h2>Portfolio Summary</h2>
<table border="1" cellpadding="8">
<tr><th>Symbol</th><th>Shares</th><th>Cost Basis</th></tr>
\${rows}
</table>
<p>\${holdings.rows.length} holdings total</p>\`
}
});
}
}`,
runtime: "javascript",
allowed_domains: []
})
Then schedule it:
tool(action="schedule",
tool_id="tool_abc123",
schedule={
enabled: true,
hours: [9, 16],
timezone: "America/New_York",
email_summary: true,
args: { portfolio: "main" }
})
API Reference
For the full technical reference including all parameters and options, see tool Tool Reference. For a step-by-step walkthrough, see Scheduled Report Guide.