Tools
Outline Wiki
OpenClaw plugin from Cereb-ai/openclaw-outline-wiki-plugin
Install
npm install
npm
Configuration Example
{
"plugins": {
"entries": {
"outline-wiki-openclaw-plugin": {
"enabled": true,
"config": {
"apiToken": "<Outline API bearer token>",
"endpoint": "https://your-outline.example.com/api",
"mcpEndpoint": "https://your-outline.example.com/mcp",
"defaultCollectionId": "<optional UUID, used when outline_doc_create omits collectionId>"
}
}
}
}
}
README
# @cereb/outline-wiki-openclaw-plugin
[](LICENSE)
[](package.json)
[](https://docs.openclaw.ai)
OpenClaw native plugin for Outline Wiki knowledge bases — exposes **15 named tools** (one per Outline REST method), each invocable directly from an OpenClaw agent or the bundled `outline-tool` CLI. Replaces the legacy single-dispatcher pattern with one named tool per Outline REST method.
## Features
- **15 named tools** covering documents, search, collections, attachments, and revision history.
- **Two invocation paths** — call as an OpenClaw named tool, or use the bundled `outline-tool` CLI from OpenCode, a terminal, or CI.
- **CLI ↔ MCP aligned behavior** — every method's parameters, defaults, fallbacks, and verify behavior are consistent between the OpenClaw tool and the CLI (e.g. `outline_search_query.limit` defaults to `25`, `outline_doc_create.collectionId` falls back to `defaultCollectionId` config, post-create verify via `documents.info`). See `skills/outline-wiki/SKILL.md` for the behavior table.
- **Document hierarchy** — `outline_doc_create` and `outline_doc_move` accept an optional `parentDocumentId` to nest a document under a parent in the same call.
- **Fail-fast on missing config** — clear error messages, never silent fallback.
- **Single round-trip** — `outline_doc_get` already returns the full markdown body in `data.text`; no second `documents.export` call needed.
## Tools
| tool | purpose | required args |
|---|---|---|
| `outline_doc_list` | list documents (metadata only — `text` stripped, see Response-trim contract below) | — |
| `outline_doc_get` | single document + full markdown body | `id` |
| `outline_doc_create` | create document (publish=true default; accepts `parentDocumentId`); `collectionId` falls back to `defaultCollectionId` config; verifies result via `documents.info`; **response trims `document.text`** (CP-2379 — round-trip trim) | `title`, `text`, `collectionId` (or `defaultCollectionId` config) |
| `outline_doc_update` | update text / title. `editMode` picks how `text` is applied — `replace` (default, full overwrite) / `append` / `prepend` / `patch` (`patch` requires `findText`; server returns 400 if missing or 404 if not matched — never silently replaces the whole document); supports `publish`, `changelog` (best-effort revision-name write), `strictChangelog`; **rejects `parentDocumentId`** (use `outline_doc_move` to reparent); **response trims `document.text`** (CP-2379 — round-trip trim). **CP-3689 patch guardrail**: for `editMode=patch` the plugin requires `findText` to match exactly once before sending any update (0 or >1 matches → error, no write) and reads the body back afterwards to verify the change landed (`patchVerification` + `warnings`) | `id` + (`text` or `title`) |
| `outline_doc_delete` | trash (default) or hard-delete (`permanent: true`, requires already-trashed) | `id` |
| `outline_doc_archive` | move to archive (admin-readable, recoverable) | `id` |
| `outline_doc_restore` | restore from archive | `id` |
| `outline_doc_move` | move to a different collection (accepts `parentDocumentId` to reparent in the same call) | `id`, `collectionId` |
| `outline_search_query` | full-text search (limit default `25`, not `10`); **per-hit `document.text` stripped** (CP-2379) — keep ranking/context + nav metadata | `query` |
| `outline_collection_list` | list all collections | — |
| `outline_collection_documents` | list documents in a collection (includes children structure) | `id` (collection id) |
| `outline_collection_create` | create collection (default `permission="read_write"`, `sharing=true`) | `name` |
| `outline_collection_update` | update collection fields | `id` + (`name` / `description` / `icon` / `color` / `permission` / `sharing` 至少一项) |
| `outline_attachment_upload` | upload via S3 presigned POST (`url` or `path` mode) | `name` + (`url` or `path`) |
| `outline_rev_log` | revision metadata (name / timestamp / author) for a document | `documentId` |
Per-tool argument schemas, the OpenClaw agent skill, and the 避坑清单 live in [`skills/outline-wiki/SKILL.md`](skills/outline-wiki/SKILL.md).
## Response-trim contract (CP-2379)
Four high-frequency handlers strip the full markdown body (`text`) from their toolResult payload to keep the planner token spend in check (toolResult accounts for 77-86% of per-task token cost on cereb-pilot — see CP-2378):
- `outline_search_query` — per-hit `document.text` is stripped; keep `ranking` + `context` (already a snippet) + inner-document nav metadata (`id` / `title` / `url` / `urlId` / `collectionId` / `updatedAt`).
- `outline_doc_list` — `text` is stripped from every doc; nav metadata preserved.
- `outline_doc_create` / `outline_doc_update` — round-trip trim: the agent just sent the body via `text`, so it does NOT come back in `document.text`. Trimmed `document` (nav metadata) + the convenience `summary` (`id` / `title` / `url` / `urlId` / `revision` / `publishedAt` or `updatedAt`) are returned instead.
- `outline_doc_get` is intentionally NOT trimmed — that's the canonical "fetch the body" call.
The CLI (`outline-tool`) shares the same trim helpers (`trimDocBody` / `trimSearchHit` in `src/cli.ts`), so MCP and CLI byte-for-byte parity on response shape is preserved (`tests/cli-vs-mcp-parity.test.ts` + `tests/response-trim.test.ts` enforce this).
Regression tests: `tests/response-trim.test.ts` — 14 cases asserting no `text` round-trips, MCP ↔ CLI parity on every trimmed handler.
## Installation
### From local source (development)
```bash
git clone https://github.com/Cereb-ai/openclaw-outline-wiki-plugin.git
cd openclaw-outline-wiki-plugin
npm install
npm run build
npm pack
openclaw plugins install "npm-pack:./$(ls cereb-outline-wiki-openclaw-plugin-*.tgz | head -1)" --force
systemctl --user restart openclaw-gateway.service # required to load the new plugin
```
### From npm (once published)
```bash
npm install -g @cereb/outline-wiki-openclaw-plugin
openclaw plugins install "@cereb/outline-wiki-openclaw-plugin"
systemctl --user restart openclaw-gateway.service
```
## Configuration
The plugin reads config in this order (highest priority first):
1. `plugins.entries.outline-wiki-openclaw-plugin.config` in `~/.openclaw/openclaw.json`
2. Environment variables (`OUTLINE_API_TOKEN` / `OUTLINE_TOKEN`, `OUTLINE_ENDPOINT`, `OUTLINE_MCP_ENDPOINT`)
### `~/.openclaw/openclaw.json`
```json
{
"plugins": {
"entries": {
"outline-wiki-openclaw-plugin": {
"enabled": true,
"config": {
"apiToken": "<Outline API bearer token>",
"endpoint": "https://your-outline.example.com/api",
"mcpEndpoint": "https://your-outline.example.com/mcp",
"defaultCollectionId": "<optional UUID, used when outline_doc_create omits collectionId>"
}
}
}
}
}
```
### Environment variables
| variable | required | default | description |
|---|---|---|---|
| `OUTLINE_API_TOKEN` (or `OUTLINE_TOKEN`) | ✅ | — | Outline API bearer token |
| `OUTLINE_ENDPOINT` | ✅ | — | Outline API base URL, e.g. `https://your-outline.example.com/api` |
| `OUTLINE_MCP_ENDPOINT` | ❌ | same host as `OUTLINE_ENDPOINT` | MCP endpoint for S3 pre-signed attachment uploads |
Any missing required variable → fail-fast at startup with an actionable error pointing at the missing field.
## Usage
**OpenClaw native tool** (default for agents):
```json
outline_doc_list { limit: 5 }
outline_search_query { query: "redis sentinel", limit: 10 }
outline_doc_get { id: "<doc-uuid>" }
outline_doc_create { title: "...", text: "...", collectionId: "<uuid>", publish: true }
outline_doc_update { id: "<doc-uuid>", text: "...", editMode: "replace" }
# In-place edit (cheapest — caller sends only the delta; requires `findText`):
outline_doc_update { id: "<doc-uuid>", text: "new wording", editMode: "patch", findText: "old wording" }
# Append a section:
outline_doc_update { id: "<doc-uuid>", text: "\n## New section\n...", editMode: "append" }
outline_doc_move { id: "<doc-uuid>", collectionId: "<target-uuid>", parentDocumentId: "<parent-uuid>" }
outline_attachment_upload { name: "x.png", url: "<public-url>", documentId: "<doc-uuid>", preset: "documentAttachment" }
```
**Standalone CLI** `outline-tool` (for OpenCode, terminal, CI):
The CLI accepts the same method names as the MCP tools (`outline_*` long names or short `category.method`), the same parameters, the same defaults, the same fallbacks, and the same verify behavior. **Same args, same wire body, same response** — see "CLI ↔ MCP behavior" below.
```bash
# MCP names (preferred — match OpenClaw tool names verbatim)
outline-tool outline_doc_list '{"limit":2}'
outline-tool outline_doc_get '{"id":"..."}'
outline-tool outline_search_query '{"query":"redis sentinel"}'
outline-tool outline_doc_create '{"title":"...","text":"...","collectionId":"..."}'
outline-tool outline_doc_update '{"id":"...","text":"...","editMode":"replace","changelog":"..."}'
# In-place edit (cheapest; requires findText):
outline-tool outline_doc_update '{"id":"...","text":"new","editMode":"patch","findText":"old"}'
outline-tool outline_collection_create '{"name":"..."}'
outline-tool outline_collection_update '{"id":"...","permission":"read_write"}'
outline-tool outline_rev_log '{"documentId":"...","limit":5}'
outline-tool outline_attachment_upload '{"name":"x.png","url":"https://...","documentId":"...","preset":"documentAttachment"}'
# Short names (backward compat) — same args
outline-tool doc.list '{"limit":2}'
outline-tool doc.get '{"id":"..."}'
outline-tool search.query '{"query":"redis sentinel"}'
outline-tool attachment.upload '{"name":"x.png","url":"https://...","documentId":"...","preset":"documentAttachment"}'
```
Exit codes: `0` = success, `2` = JSON parse error, `3` = dispatch error, `4` = sh
... (truncated)
tools
Comments
Sign in to leave a comment