@chloejs/core

中文文档
0.55.0发布于 2026/11/04MITTypeScriptES Module构建来源已验证近 30 天下载 6855

TypeScript AI agent runtime. Write your agents in code and choose how predictable they are: deterministic steps where they can be, an LLM only where a step needs judgement, all on your machine.

原始使用文档
文档目录14 节
  1. Start with your own assistant
  2. Who is in charge
  3. Give the model only as much as the step needs
  4. Hand over the goal, not the keys
  5. See which step asked a model
  6. What comes with it
  7. Code is tested. Words are scored.
  8. Is it for you
  9. Run it wherever Node runs
  10. Settings and secrets
  11. Commands
  12. Private by default
  13. What is in here
  14. AI is one part of it

Chloe

npm

chloejs.org: the docs, the examples and the reference.

AI agents where your code is in charge.

Chloe runs your AI agents on your own machine. The work is plain code, and an LLM is asked only when a step needs judgement. Jobs run on a schedule, from a chat or by hand, and the jobs, the runs, the memory and the evals are files you can read, with any LLM.

npm install @chloejs/core
npx chloe setup       # the files, a model, a free port: it asks, and checks
npx chloe             # the agents, the cron lines, one port, and a link that opens the page
  • Private. Runs on your machine, in one process and one SQLite file.
  • Visible. Every step, its input, its answer and its cost.
  • Yours to steer. What an agent changes is a git commit you can undo.

No build step in your project, an edit to a job is live in under a second, and it needs Node 22.18 or newer.

Get started · Examples · Primitives

Start with your own assistant

Most people meet Chloe as their own agent before they build anything else on it, so it is made to be a good one.

setup writes chloe.config.ts and one agent, agents/assistant, with a purpose and nothing else. Open the link npx chloe prints and tell it what you want: a note every morning with what is urgent in your mail, a watch on a price, a reminder before a bill is due. It changes itself to do it, its words, its jobs and its code, and each change is a commit you can read and undo on the page.

From there it is yours like any other code:

  • Reach it where you are. Telegram, Slack, Discord, WhatsApp, email, or the page. Only the people in allowFrom are answered.
  • Give it your things, bound. Mail, calendar, Drive and your notes folders, each tool tied to the search or folder you chose, so a turn that goes wrong cannot widen it.
  • It remembers. A folder of notes per agent, in a git repository of its own, one commit per run.
  • Pay how you like. A Claude subscription, a ChatGPT plan, a Google AI Pro plan, opencode, or a key. A subscription is spent before a key is.
  • It tells nobody. No telemetry, no copy of your runs, no remote dashboard.

The routine part is where it pays off. A morning brief that a model writes from scratch every day costs every day and comes back different. In Chloe the fetching, filtering and sending are code, and the model is asked one question. That is the same runtime, and the same file, you would use for a business.

import { defineAgent, prompt } from "@chloejs/core";
import * as gmail from "@chloejs/core/tools/gmail";
import * as calendar from "@chloejs/core/tools/calendar";
import * as web from "@chloejs/core/tools/web";
import { telegramChannel } from "@chloejs/core/channels";
import morningBrief from "./jobs/morning-brief.ts";

export default defineAgent({
  id: "assistant",
  identity: "Reads my mail and calendar, and tells me what matters.",
  purpose: prompt("purpose.md"),
  memory: { folder: "/home/you/notes", commit: true },
  tools: {
    gmailReadEmail: gmail.readEmail({ search: "in:inbox", what: "my inbox" }),
    calendarListEvents: calendar.listEvents({ calendars: ["primary"] }),
    webReadPage: web.readPage(),
  },
  jobs: [morningBrief],
  channels: { telegram: telegramChannel({ allowFrom: [123456789] }) },
});

Or ask your coding agent for the agent you want. npx chloe setup asks nothing when there is no keyboard and takes every default, and its last lines send the coding agent to the guides in node_modules/@chloejs/core/dist/docs/, for the version installed. npx skills add carlosmartinezt/chloejs gets it that far before anything is installed.

There is no password to set: npx chloe prints a link that opens the page signed in, once, within the hour, and npx chloe link prints another.

Who is in charge

Same invoice. A typical agent: the model decides, reading, checking, asking and paying in the order it picks. With Chloe: your code decides. A model reads the invoice, code checks your rules, a person approves the payment, and code pays.

The Chloe side, in full:

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 };
  },
});

The answer to an ask is checked against the shape it named. No model reads it. The run waits days if it must, and survives a restart while it waits.

Give the model only as much as the step needs

Four calls. Start at the top, and move down only when you have to.

work.step()I know what to do.Deterministic: the same input, the same result, every time.
work.model()I know what to ask.One question, one typed answer.
work.agent()I know what I want.The model picks the order, inside your limits.
work.ask()A person should decide.The run waits, for days if it must.

Your rules, loops and queries stay in TypeScript, and the if above a model call decides whether to ask at all. A morning with nothing to report costs nothing.

Hand over the goal, not the keys

When you only know the outcome, an agent step picks the order. You choose what it can reach and how far it can go, in the AI SDK's own words: tools is all it can reach, toolApproval is which of those calls may run, stopWhen and chloe's budget are how far it can go and what it may spend.

export default defineJob({
  id: "order-issues",
  cron: every(15).minutes,
  identity: "Reads what customers wrote in and looks into the ones that need looking into.",
  run: async (work) => {
    const messages = await work.step("load messages", () => unread());

    const looked: string[] = [];
    for (const message of messages) {
      const issue = await work.model("classify issue", {
        prompt: message.text,
        output: Issue,
      });
      if (!issue.needsInvestigation) continue;

      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,
      });

      looked.push(`${message.id}: ${found}`);
    }

    return { looked };
  },
});

See which step asked a model

The run record has one line per step, with what it was, how long it took and what it cost. A job that quietly grew a second model call shows up as a second line and a bigger number.

  • A finished step replays from the record.
  • A run cut off by a restart is closed as failed, and starts again next time.
  • A job waiting on a person survives the restart.
  • Every tool call an agent made is recorded.
  • Two runs of the same job never overlap.

One rule makes the replay safe: work happens inside a step, and code outside a step only decides. A finished step is replayed, not run again, when a run that was waiting carries on. A line outside one runs again on every resume, so it must not send, write or spend.

What comes with it

Durable jobsFinished steps replay on a resume.
SchedulesCron in TypeScript, in your time zone.
Any modelAny provider, a model per job, on a subscription or a key.
AgentsTools, approvals and a budget, set where the step is written.
ServicesEmail, Google, files, scripts, the web.
ToolsBuilt in, your own, or any MCP server.
ApprovalsA run waits days for an answer.
ChannelsTelegram, Slack, Discord, WhatsApp, email, a chat box on your site, and HTTP.
MemoryNotes and skills an agent keeps, in git.
Self-improvementAn agent changes its words, jobs and code when its owner asks. Every change is a commit you can undo.
Run historyEvery step, its input and its answer.
CostPer step, per run, per job.
Tests and evalsTests for code, scores for prompts.

Code is tested. Words are scored.

Neither spends real money: a test runs jobs for real against a stand-in gateway, and an eval answers every tool from the case.

npm run test          # the jobs: does it do the thing
npm run evals <id>    # the prompts: did the model decide well

Is it for you

Most personal AI agents run a prompt on a timer. Chloe's run your code.

Pick Chloe if:

  • You want an assistant of your own that you can read, change and grow into real jobs.
  • You want to write your agents in code, and choose which steps an LLM handles.
  • Your agents are jobs: on a schedule, from a chat, or started by hand.
  • You want to see what every step did, and what it cost.
  • You want to own it: on your own machine, with any LLM, in one process and one SQLite file.

Pick something else if:

  • You want an LLM to choose every step, the way a chat assistant does.
  • You need the work shared across many machines, or a hosted platform to run it.
  • You are building an app around a model, where the chat is the product.

Run it wherever Node runs

One process serves the page, keeps every cron line and answers the channels. Its dependencies are zod and the AI SDK, and its state is one SQLite file, so moving machine is copying a folder.

Three files, and you have an agent:

package.json           with "type": "module", so node reads your .ts files
chloe.config.ts        the agents this copy runs, and every setting
your-agent/agent.ts    what the agent is: its jobs, tools and channels

A small agent can be one plain .ts file with no chloe.config.ts. To run a job once and exit, it calls agent.run({ job, settings }). To stay running, with its cron lines and channels, it calls startChloe({ agents, settings }). Either way, node morning.ts starts it. See the examples.

An agent written for the AI SDK's ToolLoopAgent moves across as it is: its id, model, purpose, tools, stopWhen and toolApproval go into defineAgent unchanged, and chloe's own loop runs them, so each call is approved, budgeted and written down like any other.

import { anthropic } from "@ai-sdk/anthropic";
import { defineAgent } from "@chloejs/core";
import { tool } from "ai";
import { z } from "zod";

export default defineAgent({
  id: "weather",
  identity: "Says what the weather is.",
  purpose: "Answer about the weather.",
  model: anthropic("claude-opus-5-5"),
  tools: {
    weather: tool({
      description: "Get the weather in a location (in Fahrenheit)",
      inputSchema: z.object({ location: z.string() }),
      execute: async ({ location }) => ({ location, temperature: 72 }),
    }),
  },
});

That model goes to Anthropic on ANTHROPIC_API_KEY, as the package reads it, whatever the routes in settings say. Its cost is its tokens at the price the gateway's public list gives. A call to a tool with needsApproval stops the job and asks its owner yes or no, then carries on from that call with the answer.

Settings and secrets

A setting is a choice about how the runtime behaves, so it goes in the config with the agents, where it is typed and committed:

export default defineConfig({
  agents: [assistant],
  settings: {
    model: { defaultModel: "anthropic/claude-sonnet-5.5" },
    email: { provider: "resend" },
  },
})

What it leaves out is the default. Every setting is the Settings interface in core/settings.ts, with its one line of explanation on it, so your editor tells you what each one is as you write it. DEFAULTS beside it is what each one is when nobody says, and the table on chloejs.org is read out of both.

A secret goes in .env beside the config, mode 600 and never committed: every password, key and token, and nothing else.

CHLOE_MODEL_KEY=...
CHLOE_CONNECTIONS_RESEND_API_KEY=re_...
CHLOE_AGENTS_ASSISTANT_TELEGRAM=123456789:ABC...

The config names each one, so reading it shows every key there is. chloe reads no key it is not handed there:

settings: {
  model: { key: process.env.CHLOE_MODEL_KEY },
  connections: { resend: { api_key: process.env.CHLOE_CONNECTIONS_RESEND_API_KEY } },
  agents: { assistant: { telegram: process.env.CHLOE_AGENTS_ASSISTANT_TELEGRAM } },
}

The runtime reads no other setting from the environment: a setting is what the config says, or its default. Any value can be kept in .env the same way, by handing it over as process.env and a name. Where things are kept is the one exception, CHLOE_STATE, CHLOE_MEMORY and CHLOE_DB, read before the config is.

Commands

npx chloe                        # the one process, on 127.0.0.1:3067 unless serve in settings says
npx chloe link                   # a link that opens the page signed in
npx chloe account                # set the one password, or a new one
npx chloe agent <id>             # talk to one agent
npx chloe agent <id> <job>       # run one job now, without waiting for its cron line
npx chloe install                # run it as a service (systemd or launchd), so it survives a reboot

One process, one disk. The runs are a SQLite file in the state folder (data/, or CHLOE_STATE), beside the account, the tokens and, unless an agent says otherwise, its memory. Run one copy, on a machine or in a container whose state folder is a disk that outlives it. Two copies on one state folder would both fire every cron line, and a host that throws its disk away on every start forgets every run. A stop waits up to 60 seconds for the runs that are going; a run still going after that is closed as cut off at the next start.

It listens on 127.0.0.1:3067, an address only this machine can reach. serve: { host, port } in settings moves it: a container needs host: "0.0.0.0" so the machine around it can reach in, and then a proxy in front with the port closed to everything else, because the login lockout trusts the address that proxy writes.

Private by default

Chloe sends nothing to anyone you didn't name: no telemetry, no copy of your runs, and no remote dashboard. A request leaves the machine only for the model, the channels and the connections you set up. The runtime serves its own dashboard, on the box it runs on. To reach it from elsewhere, use an SSH tunnel, a private network, or your own web server in front of it: see From another machine.

What is in here

The package is this repo, compiled into dist/ on publish. Node refuses to strip types for anything under node_modules, so what you install is JavaScript; your own agent files are outside node_modules and node reads those directly, which is why there is still no build step in your project.

index.ts     what "@chloejs/core" is when you import it
server.ts    the server, which `npx chloe` runs
model/       asking a model, and tools/, the only thing a model can be handed
load/        what an agent and a job are, and reading them off disk
timer/       cron lines and every(), published as "@chloejs/core/timer"
serve/       the one port: every route, the login, tokens, and serving the page
site/        the dashboard, React, built into site/page/ and shipped built
core/        the floor. steps.ts runs a job, turn.ts runs a prompt, clock.ts
             starts each job when its cron line is due
scorers/     how a run is marked
services/    the work itself, called straight from a job, published as
             "@chloejs/core/services"
channels/    the ways in, for an agent to bind
plugins/     each feature chloe ships that can be taken out, a folder each,
             listed in plugins/index.ts: the channels, Google, Resend, the web
             and memory tools, the subscription routes, self improvement.
             npm run plugins -- remove <name> takes one out
ops/         cli.ts, which is `npx chloe`, and what it runs: the tests, the
             evals, talking to an agent, links, the password, tokens, and
             install.sh. docs.ts writes the guides into the package
docs/        the guides, published filled in as dist/docs/
example/     the shop agent the guides quote, a project of its own. Not published
test-agent/  the agent the tests load. Not published

The entrances, and no others: @chloejs/core, @chloejs/core/services, @chloejs/core/channels, @chloejs/core/connections, @chloejs/core/scorers, @chloejs/core/timer, @chloejs/core/test, and one per set of tools: @chloejs/core/tools/gmail, /calendar, /drive, /resend, /email, /web and /fs.

AI is one part of it

Start with a job that asks nobody anything. Add the step that needs judgement when you find it, and read what it cost.

The guides are in docs/, and in the package as dist/docs/, for the version installed. chloejs.org shows the latest, and its reference pages are read out of this source on every push to main, so they cannot describe a version of the code that does not exist.

MIT.

版本与发布记录

@chloejs/core 共发布 98 个版本,首次发布于 2026/09/23;过去 12 个月发布了 98 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.55.0latest2026/11/045 天前
0.54.02026/11/027 天前
0.53.02026/10/2713 天前
0.52.112026/10/2614 天前
0.52.102026/10/2614 天前
0.52.92026/10/2515 天前

关于 @chloejs/core 的常见问题

@chloejs/core 是什么?

TypeScript AI agent runtime. Write your agents in code and choose how predictable they are: deterministic steps where they can be, an LLM only where a step needs judgement, all on your machine.

如何安装 @chloejs/core?

在项目目录运行 npm install @chloejs/core,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 chloe,可以用 npx chloe 直接运行。

@chloejs/core 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@chloejs/core 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@chloejs/core 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.18.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@chloejs/core 可以商用吗?

@chloejs/core 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@chloejs/core 的下载量有多少?

根据 npm 官方下载统计,@chloejs/core 在 2026/10/10 – 2026/11/08 这 30 天内被下载 6,855 次,日均约 229 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@chloejs/core 还在维护吗?

最新版本 0.55.0 发布于 2026/11/04(5 天前);至今共发布 98 个版本,其中过去 12 个月发布了 98 个;首次发布于 2026/09/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。