Production-grade multi-agent orchestration powered by Microsoft Semantic Kernel and xAI's Grok models.
Define a team of AI agents in a simple JSON config, give them a task, and watch them collaborate intelligently — with every turn automatically checkpointed to disk so you can resume exactly where you left off, even after killing the process.
- Fully configurable agents — names, instructions, models, and plugins defined in JSON; mix reasoning and non-reasoning models per agent
- Pluggable selection strategies — sequential, round-robin, or LLM-driven selection
- Flexible termination strategies — regex (e.g.
APPROVED), max iterations, or composite - 9 built-in plugins — FileSystem, Shell, Git, Http, Json, Search, Probe, Plan, and CodeExecution (sandboxed REPL)
- MCP server support — connect any Model Context Protocol server as a plugin; tools appear alongside built-in plugins and agents consume them transparently
- Live cost tracking — per-turn and session totals with real estimated USD cost
- Token budget cap — set
MaxCostUsdin config to stop the session before it overspends - Human-in-the-loop (
--hitl) — pause after any turn to inject context, redirect, or approve - Resumable sessions — full conversation history saved to
~/.fuseraft/sessions/(owner-only permissions) - Built-in resilience — transient API errors (429, 502, 503, 504) are retried automatically with exponential back-off
- API key validation — keys are verified against the provider before the session starts, not mid-run
- Rich CLI experience — colour-coded panels, live spinner, markdown transcript export with costs
- Cake-powered build —
build.sh/build.ps1with single-file publish support
- .NET 9 SDK
- xAI API key (set as
XAI_API_KEYenvironment variable)
export XAI_API_KEY=your_key_hereTip: Use grok-4-1-fast-non-reasoning for action-heavy agents (those calling tools) and grok-4-1-fast-reasoning for judgment/approval roles. Reasoning models reject the Temperature parameter — omit it from the config when using them.
# Restore tools and build
./build.sh
# Run the default software-development team
./bin/fuseraft run "Build a REST API in Go with JWT authentication"fuseraft [command] [options]
| Command | Description |
|---|---|
run [task] |
Start a new orchestration session (default) |
sessions |
List, inspect, or delete checkpoints |
plugins |
List available plugins and their functions |
config [path] |
Display config as rich tables |
validate [path] |
Validate a config file |
fuseraft run "Your task here"
fuseraft run --config config/examples/devops-team.json "Set up CI/CD for a Node.js app"
fuseraft run --resume # resume most recent incomplete session
fuseraft run --resume a1b2c3d4 # resume specific session
fuseraft run --hitl "Refactor the auth module" # enable human-in-the-loop
fuseraft run --output transcript.md # export full transcript with costs
fuseraft run --verbose --no-bannerfuseraft sessions # list incomplete sessions
fuseraft sessions --all # include completed sessions
fuseraft sessions --delete a1b2c3d4 # delete a specific session
fuseraft sessions --delete all # purge all completed sessions
fuseraft plugins # list all plugins and their functions
fuseraft plugins --plugin Git # filter to a specific plugin
fuseraft config # show default config
fuseraft config config/examples/devops-team.json
fuseraft config --list # enumerate all configs under config/
fuseraft validate config/my-team.json
fuseraft validate config/my-team.json --strict # also check plugin names
Configs live under config/. The default is config/orchestration.json.
{
"Orchestration": {
"Name": "SoftwareDevelopmentTeam",
"Description": "Developer writes code, Tester verifies, Reviewer approves.",
"Agents": [
{
"Name": "Developer",
"Description": "Senior software engineer.",
"Instructions": "You are an expert software developer...",
"Model": {
"ModelId": "grok-4-1-fast-non-reasoning",
"Endpoint": "https://api.x.ai/v1",
"ApiKeyEnvVar": "XAI_API_KEY",
"MaxTokens": 16384
},
"Plugins": ["FileSystem", "Shell", "Git", "Search"]
},
{
"Name": "Reviewer",
"Description": "Tech lead who approves changes.",
"Instructions": "You are a senior tech lead...",
"Model": {
"ModelId": "grok-4-1-fast-reasoning",
"Endpoint": "https://api.x.ai/v1",
"ApiKeyEnvVar": "XAI_API_KEY",
"MaxTokens": 8192
},
"Plugins": ["FileSystem", "Search"]
}
],
"Selection": {
"Type": "sequential"
},
"Termination": {
"Type": "composite",
"MaxIterations": 30,
"Strategies": [
{
"Type": "regex",
"Pattern": "\\bAPPROVED\\b",
"AgentNames": ["Reviewer"]
}
]
},
"Compaction": {
"TriggerTurnCount": 30,
"KeepRecentTurns": 8
},
"MaxCostUsd": 3.00
}
}Set MaxCostUsd to cap the total estimated spend for a session. After the turn that pushes cumulative cost over the limit, the session stops and the checkpoint is saved so it can be resumed later. Omit the field (or set it to null) for no limit.
Long sessions accumulate history that consumes tokens on every subsequent turn. Set Compaction to automatically summarise old turns with an LLM call when the history grows past a threshold, replacing the oldest turns with a single compact summary while retaining the most recent turns verbatim.
"Compaction": {
"TriggerTurnCount": 30,
"KeepRecentTurns": 8
}TriggerTurnCount is the history length that triggers compaction. KeepRecentTurns is how many of the most recent turns to preserve unchanged. The cost of compacted turns is carried forward in the session total. Omit the section entirely to disable compaction.
xAI (and similar providers) offer two model variants per tier:
| Variant | Best for |
|---|---|
grok-4-1-fast-non-reasoning |
Action agents that call tools repeatedly — Developer, Engineer, Tester, Researcher |
grok-4-1-fast-reasoning |
Judgment agents that analyse and decide — Reviewer, Architect, Analyst |
Reasoning models reject the Temperature parameter. Omit Temperature from the config (it defaults to null, which sends no value to the API) unless you are using a standard non-reasoning model that accepts it.
{
"Orchestration": {
"Security": {
"FileSystemSandboxPath": "/path/to/project",
"HttpAllowedHosts": ["api.github.com", "registry.npmjs.org"]
}
}
}Both the FileSystem and Shell plugins enforce FileSystemSandboxPath — any path or working directory outside the tree is rejected. Http enforces HttpAllowedHosts and always blocks private/loopback addresses regardless of the allowlist.
| Type | Description |
|---|---|
sequential |
Agents take turns in the order they are defined |
llm |
An LLM call picks the next agent each turn. Requires Prompt and Model |
| Type | Description |
|---|---|
regex |
Stops when a message matches Pattern. Optionally scoped to AgentNames |
maxiterations |
Stops after MaxIterations turns regardless of content |
composite |
Stops when any child strategy in Strategies fires |
| Plugin | Functions |
|---|---|
FileSystem |
read_file, write_file, list_files, delete_file |
Shell |
shell_run, shell_run_script, shell_get_env, shell_which, shell_pwd |
Git |
git_status, git_diff, git_log, git_show, git_branch_list, git_add, git_commit, git_checkout, git_create_branch, git_init |
Http |
http_get, http_post, http_put, http_delete, http_head |
Json |
json_format, json_minify, json_get, json_keys, json_search, json_merge, json_to_text, json_validate |
Search |
search_files, search_content, search_symbol |
Probe |
probe_code, assert_output, compare_outputs, run_hypothesis |
Plan |
plan_create, plan_get, plan_update_step, plan_add_step, plan_summary |
CodeExecution |
check_docker, sandbox_run, repl_start, repl_exec, repl_reset, repl_stop |
Add any plugin to an agent by listing its name in the Plugins array in the config.
Add any Model Context Protocol server as a plugin source. Servers are connected at session startup; their tools are registered as a KernelPlugin and agents reference them by name exactly like built-in plugins.
{
"Orchestration": {
"McpServers": [
{
"Name": "Filesystem",
"Transport": "stdio",
"Command": "npx",
"Args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp/workspace"]
},
{
"Name": "MyApi",
"Transport": "http",
"Url": "http://localhost:3000/sse"
}
],
"Agents": [
{
"Name": "Developer",
"Plugins": ["Filesystem", "MyApi", "Git"]
}
]
}
}| Field | Transport | Description |
|---|---|---|
Name |
both | Plugin name used in agent Plugins lists |
Transport |
both | "stdio" (default) or "http" |
Command |
stdio | Executable to launch (e.g. "npx", "python") |
Args |
stdio | Arguments passed to the command |
Env |
stdio | Extra environment variables for the child process |
WorkingDirectory |
stdio | Working directory for the child process |
Url |
http | SSE endpoint URL (e.g. "http://localhost:3000/sse") |
Stdio servers spawn a child process that is terminated when the session ends. HTTP servers connect to an already-running endpoint.
Two ready-to-use configs are included under config/examples/:
| File | Team |
|---|---|
devops-team.json |
Architect + Engineer (Shell/Git/FileSystem/Http) + Reviewer |
research-team.json |
Researcher (Http/Json/FileSystem) + Analyst (FileSystem/Json) |
fuseraft run --config config/examples/devops-team.json "Set up a CI/CD pipeline for a Node.js app"
fuseraft run --config config/examples/research-team.json "Summarize the latest .NET 9 release notes"Every agent turn is checkpointed to ~/.fuseraft/sessions/<sessionId>.json immediately after it completes. Session files are written with owner-only permissions (0600 on Unix). If the process is killed mid-session the full conversation history is preserved on disk, and the team picks up from the exact turn it was interrupted on.
# Resume the most recent incomplete session interactively
fuseraft run --resume
# Resume a specific session by ID
fuseraft run --resume a1b2c3d4
# See what sessions are available
fuseraft sessions
fuseraft sessions --allInput and output tokens as well as estimated cost are captured from the API response after every agent turn and shown inline in each message panel:
╭─ Developer turn 3 2.1s in:1,842 out:634 ~$0.0155 ─╮
The session summary table shows per-agent and total figures:
Agent Turns Input tokens Output tokens Est. cost
Developer 3 5,521 1,902 $0.0461
Tester 2 4,108 1,245 $0.0309
Reviewer 1 6,034 287 $0.0225
Total 6 15,663 3,434 $0.0995
The pricing table is loaded at startup from ~/.fuseraft/pricing.json when that file exists, so you can update prices without recompiling. Copy config/pricing.json from the repo as a starting point — the format is a JSON object mapping model IDs to [inputPricePerMillion, outputPricePerMillion]. If the file is absent the built-in table is used. If a model is not listed, token counts are still shown but the cost column shows —.
Token counts and cost are also written into markdown transcripts when --output is used.
Run with --hitl to pause after every agent turn:
fuseraft run --hitl "Redesign the database schema"After each turn a prompt appears:
↩ Enter to continue · type a message to redirect · q to stop:
| Input | Effect |
|---|---|
| Enter | Continue — the next agent takes its turn as normal |
| Any text | Inject — your message is added to the conversation as a Human turn; agents see it and respond to the redirect on the next round |
q / quit |
Stop — the session is checkpointed and can be resumed later |
Human injections are saved to the session checkpoint and replayed correctly if the session is resumed later.
# full pipeline (clean, restore, build, test, publish)
./build.sh
# compile only
./build.sh --target=Build
# self-contained single-file archive
./build.sh --target=Pack --runtime=linux-x64.\build.ps1
.\build.ps1 -Target Build
.\build.ps1 -Target Pack -Runtime win-x64dotnet cake build.cake --target=Lint
dotnet cake build.cake --configuration=DebugMIT