Skip to main content
Any Framework

IronHive CLI - command-line agent frontend for the IronHive.Host SDK

Published
Sep 1, 2026
1mo ago
Total Downloads
11.6K
11,640

Install

dotnet add package IronHive.Cli --version 0.19.12

No framework information available.

README

ironhive-host

NuGet: IronHive.Host NuGet: IronHive.Cli NuGet: IronHive.Host.Protocol CI License: MIT

Universal Agent Host β€” CLI Β· server Β· embedded

μ—­ν• Β·λ²”μœ„Β·κΈ°λŠ₯ λͺ…μ„Έ(미듀웨어 정체성)λŠ” CHARTER.md μ°Έμ‘° β€” product-middleware Β§β‘€ μ—μ΄μ „νŠΈ 호슀트.

A foundation tool for AI-powered automationβ€”not just coding, but any task that benefits from intelligent command execution. One agent core (plan β†’ execute β†’ tool-call), exposed as an installable CLI, an embeddable .NET SDK, or a long-running server (stdio/JSON-Lines or HTTP/SSE) β€” pick the surface that fits, without re-implementing the agent loop.

The agent loop, context/compaction, mode system, MCP plugins, and permission engine itself live in IronHive.Agent (from ironhive-agent), which this package consumes as a PackageReference. IronHive.Host adds the hosting surface on top: CLI/server/embed entry points, the IronHive.Host.Protocol turn-stream contract, layered config, provider adapters, and session/execution-log/memory integration. See CHARTER.md for the full role boundary.

Features

  • Three surfaces, one core β€” CLI (ironhive), embeddable SDK (IronHive.Host), and server runners (stdio or HTTP/SSE) all drive the same IronHive.Agent loop.
  • MCP-native tooling β€” plugs into MCP servers (memory, code execution, custom tools) instead of hardcoding a tool set.
  • Multi-provider out of the box β€” OpenAI, Anthropic, GoogleAI, Azure OpenAI, xAI, Ollama, LM Studio, GPUStack, and local inference via LMSUPPLY_ENABLED.
  • Context-window safe by default β€” automatic history compaction (ContextManager) and a hard-backstop TokenBudgetChatClient prevent silent context overflows, including on small quantized models.
  • Resilient tool-calling β€” ResilientFunctionInvoker turns malformed tool-call arguments into model-actionable recovery hints instead of aborting the stream.
  • Layered configuration β€” global β†’ project β†’ environment β†’ .env, with automatic migration from legacy settings.json.

⚠️ 0.16.0 breaking repackage (upgrading from an older version? read this)

SDK 라이브러리 IronHive.Host.Core β†’ IronHive.Host(SDKκ°€ top-level 이름을 μ†Œμœ , λ„€μž„μŠ€νŽ˜μ΄μŠ€ IronHive.Host.Core.* β†’ IronHive.Host.*). CLI tool νŒ¨ν‚€μ§€ IronHive.Host β†’ IronHive.Cli (μ‹€ν–‰ λͺ…령은 ironhive κ·ΈλŒ€λ‘œ). turn-stream ν”„λ‘œν† μ½œ 계약은 별도 thin νŒ¨ν‚€μ§€ IronHive.Host.Protocol(무의쑴)둜 뢄리 μœ μ§€. μ˜› IronHive.Host tool νŒ¨ν‚€μ§€λŠ” 배포 쀑단(unlist μ•„λ‹˜ β€” κΈ°μ‘΄ 볡원 계속 λ™μž‘); μ‹ κ·œ μ„€μΉ˜λŠ” dotnet tool install -g IronHive.Cli. λ¦΄λ¦¬μŠ€λŠ” 이제 iyulab/ironhive-hostμ—μ„œ self-host β€” μ˜› ironhive-cli-releasesλŠ” archive(read-only, κΈ°μ‘΄ v0.11-0.15 λ‹€μš΄λ‘œλ“œ URL μœ μ§€).

Contents

Philosophy

Do one thing well.

Receive a command. Plan. Execute. Return.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          External Systems               β”‚
β”‚   CI/CD Β· Schedulers Β· Orchestrators    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ invoke
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚             ironhive-host                β”‚
β”‚   Command β†’ Plan β†’ Execute β†’ Done       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ MCP
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Plugins (MCP Servers)         β”‚
β”‚   code-beaker Β· memory-indexer Β· ...    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

As an SDK (IronHive.Host)

dotnet add package IronHive.Host

Build reusable agent hosts (agent loop, tools, session, providers). The CLI below is one consumption surface of this SDK.

As a CLI (IronHive.Cli)

dotnet tool install -g IronHive.Cli
ironhive

Or build from source:

git clone https://github.com/iyulab/ironhive-host
cd ironhive-host
dotnet build

Quick Start

# Interactive mode
ironhive

# Single command
ironhive -p "Write a README for this project"

# JSON output (for programmatic use)
ironhive -p "Hello" --output json

# Streaming JSON Lines
ironhive -p "Hello" --output jsonl

# Plain text (no ANSI)
ironhive -p "Hello" --plain

JSON Output Schema

--output json/jsonl is meant for programmatic consumption β€” piping into jq, another process, or a script. Fields that would otherwise serialize as null (sessionId, usage, thinking, toolCalls) are omitted from the object entirely rather than written as null.

--output json (single response, -p/--prompt):

{
  "content": "string",                 // always present β€” the assistant's text reply
  "sessionId": "string",               // omitted if no session is active
  "usage": {                           // omitted if usage wasn't reported
    "inputTokens": 0,
    "outputTokens": 0,
    "totalTokens": 0
  },
  "thinking": {                        // present only with --show-thinking AND the model returned thinking content
    "content": "string",
    "tokenCount": 0
  },
  "toolCalls": [                       // omitted if no tools were called
    {
      "name": "string",
      "arguments": "string",           // JSON-encoded arguments, as a string
      "result": "string",
      "success": true                  // true | false | null β€” null means the outcome is unknown
                                        // (unset unless the underlying IChatClient has
                                        // Microsoft.Extensions.AI function-invocation middleware)
    }
  ]
}

On cancellation (Ctrl+C) or an unhandled error, the object is replaced with an error shape instead: { "error": "cancelled", "code": 130 } or { "error": "<message>", "code": 1 }.

--output jsonl (streaming JSON Lines β€” one object per line, discriminated by type):

type Fields When
start sessionId First line, always
thinking content Only with --show-thinking, once per thinking delta
text content Once per text delta
tool_call id, name, arguments Once per tool-call delta (arguments is JSON-encoded)
done sessionId Last line on success
error error Instead of done, on cancellation or an unhandled exception

sessions list --output json β€” an array ([] if empty), one object per session:

[
  {
    "id": "string",
    "status": "string",        // lowercased, e.g. "active", "completed"
    "model": "string",
    "created": "2026-08-31T00:00:00.0000000Z",  // ISO 8601 (round-trip "o" format)
    "messageCount": 0,
    "firstMessage": "string"
  }
]

sessions delete <id> --output json:

  • Success: { "deleted": "<id>", "success": true }
  • Missing <id> or session not found: { "error": "string", "code": 1 }

Session Management

# Continue most recent session
ironhive -c

# Resume specific session
ironhive -r <session-id>

# List sessions
ironhive sessions list
ironhive sessions list --output json

Model Configuration

# Environment variables
export GPUSTACK_ENDPOINT=http://localhost:8080/v1
export GPUSTACK_API_KEY=your-key
export GPUSTACK_MODEL=gpt-4o-mini

# Or OpenAI
export OPENAI_API_KEY=sk-xxx

Configuration

Configuration is merged in order (later overrides earlier):

  1. Global: ~/.ironhive/config.yaml
  2. Project: .ironhive/config.yaml
  3. Environment: IRONHIVE_*, GPUSTACK_*, OPENAI_*, ANTHROPIC_*, GOOGLEAI_* / GOOGLE_API_KEY, XAI_*, AZURE_OPENAI_*, OLLAMA_*, LMSTUDIO_*, LMSUPPLY_ENABLED, and other provider-specific vars
  4. .env file: Project root .env

On first run, a legacy ~/.ironhive/settings.json (from earlier versions) is automatically migrated to config.yaml.

Config keys

The loader accepts these top-level keys in config.yaml. Acronym provider sections use lowercase keys; unknown top-level keys are ignored with a logged warning.

Key Notes
gpuStack camelCase
openai lowercase (acronym)
anthropic
googleai lowercase (acronym)
azureopenai lowercase (acronym)
xai
ollama
lmstudio lowercase (acronym)
lmsupply lowercase (acronym)
permissions
compaction
webSearch camelCase
deepResearch camelCase
chatBehavior camelCase
# ~/.ironhive/config.yaml
openai:
  apiKey: sk-...
  model: gpt-4o-mini
gpuStack:
  endpoint: http://localhost:8080
  apiKey: ...
  model: gpt-4o-mini
# .ironhive/config.yaml

# Context compaction is active by default β€” long sessions compact history
# instead of overflowing. Tune via the compaction section:
compaction:
  useTokenBasedCompaction: true
  protectRecentTokens: 40000     # most-recent tokens always kept
  minimumPruneTokens: 20000      # only compact when at least this much is prunable
  targetRatio: 0.70              # compact down to ~70% of the context window

Core Library Integration

Use IronHive.Host for direct .NET integration:

// Add to your project
<PackageReference Include="IronHive.Host" />

// Configure with DI
services.AddIronHiveWithOpenAI(apiKey, "gpt-4o-mini");
// Or
services.AddIronHiveWithOllama("llama3.2");

// Use
var agentLoop = serviceProvider.GetRequiredService<IAgentLoop>();
var response = await agentLoop.RunAsync("Hello");

// Streaming
await foreach (var chunk in agentLoop.RunStreamingAsync("Hello"))
{
    Console.Write(chunk.TextDelta);
}

See samples/console-chat for a complete example.

ChatBehaviorConfig

Controls how FunctionInvokingChatClient orchestrates the tool-call iteration loop. Exposed in IronHiveConfig.ChatBehavior so you can tune per-model without forking the source.

Property Default Notes
MaximumIterationsPerRequest 10 Lower (5–7) for small 4K-window models; raise (15–20) for large-context models
MaximumConsecutiveErrorsPerRequest 3 Backstop on back-to-back marshaller errors; rarely hit when ResilientFunctionInvoker is installed
# .ironhive/config.yaml
chatBehavior:
  maximumIterationsPerRequest: 7      # tune down for small/quantized models
  maximumConsecutiveErrorsPerRequest: 3

Context Compaction

Long sessions are kept within the model's context window automatically. When the agent loop is built (via the CLI, the server runners, or IronHive.Host DI), a ContextManager is wired from the compaction config so older history is compacted (token-based, protecting the most recent turns and important tool outputs) instead of silently overflowing.

  • Enabled by default; tune via the compaction: config section (see Configuration above)
  • Model-aware β€” the context window is sized from the active model
  • Embedded consumers can set options.Compaction on AddIronHive(...); manual loop builders can wire it via HostContextManagerFactory.Create(compactionConfig, modelName) and pass the result to AgentLoop/ThinkingAgentLoop
  • Complements (does not replace) TokenBudgetChatClient, which remains the hard backstop against per-request overflow

TokenBudgetChatClient

IChatClient decorator that short-circuits streaming calls when the accumulated message-history size would exceed a configurable fraction of the model's context window. Prevents context-overflow silent failures on small quantized models (e.g. 4K-window Gemma E4B).

  • Sits between FunctionInvokingChatClient and the underlying provider
  • Estimates tokens as total-chars Γ· 4 (conservative upper bound)
  • When the estimate exceeds maxContextTokens Γ— threshold, emits a graceful ChatFinishReason.Length response instead of letting the model error silently
  • Context window auto-detected via IContextSizeProvider if the inner client exposes it; otherwise falls back to defaultMaxContextTokens
var client = new TokenBudgetChatClient(
    inner: innerClient,
    defaultMaxContextTokens: 4096,
    threshold: 0.8);   // trigger at 80 % of context window

ResilientFunctionInvoker

Factory for the M.E.AI FunctionInvoker delegate that converts marshaller-level ArgumentException (missing/malformed tool arguments) into model-actionable procedural error strings, enabling small quantized models to self-correct without aborting the stream.

Install via UseFunctionInvocation:

chatClient.UseFunctionInvocation(configure: c =>
{
    c.FunctionInvoker = ResilientFunctionInvoker.Create();
});

When the model sends a tool call with a missing required parameter, instead of throwing and aborting, the invoker returns a numbered recovery directive telling the model exactly what is missing, where to find the value, and explicitly forbidding the empty-args retry pattern.

AgentServerRunner / AgentHttpRunner

Two runner implementations share the same processor delegate signature, enabling a single agent pipeline to serve either transport:

async IAsyncEnumerable<ServerEvent> ProcessMessage(
    UserMessageRequest msg,
    CancellationToken token)
{
    // msg.Model carries the per-message model override (nullable)
    await foreach (var evt in agentLoop.RunStreamingAsync(msg.Content, token)
        .ToServerEvents(executionLog, token))
    {
        yield return evt;
    }
}

// stdin/stdout JSON Lines (used by `ironhive run --server`)
var runner = new AgentServerRunner(ProcessMessage, logger);
await runner.RunAsync(ct);

// HTTP/SSE (host spawns the agent and communicates via REST)
var httpRunner = new AgentHttpRunner("http://localhost:5100", sessionId, ProcessMessage, logger);
await httpRunner.RunAsync(ct);

AgentHttpRunner expects these host endpoints:

Endpoint Method Purpose
/api/agent/{id}/ready POST Signal agent is up
/api/agent/{id}/inbox GET (SSE) Receive ServerRequest commands
/api/agent/{id}/events POST Deliver ServerEvent batches

Both runners support typeInfoModifiers to extend polymorphic type registrations without mutating the base JsonSerializerOptions:

var runner = new AgentServerRunner(ProcessMessage, logger,
    typeInfoModifiers: [ApplyCustomPolymorphismOverrides]);

AgentHttpRunner additionally exposes WaitForHitlResponseAsync / ResolveHitl for human-in-the-loop flows, and PublishEvent for out-of-band event delivery (e.g. provider fallback notices).

Protocol types (ServerRequest β†’ agent, ServerEvent β†’ host):

Type Discriminator Key fields
UserMessageRequest user_message Content, Model?
ContextUpdateRequest context_update WorkingPath?, SelectedItems?
HitlResponseRequest hitl_response Approved, Reason?
CancelRequest cancel β€”
ShutdownRequest shutdown β€”
ToolStartEvent tool_start Tool, Input?, CallId?
ToolEndEvent tool_end Tool, Success, Output? (≀ 8 KB), CallId?
FallbackServerEvent fallback Kind (retry|fallback|exhausted), Category, Message, ProviderIndex, TotalProviders, Attempt, MaxAttempts
TextDeltaEvent text_delta Content
TurnEndEvent turn_end β€”
ErrorEvent error Message

Samples

Sample Path Description
Console Chat samples/console-chat/ Core library direct integration
Web Chat samples/web-ai-chat/ Next.js + CLI subprocess
# Console Chat
cd samples/console-chat
dotnet run

# Web Chat
cd samples/web-ai-chat
npm install && npm run dev

Development

Requirements

  • .NET 10 SDK
  • Git

Build & Test

dotnet build
dotnet test

Project Structure

ironhive-host/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ IronHive.Host.Protocol/  # Thin turn-stream contracts (zero-dep NuGet)
β”‚   β”œβ”€β”€ IronHive.Host/           # SDK / core library (NuGet)
β”‚   β”‚   β”œβ”€β”€ Config/              # Configuration classes
β”‚   β”‚   β”œβ”€β”€ Extensions/          # DI helpers
β”‚   β”‚   β”œβ”€β”€ Providers/           # LMSupply, IronHive chat client providers
β”‚   β”‚   β”œβ”€β”€ Server/              # AgentServerRunner, AgentHttpRunner (references Host.Protocol)
β”‚   β”‚   β”œβ”€β”€ Session/             # Session management
β”‚   β”‚   └── Tools/               # Built-in tools, ResilientFunctionInvoker, TokenBudgetChatClient
β”‚   └── IronHive.Cli/            # CLI application (tool command: ironhive)
β”œβ”€β”€ samples/
β”‚   β”œβ”€β”€ console-chat/            # .NET Core integration
β”‚   └── web-ai-chat/             # Next.js + subprocess
└── tests/

Contributing

Issues and pull requests are welcome. This project is pre-1.0 (0.x) β€” breaking changes land freely for structural correctness; see CHARTER.md for scope and design intent before proposing a feature. dotnet build && dotnet test (see Development) should pass before opening a PR.

Related Projects

License

MIT

Changes from Previous Version

No structural changes between v0.19.9 and v0.19.12.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

No target framework metadata is available. Confirm compatibility in a representative project before standardising on this package.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.