Skip to content

Add a TypeScript tool

Let an agent propose a Statuspage incident, then approve it before your app posts it.

You need a running Wardrik daemon, Node 22.18+, and a Statuspage page ID and API key.

mkdir statuspage && cd statuspage
npm init -y && npm pkg set type=module
npm install @wardrik/[email protected] zod
statuspage.ts
import { Wardrik } from "@wardrik/sdk";
import { z } from "zod";
const page = process.env.STATUSPAGE_PAGE_ID;
const key = process.env.STATUSPAGE_API_KEY;
const wardrik = new Wardrik({ name: "statuspage" });
wardrik.tool({
name: "post_status",
description: "Open an incident on the public status page, with its first update.",
input: z.object({
name: z.string().describe("The incident's title, as customers see it"),
status: z.enum(["investigating", "identified", "monitoring", "resolved"]),
body: z.string().describe("The first update, in plain words"),
}),
run: async (incident, { signal }) => {
const response = await fetch(`https://api.statuspage.io/v1/pages/${page}/incidents`, {
method: "POST",
headers: { authorization: `OAuth ${key}`, "content-type": "application/json" },
body: JSON.stringify({ incident }),
signal,
});
if (!response.ok) throw new Error(`Statuspage returned HTTP ${response.status}`);
const { id, shortlink } = await response.json();
return { id, shortlink };
},
});
const stop = new AbortController();
process.on("SIGTERM", () => stop.abort());
process.on("SIGINT", () => stop.abort());
await wardrik.work({ signal: stop.signal });
  • It isn't readOnly, so every call needs approval unless a policy allows it.
  • A thrown error fails the call. The model receives the error message.

Allow the user default/@statuspage to serve tools to the org's agents:

~/.config/wardrik/config.yaml
roles:
tools: {rules: [{verbs: [serve], kinds: [agent]}]}
bindings:
- {org: default, role: tools, subjects: [user:default/@statuspage]}
systemctl --user restart wardrik
wardrik token create statuspage --subject user:default/@statuspage
export STATUSPAGE_PAGE_ID=... STATUSPAGE_API_KEY=...
WARDRIK_TOKEN=wdk_... node statuspage.ts

This example uses the default organization, default. The app needs no inbound port, and the Statuspage key stays in the app.

~/.config/wardrik/agents/status.md
---
description: Posts to the public status page when asked.
tools: [workers/*]
policy:
ask:
workers/post_status: This posts publicly on the status page.
---
You post incidents on the public status page. Write for customers, in plain words.
wardrik reload
wardrik ask status "Checkout is failing for some customers. Post that we're investigating."
wardrik approval ls
AGENT CALL TOOL WHY
status call_7c2e… workers__post_status This posts publicly on the status page.
wardrik approval approve status call_7c2e…
wardrik approval deny status call_7c2e… --reason "We don't post until it's confirmed."

After approval, your app posts the incident and the agent returns its link. The call ID above is illustrative; use the ID from your pending call.

~/.config/systemd/user/statuspage.service
[Unit]
Description=Status page tools for Wardrik
After=wardrik.service
[Service]
WorkingDirectory=%h/statuspage
EnvironmentFile=%h/.config/statuspage.env
ExecStart=/usr/bin/node statuspage.ts
Restart=on-failure
[Install]
WantedBy=default.target
chmod 600 ~/.config/statuspage.env # WARDRIK_TOKEN and the Statuspage keys
systemctl --user daemon-reload
systemctl --user enable --now statuspage

For other machines or containers, see Host your tools.