For the complete documentation index, see llms.txt. This page is also available as Markdown.

AI UI

In-process Claude tool-use loop — make a holon callable in natural language

Status: early — @holons/ai-ui is at 0.1.0. The agent loop and tool conversion are stable; the command registry currently lives as a fallback in this package and will move to @holons/core/commands upstream. Expect the import path for shared commands to change.

@holons/ai-ui is an in-process natural-language interpreter for Holons. It runs a Claude tool-use loop against the @holons/core commands so a user can say "log two hours on the garden task" and the agent translates it into the right sequence of @holons/core calls. It is what makes a Claude model embedded inside the holon's own infrastructure, rather than orchestrating it from outside.

This is the sibling of the MCP server: both expose @holons/core to AI agents, but they sit at different layers.

@holons/ai-ui

@holons/mcp-ui

Process model

In-process — embeds Claude SDK inside the running app

Out-of-process — MCP server reached by external clients

Entry point

holons-ai CLI (or library import)

stdio / SSE over HTTP

Caller

A holon's own scripts, cron jobs, bot handlers

Claude Desktop, IDE integrations, other MCP-aware tools

Best for

Embedding intelligence into the holon

Letting external agents participate in the holon

The two are not redundant—they support different deployment patterns. A holon can run both.

What it is

  • Name: @holons/ai-ui

  • Location: harvest/packages/ai-ui/

  • Binary: holons-ai

  • SDK: @anthropic-ai/sdk

  • Default model: claude-sonnet-4-6 (override via HOLONS_AI_MODEL)

Using the CLI

Environment:

Variable
Purpose
Required

ANTHROPIC_API_KEY

Claude API auth

Yes

HOLONS_AI_MODEL

Override the default model

No

The CLI prints the agent's final text answer to stdout; everything else goes to stderr.

How the loop works

The loop terminates when the model emits stop_reason: 'end_turn' or produces no further tool_use blocks. Defensive cap: maxIterations (default 10), to prevent runaway loops.

Per-call defaults:

  • maxTokens = 4096

  • maxIterations = 10

Prompt caching

The system prompt and tool definitions don't change across turns within a session, so they're sent with a single cache_control: { type: 'ephemeral' } breakpoint on the system block. Anthropic's render order is tools → system → messages, so a breakpoint on the system block caches both tools and system together. This:

  • keeps the implementation well under the 4-breakpoint cache cap,

  • avoids unnecessary cache writes,

  • makes multi-turn sessions cheap.

The same pattern is recommended for any tool-use loop calling Claude — see the agent.ts source for the exact wiring.

Tool definitions

Tools are derived from a CommandRegistry. Each registered command has:

At load time, every command is converted to an Anthropic Tool with a JSON Schema generated from its params. Required-param enforcement, type coercion, and side effects all live inside the command's own execute() — so the same registry powers both the AI loop and the text UI CLI.

Currently the registry lives at packages/ai-ui/src/commands.ts as a fallback (identical to the text-ui copy), designed so that when @holons/core/commands is extracted upstream, the package can switch to the shared registry with a no-op rename.

System prompt

The default system prompt is intentionally narrow:

You are the Holons assistant. You help users manage tasks, hours, and shopping lists across their holons by calling the available tools. Always call a tool when the user requests an action; never fabricate results. After tools complete, summarize what was done in one sentence.

Two principles worth noting:

  1. Always call a tool when the user requests an action. The agent is not asked to be clever about when to act—if the user wants an action, an action happens.

  2. Never fabricate results. Tool calls are the source of truth; the model's job is to dispatch and summarize, not to invent.

Callers can override the system prompt by passing system to runAgent().

Programmatic use

runAgent() is the library entry point — usable wherever a holon wants to embed natural-language intelligence (a bot handler, a webhook, a scheduled job):

The returned AgentResult includes the final text, the iteration count, the last stop reason, and the full message transcript—useful for debugging or for feeding back into another loop.

Testing

packages/ai-ui/src/tools.test.ts covers the command→tool conversion and the registry fallback. The agent loop is testable by injecting a pre-built Anthropic client into runAgent({ client })—no network needed for unit tests.

When to use it

Pick @holons/ai-ui when:

  • A holon's own code (a bot, a cron job, a script) wants to interpret natural-language input.

  • You're comfortable shipping the Anthropic SDK as part of your holon's runtime.

  • The agent should run on behalf of the holon, not as a separate user identity.

Pick the MCP server when:

  • An external client (Claude Desktop, an IDE) should be able to drive the holon.

  • Multiple AI agents may connect concurrently with different actor identities.

  • The integration should follow the standard MCP protocol rather than a Holons-specific API.

See also

  • MCP Server — the out-of-process complement

  • Harvest — the monorepo @holons/ai-ui is part of

  • HolonsBot — a natural place to embed an in-process agent loop

  • Glossary — vocabulary for the protocol concepts the agent acts on

Last updated

Was this helpful?