Core Concepts
Composable orchestration
Section titled “Composable orchestration”NimbleBrain’s core value is composing multiple MCP servers into a single, orchestrated workspace. Rather than connecting to one MCP server at a time, NimbleBrain aggregates tools from every installed app into a unified namespace, layers prompts to give the agent awareness of all available capabilities, and filters tool access per-task through skills.
┌──────────────────────────────────────────────────┐│ ToolRegistry ││ ││ ┌─────────┐ ┌─────────┐ ┌──────────────────┐ ││ │ App 1 │ │ App 2 │ │ App 3 (remote) │ ││ │ (stdio) │ │ (stdio) │ │ (HTTP/SSE) │ ││ │ 3 tools │ │ 5 tools │ │ 2 tools │ ││ └─────────┘ └─────────┘ └──────────────────┘ ││ ││ Unified namespace: 10 app tools + system tools │└──────────────────────────────────────────────────┘ │ │ ▼ ▼ Skill filtering Agent Engine (allowed-tools) (agentic loop)Three mechanisms make this composable:
| Mechanism | What it does |
|---|---|
| Tool aggregation | The ToolRegistry collects tools from every MCP source (local stdio, remote HTTP/SSE) and presents them as a flat namespace. The agent doesn’t know or care which server owns a tool. |
| Skill-scoped filtering | Each skill declares allowed-tools glob patterns. When a skill matches, only tools matching those patterns (plus system tools) are visible to the agent. This scopes the agent’s capabilities per task. |
| 4-layer prompt composition | System prompts are assembled from: (1) identity, (2) core context, (3) installed app metadata with trust scores, and (4) the matched skill’s prompt. Every layer adds awareness without the agent needing to discover it. |
Agent loop
Section titled “Agent loop”Every chat message triggers an agentic loop in the AgentEngine. The loop repeats until the model produces a response with no tool calls, or a limit is reached.
User message │ ▼┌─────────────────┐│ Call Claude │◄─────────────────┐│ (with tools) │ │└────────┬────────┘ │ │ │ ┌────┴────┐ │ │ Tool │ Yes │ │ calls? │──────► Execute tools │ │ │ in parallel ───┘ └────┬────┘ │ No ▼ Return responseEach pass through the loop is one iteration. Defaults:
| Setting | Default | Hard cap |
|---|---|---|
| Max iterations | 25 | 50 |
| Max input tokens | 500,000 | — |
| Max output tokens | 16,384 | — |
models.default | anthropic:claude-sonnet-4-6 | — |
The engine stops for one of three reasons:
complete— the model responded without requesting any tool callsmax_iterations— the iteration limit was reachedtoken_budget— cumulative input tokens exceededmaxInputTokens. When this happens, tool calls from the current LLM response are dropped (not executed) to avoid running tools whose results can’t be processed.
All tool calls within a single iteration run in parallel via Promise.all().
Orchestration flow
Section titled “Orchestration flow”Before the engine loop starts, the Runtime orchestrates the composition described above:
- Resolve or create a conversation
- Match the user message to a skill (triggers, then keywords)
- Compose the system prompt — 4-layer: identity + core skills + installed apps + matched skill
- Filter the unified tool namespace based on the matched skill’s
allowed-toolsglobs - Run the
AgentEngineloop against the composed tool set - Persist the conversation (JSONL or in-memory)
Bundles (apps)
Section titled “Bundles (apps)”A bundle is an MCP server package installed into NimbleBrain. Bundles follow the MCPB format — each has a manifest.json declaring how to start the server, what tools it provides, and optional UI metadata.
Sources
Section titled “Sources”Bundles are installed per workspace and tracked in workspace.json (not nimblebrain.json — bundle entries placed there are stripped on load). They come from:
| Source | How it works |
|---|---|
| Registry | Downloaded from the mpak registry by scoped name (e.g. @nimblebraininc/ipinfo). Managed across the org via manage_apps. |
| Connector catalog | Remote MCP connectors installed point-and-click from the in-app catalog, or via manage_connectors. |
| Local path | A bundle directory on the filesystem, for local development. |
Lifecycle states
Section titled “Lifecycle states”Each bundle process goes through these states:
starting ──► running ──► crashed ──► dead │ ▲ └──► stopped ─────────┘| State | Meaning |
|---|---|
starting | Process is spawning |
running | Healthy and serving tools |
crashed | Process exited unexpectedly (will attempt recovery) |
dead | Repeated crashes, not restarting |
stopped | Manually stopped via API or CLI |
No bundles by default
Section titled “No bundles by default”NimbleBrain does not install any MCP bundles by default. Platform capabilities (home, conversations, files, settings, usage, automations) are built in as inline tool sources. Install bundles from the mpak registry, a local path, or a remote URL to give the agent domain-specific tools.
Bundle options
Section titled “Bundle options”{ "name": "@nimblebraininc/postgres", "env": { "DATABASE_URL": "postgres://localhost/mydb" }}| Field | Description |
|---|---|
env | Environment variables passed to the bundle process |
trustScore | MTF trust score (0–100) from the mpak registry |
ui | UI metadata: name, icon, and placement declarations |
Skills
Section titled “Skills”Skills are Markdown files with YAML frontmatter. They control what the agent knows and what tools it can use for a given message.
Skill file format
Section titled “Skill file format”---name: researchdescription: > Deep research on a topic — search the web, gather sources, and synthesize a report. Use when the user asks to research, investigate, or analyze a topic.allowed-tools: websearch__search nb__searchmetadata: nimblebrain: loading-strategy: dynamic priority: 50 triggers: - "research this" - "deep dive"---
You are a research agent. Search the web, gather multiple sources,and synthesize findings into a structured report.How a skill loads — loading-strategy
Section titled “How a skill loads — loading-strategy”loading-strategy | Priority | Behavior |
|---|---|---|
always | 0–10 (core) or 11–99 | Always composed into the system prompt — identity, voice, durable rules. |
dynamic | 11–99 | Loaded on demand, via the activation signals below. |
How dynamic skills activate
Section titled “How dynamic skills activate”A dynamic skill enters context through any of:
- Description — its name + description sit in a catalog; the model activates the relevant one (so the description must say what it does and when to use it).
- Tool-affinity — auto-activates when a tool in the active set matches one of its
tool-affinityglobs. - Triggers — auto-activates on an exact phrase, for deterministic must-fire cases.
User: "research this topic and analyze the sources" │ trigger "research this" ── match! ──► research skill activatesAn activated skill injects its markdown body into the system prompt; allowed-tools (if set) scopes which tools it may call.
Skill directories
Section titled “Skill directories”Skills are loaded from three locations (in order):
- Built-in —
src/skills/builtin/(shipped with the package) - Global —
~/.nimblebrain/skills/ - Config — directories listed in the
skillDirsconfig option
Tools come from two places: MCP bundles and built-in system tools.
System tools
Section titled “System tools”Every NimbleBrain instance has these nb__* tools available:
| Tool | Description |
|---|---|
nb__search | Search installed tools (scope: "tools") or the mpak registry (scope: "registry") |
nb__status | Platform status; scope: "bundles" for per-app health, scope: "skills" for loaded skills, scope: "config" for model and limits |
nb__delegate | Spawn a child agent for sub-tasks (multi-agent delegation) |
nb__read_resource | Read an MCP resource by URI |
manage_connectors | List the connector catalog, install/disconnect remote MCP connectors per workspace or per user |
manage_apps | Org-level management of installed registry apps: list, check for updates, upgrade |
manage_workspaces | Create and manage workspaces |
manage_members | Manage workspace membership |
manage_users | Manage users (when a managed identity adapter is configured) |
App-platform capabilities are exposed through prefixed tool families: conversations__*, files__*, automations__*, skills__*, usage__report, instructions__write_instructions, and compose__effective_context.
Tool surfacing strategy
Section titled “Tool surfacing strategy”NimbleBrain uses tiered tool surfacing to keep the LLM’s tool list manageable:
| Condition | What the LLM sees |
|---|---|
| Total tools ≤ 30 | All tools surfaced directly |
| Total tools > 30, no skill matched | Only nb__* system tools. Others available via nb__search (scope: "tools"). |
Skill matched with allowed-tools | Tools matching the globs + system tools. Others via nb__search. |
The threshold is configurable via maxDirectTools (default: 30).
Multi-agent delegation
Section titled “Multi-agent delegation”The nb__delegate tool spawns a child AgentEngine run with a scoped system prompt and filtered tool set. Named agent profiles are configured in workspace.json:
{ "agents": { "researcher": { "description": "Deep research agent", "systemPrompt": "You are a research agent...", "tools": ["websearch__*"], "maxIterations": 8, "model": "reasoning" } }}The child agent’s iteration budget is capped at min(child.maxIterations, parent.remaining - 1). Multiple delegations in the same turn run concurrently.
Conversations
Section titled “Conversations”Conversations persist across messages so the agent remembers context.
Storage
Section titled “Storage”Conversations are workspace-owned. Every turn is written to a per-conversation JSONL file under the workspace it ran in:
~/.nimblebrain/workspaces/<wsId>/conversations/<ownerId>/<convId>.jsonlThe owner (ownerId) is the authorization principal — only they can read or resume the conversation — while the workspace (wsId) is where it is stored. Persistence is automatic; there is nothing to configure.
JSONL format
Section titled “JSONL format”Each conversation is a single .jsonl file:
{"id":"conv_abc123","createdAt":"2025-03-15T10:30:00Z"}{"role":"user","content":"What files are in my home directory?","ts":"..."}{"role":"assistant","content":"Let me check...","ts":"...","toolCalls":[...]}Line 1 is metadata (ID, creation timestamp). Lines 2+ are StoredMessage objects with role, content, timestamp, and optional tool call records.
Resuming conversations
Section titled “Resuming conversations”To continue an existing conversation, open it from the Conversations sidebar in the web UI. Through the API, pass conversationId in the chat request body.
MCP Apps
Section titled “MCP Apps”NimbleBrain is a full MCP Apps host, implementing the ext-apps specification. MCP Apps are interactive UI applications — built with HTML/JavaScript — that render directly inside the host as sandboxed iframes.
Unlike traditional web apps, MCP Apps:
- Live inside the conversation — no tab-switching, context stays together
- Call tools bidirectionally — apps invoke MCP tools and receive pushed results from the agent
- Inherit the host’s theme — CSS variables are injected automatically
- Run in a security sandbox — no access to the parent page, cookies, or other apps
Any MCP bundle that declares UI resources and placements becomes an MCP App. See MCP Apps for the full concept and MCP App Bridge for the implementation protocol.
Platform as MCP server
Section titled “Platform as MCP server”NimbleBrain exposes a /mcp endpoint that turns the platform into a Streamable HTTP MCP server. External MCP clients — Claude Code, Open WebUI, or another NimbleBrain instance — can connect through a single endpoint. Each request names its workspace via the X-Workspace-Id header (validated against your membership): /mcp serves that one workspace’s tools plus your identity tools (conversations, files, automations), and refuses tools in any other workspace. A request with no X-Workspace-Id is identity-only.
This means NimbleBrain is both an MCP client (connecting to installed bundles) and an MCP server (exposing composed tools to external hosts). See MCP Endpoint Reference for configuration and usage.