Skip to content

Managing Apps

Once a bundle is installed, NimbleBrain tracks its lifecycle from startup through crashes and recovery. You can start, stop, and inspect bundles through the CLI, API, or web UI.

Every installed bundle is in one of five states:

starting ──→ running ──→ crashed ──→ dead
│ │
└──→ stopped ←────────┘
└──→ starting (explicit restart)
StateMeaning
startingMCP server process is being spawned
runningProcess is alive and responding to tool calls
crashedProcess exited unexpectedly. The health monitor will attempt automatic restart.
deadRestart attempts exhausted. Must be explicitly restarted.
stoppedManually stopped by you. Will not auto-restart.
Terminal window
nb bundle list
Configured bundles:
@nimblebraininc/bash (named)
@nimblebraininc/granola (named)
../mcp-servers/hello (local)

For JSON output:

Terminal window
nb bundle list --json
[{"name":"@nimblebraininc/bash"},{"name":"@nimblebraininc/granola"},{"path":"../mcp-servers/hello"}]

The nb status command shows live health data when the server is running:

Terminal window
nb status
Bundles: 3 configured
@nimblebraininc/bash
@nimblebraininc/granola
@nimblebraininc/postgres
Skills: 2 loaded
Bundle health:
bash: running (uptime: 7200s, restarts: 0)
granola: running (uptime: 7200s, restarts: 0)
postgres: crashed (uptime: n/a, restarts: 3)

The health endpoint is also available unauthenticated:

Terminal window
curl http://localhost:27247/v1/bundles/health
[
{"name": "bash", "state": "running", "uptime": 7200000, "restartCount": 0},
{"name": "granola", "state": "running", "uptime": 7200000, "restartCount": 0},
{"name": "postgres", "state": "crashed", "uptime": null, "restartCount": 3}
]

Stop a running bundle:

Terminal window
curl -X POST http://localhost:27247/v1/apps/granola/stop

Start a stopped or dead bundle:

Terminal window
curl -X POST http://localhost:27247/v1/apps/granola/start
Terminal window
nb bundle remove @nimblebraininc/granola
Removed "@nimblebraininc/granola" from config. Run nb reload to apply.

Uninstalling a bundle:

  1. Checks the protected flag — rejects if protected
  2. Stops the MCP server process
  3. Removes the source from the tool registry
  4. Removes the entry from nimblebrain.json atomically
  5. Emits a bundle.uninstalled event

Data is not deleted during uninstall.

Mark a bundle as protected in nimblebrain.json to prevent removal via nb__manage_bundle or the API:

{
"bundles": [
{
"name": "@nimblebraininc/bash",
"protected": true
}
]
}

Attempting to uninstall a protected bundle produces an error:

Cannot uninstall "bash": bundle is protected

When a bundle is installed from mpak, NimbleBrain records its MTF (mpak Trust Framework) trust score. The score is a number from 0 to 100, stored in the config and available in the GET /v1/apps response.

Trust scores are fetched via mpak info <name> --json at install time and stored in the bundle’s config entry:

{
"name": "@nimblebraininc/granola",
"trustScore": 85
}

Local and remote bundles do not have trust scores (they report null).

Set per-bundle config values (typically API keys):

Terminal window
nb config set @nimblebraininc/granola api_key=grn_abc123

View current config:

Terminal window
nb config get @nimblebraininc/granola
api_key: gr****

Values are stored in ~/.mpak/config.json with 0600 permissions. See Installing Apps for details.

After changing nimblebrain.json (adding, removing, or modifying bundle entries), signal the running server to reload:

Terminal window
nb reload
Reload signal sent. Running runtime will pick up changes.

This writes a timestamp to ~/.nimblebrain/.reload. The running runtime watches for this sentinel and reloads bundles and skills without restarting the process.