docs: recommend tools.alsoAllow for optional plugin tools

This commit is contained in:
Vignesh Natarajan
2026-01-25 00:40:13 -08:00
committed by Pocket Clawd
parent d62b7c0d1e
commit 3497be2963
5 changed files with 24 additions and 6 deletions

View File

@@ -201,7 +201,7 @@ For ad-hoc workflows, call Lobster directly.
- Lobster runs as a **local subprocess** (`lobster` CLI) in tool mode and returns a **JSON envelope**.
- If the tool returns `needs_approval`, you resume with a `resumeToken` and `approve` flag.
- The tool is an **optional plugin**; you must allowlist `lobster` in `tools.allow`.
- The tool is an **optional plugin**; enable it additively via `tools.alsoAllow: ["lobster"]` (recommended).
- If you pass `lobsterPath`, it must be an **absolute path**.
See [Lobster](/tools/lobster) for full usage and examples.

View File

@@ -158,7 +158,19 @@ If you want to use a custom binary location, pass an **absolute** `lobsterPath`
## Enable the tool
Lobster is an **optional** plugin tool (not enabled by default). Allow it per agent:
Lobster is an **optional** plugin tool (not enabled by default).
Recommended (additive, safe):
```json
{
"tools": {
"alsoAllow": ["lobster"]
}
}
```
Or per-agent:
```json
{
@@ -167,7 +179,7 @@ Lobster is an **optional** plugin tool (not enabled by default). Allow it per ag
{
"id": "main",
"tools": {
"allow": ["lobster"]
"alsoAllow": ["lobster"]
}
}
]
@@ -175,7 +187,7 @@ Lobster is an **optional** plugin tool (not enabled by default). Allow it per ag
}
```
You can also allow it globally with `tools.allow` if every agent should see it.
Avoid using `tools.allow: ["lobster"]` unless you intend to run in restrictive allowlist mode.
Note: allowlists are opt-in for optional plugins. If your allowlist only names
plugin tools (like `lobster`), Clawdbot keeps core tools enabled. To restrict core

View File

@@ -346,7 +346,7 @@ export function createClawdbotCodingTools(options?: {
if (resolved.unknownAllowlist.length > 0) {
const entries = resolved.unknownAllowlist.join(", ");
const suffix = resolved.strippedAllowlist
? "Ignoring allowlist so core tools remain available."
? "Ignoring allowlist so core tools remain available. Use tools.alsoAllow for additive plugin tool enablement."
: "These entries won't match any tool unless the plugin is enabled.";
logWarn(`tools: ${label} allowlist contains unknown entries (${entries}). ${suffix}`);
}

View File

@@ -209,6 +209,12 @@ export function stripPluginOnlyAllowlist(
if (!isCoreEntry && !isPluginEntry) unknownAllowlist.push(entry);
}
const strippedAllowlist = !hasCoreEntry;
// When an allowlist contains only plugin tools, we strip it to avoid accidentally
// disabling core tools. Users who want additive behavior should prefer `tools.alsoAllow`.
if (strippedAllowlist) {
// Note: logging happens in the caller (pi-tools/tools-invoke) after this function returns.
// We keep this note here for future maintainers.
}
return {
policy: strippedAllowlist ? { ...policy, allow: undefined } : policy,
unknownAllowlist: Array.from(new Set(unknownAllowlist)),

View File

@@ -189,7 +189,7 @@ export async function handleToolsInvokeHttpRequest(
if (resolved.unknownAllowlist.length > 0) {
const entries = resolved.unknownAllowlist.join(", ");
const suffix = resolved.strippedAllowlist
? "Ignoring allowlist so core tools remain available."
? "Ignoring allowlist so core tools remain available. Use tools.alsoAllow for additive plugin tool enablement."
: "These entries won't match any tool unless the plugin is enabled.";
logWarn(`tools: ${label} allowlist contains unknown entries (${entries}). ${suffix}`);
}