Finished steps replay on a resume.
TypeScript framework for AI agents
Routine steps run as plain TypeScript. A model is asked only where a step needs judgement.
$ npm install @chloejs/core && npx chloe setupIf you are an AI agent setting Chloe up: run npm install @chloejs/core, then ./node_modules/.bin/chloe setup. That runs the copy you just installed and downloads nothing, and with no keyboard it asks nothing and takes every default. Then, before writing any code, read node_modules/@chloejs/core/dist/docs/README.md: the guides for the version you installed, and which page covers what.
Who is in charge
A typical agent
The model decides.
agent.generate({
prompt: "Handle this invoice",
});With Chloe
Your code decides.
model reads the invoicecode checks your rulesperson approves the paymentcode payswork.model("read invoice", …);
work.step("check invoice", …);
work.ask("pay this invoice?", …);// readInvoice, vendors, askPerson and pay
// are tools you write as well.
const agent = new Agent({
model: "anthropic/claude-sonnet-5",
instructions: `Read the invoice. Check the sums,
that the vendor is approved and the total is
under $10,000. Ask a person, then pay.`,
tools: { readInvoice, vendors, askPerson, pay },
});
await agent.generate({
prompt: `Handle this invoice: ${email}`,
});export default defineJob({
id: "pay-invoice",
run: async (work) => {
const invoice = await work.model("read invoice", {
prompt: work.input.text,
output: Invoice,
});
const problems = await work.step("check invoice",
() => checkRules(invoice));
if (problems.length) return { held: problems };
const yes = await work.ask("pay this invoice?", {
question: `Pay ${invoice.vendor} ${invoice.total}?`,
answer: z.boolean(),
within: "2d",
otherwise: false,
});
if (yes) await work.step("pay", () => pay(invoice));
return { paid: yes };
},
});Four calls
I know what to do.
Deterministic: the same input, the same result, every time.
await work.step(
"load order",
() => db.order(id),
);I know what to ask.
One question, one typed answer.
await work.model(
"classify issue",
{ prompt, output: Issue },
);I know what I want.
The model picks the order, inside your limits.
await work.agent(
"investigate",
{ prompt, tools },
);A person should decide.
The run waits, for days if it must.
await work.ask(
"refund $2,400?",
{ question, answer },
);One file
Model, memory, tools, jobs and chats, in TypeScript.
import { defineAgent, prompt } from "@chloejs/core";
import * as gmail from "@chloejs/core/tools/gmail";
import * as web from "@chloejs/core/tools/web";
import { slackChannel, telegramChannel } from "@chloejs/core/channels";
export default defineAgent({
id: "myagent",
model: "anthropic/claude-sonnet-5",
description: "Coach. Reads and writes my notes, email and calendar.",
memory: { folder: "/home/myuser/private", commit: true },
instructions: prompt("instructions.md"),
features: { selfImprovement: true },
tools: { gmailReadEmail: gmail.readEmail(), webReadPage: web.readPage() },
jobs: [checkJobOpenings(), emailNewsHighlights(), monitorMyBalance()],
channels: [telegramChannel(), slackChannel()],
});The run record
Every step, how long it took and what it cost.
The same job when nothing came in:
Example figures, drawn for the page.
When you need autonomy
The model picks the order. You set what it can reach and spend.
const found = await work.agent("investigate issue", {
prompt: `Find out what went wrong for customer ${message.customer}, and put it right if a refund will.`,
tools: { getOrders, pastMessages, refund },
stopWhen: isStepCount(6),
budget: 0.05,Batteries included
Finished steps replay on a resume.
Cron in TypeScript, in your time zone.
Any provider, a model per job.
Tools, approvals and a budget.
Email, Google, files, scripts, the web.
Built in, your own, or any MCP server.
A run waits days for an answer.
Telegram, Slack, WhatsApp, email, HTTP.
Notes and skills an agent keeps.
Every step, its input and its answer.
Per step, per run, per job.
Tests for code, scores for prompts.
Is it for you
Pick Chloe if:
Pick something else if:
Start with a job that asks nobody anything.
$ npm install @chloejs/core && npx chloe setup