docs(extensions): document management and compatibility

This commit is contained in:
Xubin Ren 2026-07-26 18:33:41 +08:00
parent 41bebdcdb5
commit bbaafd0f4f
6 changed files with 623 additions and 0 deletions

View File

@ -33,6 +33,7 @@ Pick the row that matches what you want to accomplish next:
| Add model fallbacks | [Configure Model Fallback](./guides/configure-model-fallback.md) |
| Enable web search | [Configure Web Search](./guides/configure-web-search.md) |
| Add an MCP tool server | [Configure MCP Tools](./guides/configure-mcp-tools.md) |
| Install a nanobot, Pi, or OpenClaw extension | [Extensions](./extensions.md) |
| Generate images | [Image Generation](./image-generation.md) |
| Schedule work or create a local trigger | [Automations](./automations.md) |
| Understand and manage long-term memory | [Memory](./memory.md) |
@ -79,6 +80,8 @@ These pages explain implementation and extension points. You do not need them to
| Understand source ownership and runtime flow | [Architecture](./architecture.md) |
| Set up a development environment | [Development](./development.md) and [CONTRIBUTING.md](../CONTRIBUTING.md) |
| Add a channel package | [Channel Package Guide](./channel-package-guide.md) |
| Publish an extension package | [Extension Authoring](./extension-authoring.md) |
| Understand the extension control plane | [Extension System](./extension-system.md) |
| Build the WebUI source | [WebUI Development](../webui/README.md) |
If a command or screen no longer matches these docs, please [open an issue](https://github.com/HKUDS/nanobot/issues) with your nanobot version, operating system, and the page that needs correction.

View File

@ -18,6 +18,7 @@ Use this page when you know what you want to run and need the command shape. For
| Deliver a local trigger | `nanobot trigger <id> "message"` | Created first with `/trigger <name>` in the target chat/session |
| Serve an OpenAI-compatible API | `nanobot serve` | Starts `/v1/chat/completions`, `/v1/models`, and `/health` |
| Check chat channel setup | `nanobot channels status` | Useful before starting `nanobot gateway` |
| Manage extension packages | `nanobot extensions list` | Install, inspect, trust, enable, and remove nanobot, Pi, or OpenClaw packages |
| Manage optional features | `nanobot plugins list` | Shows channels and optional capabilities you can turn on |
| Log in to QR/OAuth-style channels | `nanobot channels login <channel>` | Used by channels such as WhatsApp and WeChat |
| Log in to OAuth model providers | `nanobot provider login <provider>` | Used by OpenAI Codex, xAI subscription, and GitHub Copilot providers |
@ -248,6 +249,42 @@ nanobot channels status
See [`chat-apps.md`](./chat-apps.md) for channel-specific setup.
## Extensions
Extension installation, trust, permission grants, and enablement are separate
operations:
| Command | Description |
|---|---|
| `nanobot extensions list` | Show installed packages and activation policy |
| `nanobot extensions inspect <id>` | Show contributions, dependencies, requested permissions, and diagnostics |
| `nanobot extensions search [query]` | Search compatible packages on npm |
| `nanobot extensions search [query] --ecosystem <name>` | Filter to `nanobot`, `pi`, or `openclaw` |
| `nanobot extensions install <npm-spec>` | Install an npm package as untrusted |
| `nanobot extensions install <url> --kind git [--ref <ref>]` | Install from a Git branch, tag, or commit |
| `nanobot extensions install <path> --kind local` | Install from a local package directory |
| `nanobot extensions permissions <id> [permissions...]` | Replace the exact granted permission set; omit values to revoke all |
| `nanobot extensions trust <id>` | Approve executing the installed package |
| `nanobot extensions untrust <id>` | Revoke trust and stop activation |
| `nanobot extensions enable <id>` | Allow activation when every other gate passes |
| `nanobot extensions disable <id>` | Stop activation without uninstalling |
| `nanobot extensions uninstall <id>` | Remove the user-scope package after confirmation |
| `nanobot extensions uninstall <id> --yes` | Remove without an interactive confirmation |
Example:
```bash
nanobot extensions install @acme/pi-review
nanobot extensions inspect pi.acme.pi-review
nanobot extensions permissions pi.acme.pi-review workspace.read
nanobot extensions trust pi.acme.pi-review
nanobot extensions enable pi.acme.pi-review
```
Installed packages live under `~/.nanobot/extensions/`. They do not execute
until trusted. See [Extensions](./extensions.md) for the safety model and
[Extension Authoring](./extension-authoring.md) for package compatibility.
## Optional Features
Use these commands when you want nanobot to add or remove a built-in capability

View File

@ -27,6 +27,7 @@ the focused guides first and come back here for exact fields and defaults.
| Configure model fallback | [`guides/configure-model-fallback.md`](./guides/configure-model-fallback.md) |
| Add an OpenAI-compatible provider | [`guides/configure-openai-compatible-provider.md`](./guides/configure-openai-compatible-provider.md) |
| Add Langfuse observability | [`guides/configure-langfuse-observability.md`](./guides/configure-langfuse-observability.md) |
| Install and govern extensions | [`extensions.md`](./extensions.md) |
| Secure a local AI agent | [`guides/secure-local-ai-agent.md`](./guides/secure-local-ai-agent.md) |
| Deploy the gateway | [`guides/deploy-nanobot-gateway.md`](./guides/deploy-nanobot-gateway.md) |
@ -45,6 +46,7 @@ the focused guides first and come back here for exact fields and defaults.
| Configure web search and fetch | [Web Tools](#web-tools) |
| Enable image generation | [Image Generation](#image-generation) |
| Add MCP servers | [MCP](#mcp-model-context-protocol) |
| Configure extension discovery and policy | [Extensions](#extensions) |
| Review shell, workspace, and SSRF controls | [Security](#security) |
| Control access and pairing | [Pairing](#pairing) |
| Tune gateway jobs, sessions, and tools | [Gateway Heartbeat](#gateway-heartbeat), [Auto Compact](#auto-compact), [Unified Session](#unified-session), [Tool Hint Max Length](#tool-hint-max-length) |
@ -64,6 +66,7 @@ If the WebUI does not expose the option you need, start from the task below. Mos
| Enable web search or fetch | `tools.web.search.*`, `tools.web.fetch.*`, optional `tools.ssrfWhitelist` | Ask a question that requires current web information, then inspect logs if needed | [Web Tools](#web-tools), [Security](#security) |
| Enable image generation | `tools.imageGeneration.enabled`, `tools.imageGeneration.provider`, `tools.imageGeneration.model`, matching provider credentials | Enable Image Generation in the WebUI and send one image request | [Image Generation](#image-generation) |
| Add external tools through MCP | `tools.mcpServers.<name>` | Start `nanobot gateway --verbose` and check startup/tool logs | [MCP](#mcp-model-context-protocol) |
| Discover and govern extension packages | `extensions.*` | `nanobot extensions list`, then inspect the package | [Extensions](#extensions), [Extension guide](./extensions.md) |
| Tighten tool and network safety | `tools.restrictToWorkspace`, `tools.exec.sandbox`, `tools.ssrfWhitelist`, `channels.*.allowFrom` | Run the same workflow through the channel or CLI you plan to expose | [Security](#security), [Pairing](#pairing) |
| Tune request timeouts or process concurrency | `NANOBOT_LLM_TIMEOUT_S`, `NANOBOT_STREAM_IDLE_TIMEOUT_S`, `NANOBOT_MAX_CONCURRENT_REQUESTS` | Start nanobot from the same environment and inspect startup/runtime logs | [Runtime Environment Variables](#runtime-environment-variables) |
| Run multiple isolated bots | separate `--config` and `--workspace` paths, plus distinct `gateway.port` or channel ports when processes run together | Use the same explicit paths with `nanobot status`, `agent`, `webui`, `gateway`, and `serve` | [Multiple Instances](./multiple-instances.md), [CLI Reference](./cli-reference.md) |
@ -2228,6 +2231,53 @@ When enabled, all incoming messages — regardless of which channel they arrive
> This is designed for single-user, multi-device setups. It is **off by default** — existing users see zero behavior change.
## Extensions
Use the WebUI **Extensions** page or `nanobot extensions` commands for normal
installation and trust decisions. The top-level `extensions` object is for
advanced discovery and policy:
```json
{
"extensions": {
"enabled": true,
"paths": ["/opt/nanobot/extensions"],
"allow": [],
"deny": ["acme.blocked"],
"workspaceTrust": "ask",
"entries": {
"acme.review": {
"enabled": true,
"trusted": true,
"permissions": ["workspace.read"],
"config": {
"mode": "strict"
}
}
}
}
}
```
| Option | Default | Description |
|---|---|---|
| `extensions.enabled` | `true` | Enable external extension discovery and activation |
| `extensions.paths` | `[]` | Additional manifest roots; each root may be one package or contain package directories |
| `extensions.allow` | `[]` | Optional extension ID allowlist; empty allows all IDs not denied |
| `extensions.deny` | `[]` | Extension IDs that must remain inactive |
| `extensions.workspaceTrust` | `"ask"` | Workspace extension policy: `"ask"`, `"allow"`, or `"deny"` |
| `extensions.entries.<id>.enabled` | `true` | Per-extension activation switch |
| `extensions.entries.<id>.trusted` | `false` | Approve executing that extension's code |
| `extensions.entries.<id>.permissions` | `[]` | Exact host permissions granted to the extension |
| `extensions.entries.<id>.config` | `{}` | Package-owned configuration passed to its runtime |
User-installed packages and their interactive trust state live under
`~/.nanobot/extensions/`. Config policy is merged at discovery time; nanobot
does not silently rewrite `config.json` when you install a package.
See [Extensions](./extensions.md) for the safe install flow and
[Extension Authoring](./extension-authoring.md) for the package contract.
## Disabled Skills
nanobot ships with built-in skills, and your workspace can also define custom skills under `skills/`. If you want to hide specific skills from the agent, set `agents.defaults.disabledSkills` to a list of skill directory names:

294
docs/extension-authoring.md Normal file
View File

@ -0,0 +1,294 @@
# Extension Authoring
nanobot extensions are packages with a strict `nanobot.extension.json`
manifest. The manifest can be inspected without importing optional SDKs or
executing package code. Runtime activation then projects each contribution into
the native nanobot registry that owns that capability.
This guide covers native Python extensions and the compatibility boundary for
Pi and OpenClaw packages. Users installing packages should read
[Extensions](./extensions.md).
## Package Layout
A minimal native package is:
```text
my-extension/
|-- nanobot.extension.json
`-- my_extension/
`-- __init__.py
```
`nanobot.extension.json`:
```json
{
"id": "acme.review",
"name": "Acme Review",
"version": "1.0.0",
"apiVersion": 1,
"runtime": "python",
"entry": "my_extension:register",
"description": "Adds a review tool and command.",
"homepage": "https://example.com/acme-review",
"license": "MIT",
"contributions": [
{
"kind": "tool",
"name": "review_code",
"description": "Review a local change."
},
{
"kind": "command",
"name": "review",
"description": "Start a review from chat."
}
],
"dependencies": [
{
"kind": "python",
"name": "acme-review-core",
"specifier": ">=1,<2",
"optional": false
}
],
"permissions": [
{
"name": "workspace.read",
"reason": "Read files selected for review."
}
]
}
```
Unknown fields are rejected. This is deliberate: a misspelled permission,
dependency, or contribution must not silently change package behavior.
## Manifest Reference
### Top-level fields
| Field | Required | Meaning |
|---|---:|---|
| `id` | yes | Stable lowercase package identity |
| `name` | yes | Human-readable name |
| `version` | yes | Installed package version |
| `apiVersion` | no | Manifest API, currently `1` |
| `runtime` | yes | `python`, `pi`, `openclaw`, or `declarative` |
| `entry` | runtime-dependent | One activation entry |
| `entries` | runtime-dependent | Multiple Pi/OpenClaw entries; takes precedence over `entry` |
| `contributions` | no | Capabilities owned by the package |
| `dependencies` | no | Activation prerequisites |
| `permissions` | no | Privileged host capabilities requested from the user |
| `description` | no | Catalog summary |
| `homepage` | no | Project or documentation URL |
| `license` | no | SPDX-style license label |
Entries must be relative to the package root and cannot contain `..`.
### Contributions
Supported `kind` values are:
```text
tool
skill
channel
llm_provider
transcription_provider
image_generation_provider
web_search_provider
mcp_server
hook
command
webui
```
Each contribution has a stable `name`, optional runtime `target`, optional
`description`, and optional `replaces` list. `replaces` contains extension IDs,
not contribution names. Replacement is still checked against scope precedence.
The manifest declares ownership. It does not create an implementation by
itself. A runtime must register the corresponding native capability.
### Dependencies
| Kind | `name` identifies | Version behavior |
|---|---|---|
| `python` | Installed Python distribution | PEP 440 specifier |
| `npm` | Package under the extension's `node_modules` | npm installation constraint |
| `executable` | Command on `PATH` | No version probe |
| `environment` | Environment variable | Must be non-empty |
| `extension` | Another extension ID | Installed extension version |
Set `optional: true` when the extension can activate without the dependency.
Do not put API keys in the manifest.
### Permissions
Permission names are lowercase namespaced identifiers such as
`workspace.read`, `workspace.write`, or `network.http`. Include a concrete
reason the user can evaluate. Activation requires every requested permission to
be granted.
Permissions describe host policy; they are not an OS sandbox. Keep the request
set minimal and use native host operations when one exists.
## Native Python Runtime
The Python entry is `module[:attribute]`; the default attribute is `register`.
The function is synchronous and must return `None`:
```python
from nanobot.agent.tools.base import Tool
class ReviewTool(Tool):
@property
def name(self) -> str:
return "review_code"
@property
def description(self) -> str:
return "Review a local code change."
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"path": {"type": "string"},
},
"required": ["path"],
}
async def execute(self, path: str) -> str:
return f"Review requested for {path}"
def register(api) -> None:
api.register_tool(ReviewTool())
```
The v1 Python API exposes:
- `register_tool(tool)`
- `register_command(command, handler, prefix=False)`
- `register_hook_factory(factory)`
These methods use existing nanobot registries. Do not import or patch
`AgentLoop`, reach into WebSocket internals, or create a second tool registry.
If a new contribution kind needs execution support, add an adapter at the
native subsystem boundary and keep the manifest API independent from that
implementation.
## Publish and Discover
For npm discovery, include the exact `nanobot-extension` keyword:
```json
{
"keywords": [
"nanobot-extension"
]
}
```
Compatibility packages use their upstream metadata and keyword:
- Pi: `pi-package` plus `pi.extensions`
- OpenClaw: `openclaw-plugin` plus `openclaw.extensions` or
`openclaw.runtimeExtensions`
Native Python packages can be installed from a local directory or Git source.
The market is an index; installation always passes through local validation,
dependency checks, permission review, trust, and activation.
## Compatibility Matrix
The matrix describes the current adapter, not an intention to support every
upstream API.
| Upstream capability | Pi | OpenClaw | nanobot behavior |
|---|---|---|---|
| Tool registration and calls | Executable | Executable | Projected as native `Tool`; implementation stays in Node sidecar |
| Slash commands | Executable | Executable | Registered in native command router |
| Supported lifecycle events | Observation-only | Observation-only | Receives serialized run/tool events; cannot mutate native context |
| Provider registration | Metadata only | Metadata only | Visible in catalog and diagnostics; not an executable provider |
| Transcription/image/web-search provider contracts | N/A | Metadata only | Visible but not projected into native provider registries |
| Skills declared in plugin metadata | N/A | Metadata only | Catalog ownership only; runtime skill installation is not synthesized |
| Channels | N/A | Metadata only | No OpenClaw channel host emulation |
| Session tree and custom entries | Unsupported | Unsupported | No compatible host surface |
| Terminal UI, widgets, renderers, shortcuts | Unsupported | Unsupported | WebUI and CLI have different rendering contracts |
| Model selection and thinking control | Unsupported | Unsupported | Remains owned by nanobot model presets and request policy |
| Arbitrary upstream host services | Unsupported | Unsupported | Reported as diagnostics rather than silently emulated |
### Pi package shape
```json
{
"name": "@acme/pi-review",
"version": "1.0.0",
"keywords": ["pi-package"],
"pi": {
"extensions": ["./index.ts"]
}
}
```
The sidecar supports `registerTool`, `registerCommand`, and selected `on(...)`
lifecycle handlers. TypeScript uses Node's native type stripping when
available, with `jiti` as a fallback installed with the package runtime.
### OpenClaw package shape
```json
{
"name": "@acme/openclaw-review",
"version": "1.0.0",
"keywords": ["openclaw-plugin"],
"openclaw": {
"runtimeExtensions": ["./dist/index.js"]
}
}
```
If present, `openclaw.plugin.json` supplies catalog identity, contribution
contracts, command aliases, and compatibility diagnostics. The OpenClaw
`register` function must complete synchronously during load.
## Test an Extension
Use an isolated config and workspace while developing:
```bash
nanobot extensions install ./my-extension --kind local
nanobot extensions inspect acme.review
nanobot extensions permissions acme.review workspace.read
nanobot extensions trust acme.review
nanobot extensions enable acme.review
nanobot agent -m "Use review_code on README.md"
```
Also test:
- install while untrusted does not execute code;
- missing hard dependencies leave the package inactive;
- denied or missing permissions prevent activation;
- duplicate contribution names become diagnostics;
- disable, untrust, reload, and uninstall remove runtime registrations;
- one broken package does not block unrelated packages.
For nanobot itself, extension tests live under `tests/extensions/`. Keep
compatibility fixtures small and assert diagnostics for unsupported APIs.
## Design Rules
1. Extend the control plane, not the core loop.
2. Keep one native owner for each capability.
3. Make discovery metadata-only.
4. Separate install, permission grant, trust, and enable.
5. Report partial compatibility honestly.
6. Keep market metadata independent from runtime execution.
7. Roll back all registrations owned by a failed or unloaded extension.

View File

@ -1,5 +1,9 @@
# Extension system
This page documents the maintainer-facing architecture. For installation and
operations, read [Extensions](./extensions.md). For the package contract, read
[Extension Authoring](./extension-authoring.md).
nanobot treats an extension as an installable, governable unit and a
contribution as one capability supplied by that unit. This distinction keeps
the agent core small without forcing tools, channels, providers, skills, MCP
@ -77,6 +81,10 @@ Compatibility is capability-based rather than all-or-nothing:
- Plugin failures are isolated from the agent process and produce actionable
diagnostics.
The compatibility sidecar is a failure-isolation boundary, not a security
sandbox. The exact executable and metadata-only surfaces are listed in the
[compatibility matrix](./extension-authoring.md#compatibility-matrix).
## Security model
Extensions are trusted code, not prompts or static skills. Installation and
@ -99,6 +107,16 @@ per-extension enablement, package-owned config, and workspace trust. Discovery
does not import extension code. Installation does not imply workspace trust,
and activation does not rewrite `config.json` behind the user's back.
The activation gates are deliberately independent:
```text
installed -> dependencies ready -> permissions granted -> trusted + enabled
```
Only candidates that pass every gate own active contributions. Reload first
rolls back registrations by extension owner and then activates the new
snapshot. A failed activation is converted into a diagnostic.
## Market boundary
The market is an index, not a runtime. It describes packages available from
@ -107,3 +125,35 @@ shape. Installing a listing still goes through the local installer, policy,
dependency checks, and trust flow. This keeps discovery independent from code
execution and allows multiple catalogs without coupling the agent to one
store.
## Ownership boundaries
The extension package owns identity, policy, and contribution declarations.
Native subsystems continue to own execution:
| Concern | Owner |
|---|---|
| Package identity, source, trust, permissions | `nanobot.extensions` |
| Tool execution contract | `nanobot.agent.tools` |
| Commands | `nanobot.command` |
| Agent lifecycle hooks | `nanobot.agent.hook` |
| Providers | `nanobot.providers` |
| Channels | `nanobot.channels` |
| Skills | `nanobot.skills` |
| Browser management surface | `webui` |
Do not add extension discovery or compatibility branching to `AgentLoop`.
Runtime assembly creates an `ExtensionHost`, projects supported registrations
through native APIs, and closes the host with the surrounding runtime.
## Protocol boundary
Pi and OpenClaw entries run behind a versioned NDJSON request/response protocol.
The Python process sends load, call, lifecycle event, and close requests. The
Node process returns registrations, results, outputs, and diagnostics. Protocol
messages contain JSON-compatible values only.
The adapter must reject malformed messages, time out stalled requests, and
close the sidecar when activation fails. Unsupported upstream methods are
either explicit no-ops with diagnostics or rejected; they must never be
reported as executable contributions.

189
docs/extensions.md Normal file
View File

@ -0,0 +1,189 @@
# Extensions
Extensions add capabilities to nanobot without modifying the agent loop. One
extension package can contribute tools, commands, hooks, skills, channels,
providers, MCP servers, or WebUI surfaces. nanobot also recognizes compatible
Pi packages and OpenClaw plugins, with capability-by-capability diagnostics.
Use this page to install and manage extensions. To publish one, read
[Extension Authoring](./extension-authoring.md). For the internal design, read
[Extension System](./extension-system.md).
## Install Safely
The WebUI **Extensions** page and the `nanobot extensions` commands use the same
local extension store. The safe lifecycle is:
1. Find or install a package.
2. Inspect its source, runtime, dependencies, requested permissions, and
diagnostics.
3. Grant only the permissions you understand.
4. Mark the package trusted.
5. Enable it.
Installation does not grant trust. An installed package remains visible but
inactive until it is enabled, trusted, has all requested permissions, and
passes dependency checks.
### WebUI
Open **Extensions** in the sidebar:
- **Installed** manages packages in `~/.nanobot/extensions/`.
- **Discover** searches npm packages marked for nanobot, Pi, or OpenClaw.
- **Built in** shows native nanobot capabilities projected into the same
catalog. Built-in entries are informational and are not uninstallable.
Select an entry to see its contributions, dependencies, permission reasons,
source, compatibility notices, and activation errors. Trust and permission
controls are intentionally separate.
### CLI
```bash
# Search all supported npm ecosystems
nanobot extensions search "memory"
# Search one compatibility ecosystem
nanobot extensions search "review" --ecosystem pi
# Install without trusting the package
nanobot extensions install @scope/package
# Inspect before activation
nanobot extensions inspect pi.scope.package
# Grant exactly the requested host permissions
nanobot extensions permissions pi.scope.package network.http workspace.read
# Trust and enable
nanobot extensions trust pi.scope.package
nanobot extensions enable pi.scope.package
```
Install from Git or a local directory when the package is not published:
```bash
nanobot extensions install https://github.com/acme/nanobot-tool.git --kind git
nanobot extensions install ./my-extension --kind local
```
Local-directory installation is available only to local WebUI requests. Remote
browser clients cannot ask the gateway to read an arbitrary server path.
## Sources and Scopes
Extensions can come from three scopes:
| Scope | Typical source | Behavior |
|---|---|---|
| Built in | nanobot package | Trusted by construction; shown for ownership and diagnostics |
| User | `~/.nanobot/extensions/` | Installed and governed through the WebUI or CLI |
| Workspace | `<workspace>/.nanobot/extensions/` | Project-local code; controlled by workspace trust policy |
When the same extension ID exists in multiple scopes, the nearest scope wins:
workspace over user, user over built in. A contribution cannot silently replace
another extension's contribution. Explicit replacement metadata and sufficient
scope are required.
## Pi and OpenClaw Packages
nanobot reads native Pi and OpenClaw package metadata and runs supported
JavaScript or TypeScript entries in a Node.js sidecar. Compatibility is not
all-or-nothing:
- Tools, slash commands, and supported lifecycle observation hooks can run.
- Provider-like registrations and several host-specific capabilities may be
cataloged but not executable.
- Terminal UI, session-tree, renderer, shortcut, and model-control APIs do not
have equivalent nanobot host surfaces.
- Every degraded or unsupported registration appears in diagnostics.
Check the [compatibility matrix](./extension-authoring.md#compatibility-matrix)
before depending on a package. A package appearing in search results means its
metadata is recognizable, not that every upstream API is implemented.
## Trust and Permissions
An extension is executable code. Review it with the same care as a Python or npm
dependency.
- **Enabled** says the extension may activate.
- **Trusted** says you approve executing its code.
- **Granted permissions** are exact host capabilities approved for that
extension.
- **Dependencies** must be present before activation.
Permissions are host policy, not an operating-system sandbox. A trusted native
Python extension executes in the nanobot process. A Pi or OpenClaw extension
executes in a separate Node.js process, which improves failure isolation but is
not a strong OS security boundary. Use containers or another OS sandbox for
untrusted third-party code.
npm installation uses lifecycle scripts disabled. This prevents package
`preinstall` and `postinstall` scripts from running during installation, but the
extension entry itself will run after you explicitly trust and enable it.
## Configuration
Most users should manage installed packages in the WebUI or CLI. Advanced
deployments can also define extension policy in `~/.nanobot/config.json`:
```json
{
"extensions": {
"enabled": true,
"paths": ["/opt/nanobot/extensions"],
"allow": [],
"deny": ["acme.blocked"],
"workspaceTrust": "ask",
"entries": {
"acme.review": {
"enabled": true,
"trusted": true,
"permissions": ["workspace.read"],
"config": {
"mode": "strict"
}
}
}
}
}
```
Config entries do not rewrite the installation registry. See
[Configuration](./configuration.md#extensions) for exact fields.
## Diagnose an Inactive Extension
Start with:
```bash
nanobot extensions list
nanobot extensions inspect <extension-id>
```
Common causes:
| State or diagnostic | What to do |
|---|---|
| Untrusted | Review the package, then use `trust` |
| Requested permission pending | Grant the exact requested permission set |
| Disabled | Use `enable` or remove it from `extensions.deny` |
| Missing dependency | Install the named package, executable, environment variable, or extension |
| Contribution conflict | Disable one owner or use an explicit replacement from an appropriate scope |
| Compatibility notice | Read which upstream API was translated, degraded, or unsupported |
| Activation failed | Check the package entry, runtime dependency, and gateway logs |
Policy changes reload the active extension host. A broken extension becomes a
diagnostic and does not prevent unrelated extensions from being discovered.
## Remove an Extension
```bash
nanobot extensions disable <extension-id>
nanobot extensions uninstall <extension-id>
```
Uninstall removes the user-scope package and its local policy record. It does
not remove a built-in capability or a separately configured workspace copy.