Tailored AI

@tailored-ai/core

The agent library. Everything except the CLI surface and the HTTP routes. Framework-free TypeScript, ESM, Node 20 or newer.

bash
npm install @tailored-ai/core better-sqlite3

better-sqlite3 is listed as a peerDependency so you control the version your app uses.

What it contains

AreaModules
Runtime + hot reloadAgentRuntime, loadConfig, validateConfig
Agent looprunAgentLoop, resolveAgent, history compaction, retry, timing
Toolsread, write, exec, web_fetch, web_search, memory, recall, core_memory, facts, tasks, delegate, claude_code, browser, discord_dm, request_action, custom-tool loader, more
Providersopenai_compatible (Ollama, vLLM, LM Studio, any OpenAI-wire server); hosted vendors via @tailored-ai/provider-* plugins
ChannelsDiscord (DiscordChannel), HTTP/SSE (via @tailored-ai/server)
PersistenceSQLite via better-sqlite3: sessions, messages, tasks, projects, memory, cron state
MemoryRecall tier with embeddings, chunk promotion, TTL sweep
WorkflowsYAML loader and engine. Linear and graph execution modes
CronScheduled jobs with prompt expansion ({{next_task}}, {{last_run_iso}})
Sandboxeshost, docker, podman: createSandbox, globalSandboxRegistry
WorktreescreateWorktree({ strategy: "head" | "branch" | "merge-to-head" })

The package's main entry re-exports the public API. See packages/core/src/index.ts for the full surface.

Minimal embed

ts
import Database from "better-sqlite3";
import {
  AgentRuntime,
  createProvider,
  loadConfig,
  runAgentLoop,
} from "@tailored-ai/core";

const config = await loadConfig("./config.yaml");
const db = new Database("./agent.db");
const provider = createProvider(config);

const runtime = new AgentRuntime({ config, db, provider });
const loopOptions = runtime.buildLoopOptions({ agent: "default" });

const response = await runAgentLoop("Hello", loopOptions);
console.log(response);

The same runtime can be shared with @tailored-ai/server to expose the agent over HTTP.

Hot reload

AgentRuntime holds mutable references to config, the tool registry, and the provider. Every loop iteration re-resolves them. Editing config.yaml takes effect on the next message; no restart.

The CLI uses a file watcher to call runtime.reloadConfig() on save. When embedding, you can call the same method, or mutate the config object directly (the runtime reads it by reference).

Optional peer dependencies

Two tools in core import optional peers lazily, so they cost nothing if you don't use them:

ToolPeerInstall command
browserplaywrightnpm install playwright && npx playwright install chromium
md_to_pdfmd-to-pdfnpm install md-to-pdf

Each fails with a clear "run npm install …" message at first use if the peer isn't present.

Source

packages/core/. The main barrel export is src/index.ts.