mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-04 08:28:36 +00:00
docs(extensions): document management and compatibility
This commit is contained in:
parent
41bebdcdb5
commit
bbaafd0f4f
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
294
docs/extension-authoring.md
Normal 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.
|
||||
@ -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
189
docs/extensions.md
Normal 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.
|
||||
Loading…
x
Reference in New Issue
Block a user