octoflow-core
v1.0.1
Published
Library-first TypeScript runtime for connecting LLM backends, tools, memory, guardrails, and flows to existing apps.
Maintainers
Readme
octoflow-core
Main OctoFlow runtime for adding agents to existing TypeScript apps. It discovers ready LLM backends, routes requests, runs sessions, streams events, executes typed tools, applies policy, manages stores, and connects packs, flows, MCP servers, skills, gateways, memory, and plugins.
Native CLI backends (claude-code-cli, codex-cli, cursor-cli, gemini-cli,
acp-cli, and custom) are bridge-only: OctoFlow routes prompts and task
state, while the CLI owns tools, MCP, skills, memory, and its native agent loop.
Use API, SDK, local, or A2A backends when the OctoFlow core harness should own
those capabilities.
Install
npm install octoflow-coreNode.js >=20 is required.
Use It When
- You want one API over CLI agents, API models, Ollama, custom hosts, or A2A peers.
- You need request/response, streaming, sessions, resume, task state, and structured output in your own app.
- You want built-in file and shell actions with approvals, path controls, profiles, and secret redaction.
- You plan to add memory, MCP, skills, packs, flows, plugins, platform adapters, or an OpenAI-compatible gateway.
30-Second Start
import { createAgent, defineAction, extractText } from 'octoflow-core';
const lookupDocs = defineAction({
name: 'lookup_docs',
description: 'Look up project docs.',
parameters: {
type: 'object',
properties: { topic: { type: 'string' } },
required: ['topic'],
},
execute: async ({ topic }) => `Docs for ${String(topic)}`,
});
const agent = await createAgent({
llm: [
{ backend: 'claude-code-cli', model: 'sonnet' },
{ backend: 'anthropic-api', model: 'claude-sonnet-4-6' },
{ provider: 'groq', model: 'llama-3.3-70b-versatile' },
{ provider: 'openrouter', model: 'openai/gpt-4o-mini' },
{ backend: 'gemini-api', model: 'gemini-2.5-flash' },
{ backend: 'ollama', model: 'llama3.2' },
],
actions: [lookupDocs],
context: { instructions: 'Use tools when they help.' },
});
const result = await agent.sendMessage({
message: 'Explain this repository in three bullets.',
});
console.log(extractText(result));
await agent.close();Backends without credentials or local binaries are skipped. The first ready entry in ordered llm fallback wins, with fallback on failure. Multiple provider profiles can share openai-api; each keeps isolated host/API-key/model config.
Use discoverAvailableBackends() for zero-config readiness scans; with no explicit priority it checks the default routing order plus cataloged built-in backends such as Gemini CLI and ACP. Use inspectBackendCatalog() when tools, examples, or tests need the shared backend/provider list, auth env vars, default hosts, model override hints, and probe metadata without duplicating backend tables. Use agent.inspectHarness() after startup when diagnostics need the live inventory of selected backends, resolved config, plugins, registered actions/tools, runtime skills, SKILL.md bundles, MCP servers/tools, brain status, Pack workers, the canonical core capability matrix, and backend feature conformance.
createAgent() is the single entry point for all runtimes. Use agentType to select the topology: 'tool-loop' (default), 'supervisor', 'swarm', 'sequential', and more. First-use presets (createCodingAgent(), createSupportAgent(), createResearchAgent(), createSecureToolAgent(), createSupervisorTeam()) are thin wrappers over that same API. See docs/api.md#createagent-options for the full option reference, and docs/agent-prompts.md for configuring the agent's base/system prompt and backend-native prompt caching.
What You Get
| Area | Runtime surface |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Backends | Discovery, priority routing, explicit provider selection, CLI adapters (claude-code-cli, codex-cli, gemini-cli, cursor-cli), API providers (Anthropic, OpenAI, Gemini, Ollama), ACP — drive any Agent Client Protocol agent (acp-cli, 16 built-in agents), custom hosts and CLIs. |
| Conversations | One-shot messages, streams, sessions, resume, default API compaction, backend-native prompt caching for stable prompt prefixes, provider cache diagnostics, task cost source/estimates, task state, stores, clean shutdown. |
| Tools | defineAction(), built-ins, MCP loading, skills, custom action registry with opt-in strict duplicate mode for non-native-CLI harnesses. Native CLI backends keep their own tool/MCP/skill surface. |
| Retrieval | chunkText(), createVectorStore(), and createRetrievalActions() for simple embedder-backed file search/RAG in core. |
| Safety | Approval flow, policy profiles, managed git worktrees, workspace-limited tools, path controls, tenant checks, deny paths, secret redaction, circuit breakers. |
| Orchestration | Packs, flows, workers, topic channels, PackMesh, subagents, A2A JSON-RPC/SSE. |
| Shipping | OpenAI-compatible gateway, daemon mode, adapters, plugins, observability events. |
| Optional memory | Attach local octoflow-brain or HTTP-backed createRemoteBrain() memory for the OctoFlow-owned harness; native CLI backends use their own memory/config surfaces. |
| Optional sandboxes | Local sandbox profiles, managed per-request git worktrees, Docker, SSH, Vercel Sandbox, E2B, and custom execution environments. |
ACP support
Use backend: 'acp-cli' when you want one OctoFlow integration over multiple ACP-capable coding agents.
- Why users need it: switch agent vendors without rewriting app glue code.
- What it gives users: consistent
createAgent/sendMessage/streamusage, bridge lifecycle events, and capability-aware ACP session handling while the ACP agent owns its native tools and MCP surface. - DX behavior: one-shot + streaming are the stable baseline; multi-turn persistence is enabled when the target ACP agent advertises
session/resumeorsession/load. - Runnable check:
npm run backend-acp -w octoflow-examplesvalidates readiness, one-shot, stream, session continuity (or skip when unsupported), and steer-mode behavior.
Public Imports
| Level | Import | Use for |
| ------------ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Stable | octoflow-core | Canonical API. Complete explicit public surface: app APIs, advanced extension APIs, migration tools, audits, and common runtime contracts. |
| Beta | octoflow-core/pack | Pack and flow orchestration helpers, supervisor/worker factories. |
| Beta | octoflow-core/stores | Store implementations and contracts; in-memory and SQLite presets are stable through createAgent options. |
| Beta | octoflow-core/output | Structured output schema helpers and parsers. |
| Preview | octoflow-core/a2a | Agent-to-agent JSON-RPC/SSE client and server. |
| Preview | octoflow-core/environments | Execution environment implementations and contracts. |
| Preview | octoflow-core/observability | Event and telemetry helpers. |
| Internal | octoflow-core/testing | Test helpers for runtime behavior; not a product API. |
The public API labels are documented in docs/api.md#stability-labels.
Common Recipes
Stream live task updates:
for await (const event of agent.stream({
message: 'Draft release notes.',
})) {
if (event.kind === 'artifact-update') {
const text = event.event.artifact.parts
.filter((part) => part.kind === 'text')
.map((part) => part.text)
.join('');
process.stdout.write(text);
}
}Set sandbox/worktree defaults once in octoflow.config.json:
{
"priority": ["claude-code-cli", "codex-cli"],
"defaultProfile": "local-sandboxed",
"defaults": {
"worktree": {
"name": "fix-tests",
"cleanup": "never",
"reuse": true,
"dirty": "copy"
}
}
}Then a normal agent.sendMessage({ message: 'Fix the failing tests.' }) runs
with the configured sandbox profile and managed worktree. Per-call
worktree still overrides config. worktree: true creates a detached checkout
under .octoflow/worktrees; a string or { name } controls the directory name. Use dirty: "copy" when the agent should see uncommitted local changes.
Use agent.runStream(...) for orchestration progress (flow-step-start, flow-step-complete, flow-terminated, loop, and task-batch events). Use onEvent or agent.onAny(...) when you want those same run events on the shared event bus as agent:flow-step-start, agent:flow-step-complete, agent:flow-terminated, and the matching loop/task-batch names.
const agent = await createAgent({
onEvent(event) {
if (event.type === 'bridge:message') process.stdout.write(event.data.text);
if (event.type.startsWith('agent:flow-')) console.log(event.type);
},
});Expose a local HTTP endpoint for OpenAI or Anthropic-compatible clients:
const openAiGateway = await agent.makeGateway({ inboundProtocol: 'openai' });
// Routes: /v1/models, /v1/chat/completions, /v1/responses, /v1/embeddings, /tools/invoke
const anthropicGateway = await agent.makeGateway({
inboundProtocol: 'anthropic',
});
// Routes: /v1/models, /v1/messagesExpose an AG-UI interoperable SSE endpoint (CopilotKit, LangGraph, assistant-ui, CrewAI, Mastra):
import { createAgUiGatewayServer } from 'octoflow-core';
const { server } = await createAgUiGatewayServer(agent);
// Route: POST /agui/run — SSE (default) or JSON (Accept: application/json)
// Event taxonomy emitted per run (SSE order):
// RUN_STARTED → STATE_SNAPSHOT → STEP_STARTED → ACTIVITY_SNAPSHOT
// → ACTIVITY_DELTA → TEXT_MESSAGE_* → TOOL_CALL_* (+ TOOL_CALL_RESULT)
// → STATE_DELTA → MESSAGES_SNAPSHOT → STEP_FINISHED → CUSTOM → RUN_FINISHED
// RunAgentInput: threadId, runId, messages, tools, context, forwardedProps, resume[], state.Use the lifecycle verifier in your own tests:
import { verifyAgUiEventSequence } from 'octoflow-core';
const violations = verifyAgUiEventSequence(events);
// [] = conformant sequence; non-empty = lifecycle invariant brokenFull AG-UI support matrix: docs/feature-catalog.md. Runnable references: react-ag-ui-chatbot for raw @ag-ui/client, and react-copilotkit-ag-ui-chatbot for CopilotKit UI on the same gateway.
Enable persistent local state:
const agent = await createAgent({
priority: ['anthropic-api'],
storage: true,
});Call a remote agent over A2A (JSON-RPC + SSE, plus task push notification config set/get for webhook delivery):
import { A2AClient, createA2AServer } from 'octoflow-core/a2a';
// Expose a local agent on http://127.0.0.1:4400/rpc
const handle = await createA2AServer({
agent,
host: '127.0.0.1',
port: 4400,
agentCard: { name: 'release-notes', description: 'Drafts release notes.' },
});
handle.server.listen(4400, '127.0.0.1');
// Call it from another process — one-shot, streaming, or session-scoped
const client = new A2AClient({ url: 'http://127.0.0.1:4400/rpc' });
const { text } = await client.run('Draft release notes for v1.4.');Route tool execution to a sandboxed environment (Docker / SSH / Vercel Sandbox / E2B / local):
import {
createDockerEnvironment,
createEnvironmentsPlugin,
} from 'octoflow-core/environments';
const env = createDockerEnvironment({ image: 'node:20-alpine' });
const agent = await createAgent({
plugins: [createEnvironmentsPlugin({ environments: { default: env } })],
});
// The plugin replaces the built-in `bash` action with one that delegates
// to `env.exec(...)`, so shell calls run inside the container.Learn More
../../docs/api.md- public API guide.../../docs/ag-ui.md- AG-UI gateway: DX, support matrix, React integration, and Mastra comparison.../../docs/backend-integration.md- backend setup and routing.../../docs/configuration.md- config files, profiles, env precedence, MCP, skills, tools.../../docs/security.md- approvals, sandboxing, credentials, and execution policy.../octoflow-examples- runnable templates.
File-size rule
Per the root AGENTS.md, source files must stay ≤ 400 non-blank/non-comment lines.
Exemptions in this package:
| File | Reason |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| src/index.ts | Public barrel. Every export is an explicit named re-export — no logic, no wildcards. Line count grows with the public surface, not with implementation complexity. Splitting it would require wildcard exports (banned) or a redundant indirection layer. |
All other files are subject to the 400-line limit. Split by concern when adding new exports.
Validate
npm run -w octoflow-core lint
npm run -w octoflow-core typecheck
npm run -w octoflow-core testStatus
Beta. createAgent, defineAction, stores, approvals, memory basics, and agent.run({ flow }) are Stable — see docs/api.md#stability-labels for the full stable surface and label definitions. Everything else is labeled Beta, Preview, or Internal. Pin versions before depending on it in production.
