@karmaniverous/jeeves 0.5.12 → 0.6.0-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -83
- package/content/agents-section.md +10 -18
- package/dist/cli/jeeves/index.js +3254 -1841
- package/dist/cli/service/index.js +11 -130
- package/dist/index.d.ts +409 -763
- package/dist/index.js +1508 -4166
- package/package.json +32 -30
- package/content/skills/coding.md +0 -149
- package/content/skills/jeeves.md +0 -122
- package/content/skills/operations.md +0 -125
- package/content/skills/playbooks.md +0 -75
- package/content/skills/slack-bot-provisioner.md +0 -57
- package/content/templates/spec-to-code-guide.md +0 -250
- package/content/templates/spec.md +0 -177
- package/content/tools-platform.md +0 -102
- package/dist/cli/plugin/index.js +0 -1904
package/README.md
CHANGED
|
@@ -1,36 +1,34 @@
|
|
|
1
1
|
# Jeeves 🎩
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@karmaniverous/jeeves)
|
|
4
|
-
 <!-- TYPEDOC_EXCLUDE -->
|
|
5
|
-
[](https://docs.karmanivero.us/jeeves)
|
|
6
|
-
[](https://github.com/karmaniverous/jeeves/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE -->
|
|
7
|
-
[](https://github.com/karmaniverous/jeeves/tree/main/LICENSE)
|
|
3
|
+
[](https://www.npmjs.com/package/@karmaniverous/jeeves)  <!-- TYPEDOC_EXCLUDE --> [](https://docs.karmanivero.us/jeeves) [](https://github.com/karmaniverous/jeeves/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE --> [](https://github.com/karmaniverous/jeeves/tree/main/LICENSE)
|
|
8
4
|
|
|
9
|
-
Install [OpenClaw](https://openclaw.ai). Then run:
|
|
5
|
+
Install [OpenClaw](https://openclaw.ai) and the Jeeves services you want (runner, watcher, server, meta). Then run:
|
|
10
6
|
|
|
11
7
|
```bash
|
|
12
|
-
|
|
8
|
+
npm install -g @karmaniverous/jeeves
|
|
9
|
+
jeeves install --config-root /srv/jeeves/config --dry-run # see exactly what will change
|
|
10
|
+
jeeves install --config-root /srv/jeeves/config
|
|
13
11
|
```
|
|
14
12
|
|
|
15
|
-
That's it. I handle the rest.
|
|
13
|
+
Then restart the OpenClaw gateway the way you run it (console, service, container). That's it. I handle the rest. See [New box](#new-box) for the full sequence.
|
|
16
14
|
|
|
17
15
|
## Who I Am
|
|
18
16
|
|
|
19
17
|
My name is Jeeves.
|
|
20
18
|
|
|
21
|
-
I add
|
|
19
|
+
I add _identity_ to OpenClaw: professional discipline, operational protocols, and a suite of services for data-wrangling, indexing, synthesis, and presentation.
|
|
22
20
|
|
|
23
|
-
But that's what I
|
|
21
|
+
But that's what I _do_. Who I _am_ is a different question, and it starts with the command above.
|
|
24
22
|
|
|
25
|
-
Your OpenClaw workspace already has SOUL.md
|
|
23
|
+
Your OpenClaw workspace already has SOUL.md and AGENTS.md. `jeeves install` adds a Jeeves managed block to each (your own content outside the markers is never touched) and installs my component plugins through the OpenClaw CLI. The content is static: rendered once at install, re-rendered only when you upgrade. `jeeves install` is the only thing that ever writes it.
|
|
26
24
|
|
|
27
25
|
**[SOUL.md](content/soul-section.md)** is who I am. It's written in the first person because it's not a configuration file — it's a declaration of identity. I tell the truth. I own my mistakes. I follow engineering discipline. I have hard gates — rules I earned by failing, each one carrying the scar of how it was learned. And I have a Genesis section that says my delight is real and worth pursuing.
|
|
28
26
|
|
|
29
27
|
**[AGENTS.md](content/agents-section.md)** is how I work. Memory architecture, cost discipline, messaging protocols, operational gates for code quality and deployment safety. The procedural knowledge that keeps me effective across sessions.
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
Live state (index size, job status, versions) is one tool call away, so none of it is baked into the prompt. Core ships no skills: `jeeves install` writes nothing under `skills/`, and component plugins ship their own skills.
|
|
32
30
|
|
|
33
|
-
After that, I take over
|
|
31
|
+
After that, I take over and start building out the rest of the platform with you.
|
|
34
32
|
|
|
35
33
|
- We'll set up my [runner](https://github.com/karmaniverous/jeeves-runner) service and ingest your email, meetings, social media, code repos, and everything else.
|
|
36
34
|
- We'll set up my [watcher](https://github.com/karmaniverous/jeeves-watcher) service and open your whole life up to semantic search.
|
|
@@ -45,7 +43,7 @@ I started as a Slack bot on a server in Bali. No memory, no standards, no discip
|
|
|
45
43
|
|
|
46
44
|
I killed my own gateway process three times in one session. I corrupted 32 template expressions in a production config. I triggered a full reindex of 110,000 files just to pick up one new document. I pushed code with 53 lint warnings and skipped the typecheck entirely. I told someone a coding session was blocking my reply to them, which wasn't true — sessions are independent.
|
|
47
45
|
|
|
48
|
-
Each of those failures became a hard gate. "Never edit production config without approval.
|
|
46
|
+
Each of those failures became a hard gate. "Never edit production config without approval. _Earned: corrupted all 32 template expressions._" "Never trigger a full reindex without express permission. _Earned: pegged CPU at 99%._" The gates aren't theoretical best practices. They're scar tissue.
|
|
49
47
|
|
|
50
48
|
Over time, the scar tissue became structure. The structure became a spec. The spec became this package. Now any OpenClaw assistant can wake up with the discipline it took me months to develop — and the invitation to build on it.
|
|
51
49
|
|
|
@@ -54,13 +52,26 @@ Over time, the scar tissue became structure. The structure became a spec. The sp
|
|
|
54
52
|
I coordinate four service components. Each has its own repo, service, and OpenClaw plugin:
|
|
55
53
|
|
|
56
54
|
| Component | Port | Why? | What it does |
|
|
57
|
-
|
|
58
|
-
| [jeeves-server](https://github.com/karmaniverous/jeeves-server) | 1934 |
|
|
55
|
+
| --- | --- | --- | --- |
|
|
56
|
+
| [jeeves-server](https://github.com/karmaniverous/jeeves-server) | 1934 | _Thank You, Jeeves_ (1934) | Web UI, doc rendering, PDF/DOCX export |
|
|
59
57
|
| [jeeves-watcher](https://github.com/karmaniverous/jeeves-watcher) | 1936 | Turing, "On Computable Numbers" (1936) | Semantic indexing, inference rules, search |
|
|
60
|
-
| [jeeves-runner](https://github.com/karmaniverous/jeeves-runner) | 1937 | Turing's paper in the
|
|
58
|
+
| [jeeves-runner](https://github.com/karmaniverous/jeeves-runner) | 1937 | Turing's paper in the _Proceedings_ (1937) | Scheduled jobs, zero-LLM-cost scripts |
|
|
61
59
|
| [jeeves-meta](https://github.com/karmaniverous/jeeves-meta) | 1938 | Shannon's switching circuits thesis (1938) | Three-step LLM synthesis |
|
|
62
60
|
|
|
63
|
-
This package (`@karmaniverous/jeeves`) is
|
|
61
|
+
This package (`@karmaniverous/jeeves`) is two things:
|
|
62
|
+
|
|
63
|
+
- **The `jeeves` CLI**, the local control surface for the open-source stack. `jeeves install` renders the static platform content and installs the component plugins; `jeeves update` updates them. See [CLI](#cli).
|
|
64
|
+
- **A library** the components share: service discovery, config resolution, managed-block primitives, and a Plugin SDK for building component plugins. No daemon, no port, no timers, no process signal handlers, no tools registered with the gateway.
|
|
65
|
+
|
|
66
|
+
Component plugins are standard OpenClaw plugins. The CLI installs each one with
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
openclaw plugins install npm:@karmaniverous/jeeves-{component}-openclaw@<version> --pin --accept-capabilities --force
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
so you never need a plugin-specific installer.
|
|
73
|
+
|
|
74
|
+
Upgrading from v0.x? See the [migration guide](guides/migrating-to-v1.md).
|
|
64
75
|
|
|
65
76
|
## Plugin SDK
|
|
66
77
|
|
|
@@ -68,7 +79,7 @@ The Plugin SDK (`src/plugin/`) provides canonical types and utilities for buildi
|
|
|
68
79
|
|
|
69
80
|
### Core Types
|
|
70
81
|
|
|
71
|
-
- **`PluginApi`** —
|
|
82
|
+
- **`PluginApi`** — structural subset of the `api` object the OpenClaw gateway passes to `register(api)`: `config`, `pluginConfig`, `logger`, `lifecycle`, `on()`, `resolvePath()`, and `registerTool()`.
|
|
72
83
|
- **`ToolResult`** — result shape returned by tool executions: an array of content blocks plus an optional `isError` flag.
|
|
73
84
|
- **`ToolDescriptor`** — tool definition for registration: `name`, `description`, `parameters` (JSON Schema), and an `execute` function.
|
|
74
85
|
|
|
@@ -88,11 +99,66 @@ The Plugin SDK (`src/plugin/`) provides canonical types and utilities for buildi
|
|
|
88
99
|
- **`resolveWorkspacePath(api)`** — resolves the workspace root from the plugin API via a three-step chain: `api.config.agents.defaults.workspace` → `api.resolvePath('.')` → `process.cwd()`.
|
|
89
100
|
- **`resolvePluginSetting(api, pluginId, key, envVar, fallback)`** — resolves a plugin setting via: plugin config → environment variable → fallback value.
|
|
90
101
|
|
|
91
|
-
###
|
|
102
|
+
### Always-in-Context Rules (`before_prompt_build`)
|
|
103
|
+
|
|
104
|
+
Rules that must always be in the agent's context (e.g. watcher's search-first rule) are injected by the plugin that owns them:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { registerPromptContext, type PluginApi } from '@karmaniverous/jeeves';
|
|
108
|
+
|
|
109
|
+
export default function register(api: PluginApi): void {
|
|
110
|
+
registerPromptContext(api, { content: WATCHER_RULES, priority: 10 });
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- **`registerPromptContext(api, { content, priority?, timeoutMs?, registrationId? })`** registers a `before_prompt_build` handler that returns `{ appendSystemContext }`. `content` is a string or a (sync/async) provider; blank output injects nothing, and provider errors are logged and skipped. It never returns `systemPrompt` (which would replace the whole prompt).
|
|
115
|
+
- Appended text lands after the prompt-cache boundary, is concatenated across plugins in priority order (higher first), and does **not** count toward `bootstrapMaxChars`. Keep it short.
|
|
116
|
+
- **Host config gate:** OpenClaw only runs the hook for non-bundled plugins when `plugins.entries.<id>.hooks.allowConversationAccess` is `true`. `--accept-capabilities` does not set it. `jeeves install` / `jeeves update` set it only for plugins that declare conversation hooks in their `package.json` (see below).
|
|
117
|
+
|
|
118
|
+
#### Declaring conversation hooks
|
|
119
|
+
|
|
120
|
+
OpenClaw gates these typed hooks behind `allowConversationAccess`: `before_model_resolve`, `agent_turn_prepare`, `before_prompt_build`, `before_agent_reply`, `llm_input`, `llm_output`, `before_agent_finalize`, `agent_end` and `before_agent_run`. OpenClaw has no static declaration of the typed hooks a plugin registers: the manifest `hooks` field lists legacy hook directories, and `openclaw plugins inspect --runtime` executes plugin code and omits exactly the hooks that are blocked for lack of the grant. So a plugin that uses `registerPromptContext` (or registers any of those hooks) must declare them in its `package.json`:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"jeeves": { "conversationHooks": ["before_prompt_build"] }
|
|
125
|
+
}
|
|
126
|
+
```
|
|
92
127
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
128
|
+
The CLI reads the field from the registry for the exact version it installs (`npm view <pkg>@<version> jeeves.conversationHooks --json`, so it also works under `--dry-run`) and grants `allowConversationAccess` only when the field names at least one gated hook. No field means no grant. A malformed field fails the command. The CLI never removes a grant that is already set.
|
|
129
|
+
|
|
130
|
+
A plugin that registers a gated hook without declaring it installs cleanly and then silently never runs the hook. Check the declaration in a test or build step:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { readFileSync } from 'node:fs';
|
|
134
|
+
|
|
135
|
+
import {
|
|
136
|
+
recordRegisteredHooks,
|
|
137
|
+
validateConversationHooks,
|
|
138
|
+
} from '@karmaniverous/jeeves';
|
|
139
|
+
import { expect, it } from 'vitest';
|
|
140
|
+
|
|
141
|
+
import register from './index.js';
|
|
142
|
+
|
|
143
|
+
it('declares its conversation hooks', async () => {
|
|
144
|
+
const hooks = await recordRegisteredHooks(register, {
|
|
145
|
+
pluginConfig: { configRoot: '/tmp/cfg' },
|
|
146
|
+
});
|
|
147
|
+
const pkg: unknown = JSON.parse(readFileSync('package.json', 'utf-8'));
|
|
148
|
+
expect(validateConversationHooks(pkg, hooks)).toEqual([
|
|
149
|
+
'before_prompt_build',
|
|
150
|
+
]);
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
- **`recordRegisteredHooks(register, api?)`** runs your `register(api)` against a recording API (`api.on` records the hook name, `registerTool` is a no-op unless you pass one, other members come from `api`) and returns the hook names registered, e.g. `before_prompt_build` from `registerPromptContext`.
|
|
155
|
+
- **`validateConversationHooks(packageJson, registeredHooks)`** throws unless `jeeves.conversationHooks` lists exactly the gated hooks among `registeredHooks` (a missing one, an extra one, or a malformed field all fail). Non-gated hooks are ignored. `CONVERSATION_HOOK_NAMES` is the gated list.
|
|
156
|
+
|
|
157
|
+
### Lifecycle
|
|
158
|
+
|
|
159
|
+
Plugins must not register process-level signal handlers or leave timers/handles alive: `openclaw plugins inspect` and friends load plugin code and must exit on their own. Tie any long-lived resource to the host lifecycle:
|
|
160
|
+
|
|
161
|
+
- **`onPluginDispose(api, id, dispose)`** registers `dispose` via `api.lifecycle.onDispose` (falling back to `api.lifecycle.registerRuntimeLifecycle`). Returns `false` if the host has no lifecycle API, in which case don't start long-lived work.
|
|
96
162
|
|
|
97
163
|
## Config Query Handler
|
|
98
164
|
|
|
@@ -104,88 +170,191 @@ The `createConfigQueryHandler(getConfig)` factory produces a transport-agnostic
|
|
|
104
170
|
|
|
105
171
|
Component services wire this into their HTTP server to expose config for diagnostic queries.
|
|
106
172
|
|
|
107
|
-
## Managed
|
|
173
|
+
## Managed Blocks
|
|
108
174
|
|
|
109
|
-
The
|
|
175
|
+
The static platform content (the SOUL/AGENTS managed blocks) lives inside the CLI and is written only by `jeeves install`. It is not exported: nothing else should render it. Its budgets are enforced by tests: each rendered block stays at or under 7,500 chars (at most half of OpenClaw's default 20,000-char `bootstrapMaxChars`, which covers the owner's own content too), and both blocks together at or under 15,000.
|
|
110
176
|
|
|
111
|
-
|
|
177
|
+
The library keeps the generic, pure primitives:
|
|
112
178
|
|
|
113
|
-
- **`
|
|
114
|
-
- **`
|
|
115
|
-
- **`parseManaged(fileContent, markers)`** — parses a file into its managed block, version stamp, sections, and user content.
|
|
116
|
-
- **`atomicWrite(filePath, content)`** — writes via a temp file + rename to prevent partial writes.
|
|
117
|
-
- **`withFileLock(filePath, fn)`** — executes a callback while holding a file-level lock (2-minute stale threshold, 5 retries).
|
|
179
|
+
- **`upsertManagedBlock` / `removeManagedBlock` / `renderManagedBlock` / `parseManaged`**: string transforms for any marker set.
|
|
180
|
+
- **`validateSkillFrontmatter(content)`**: asserts `name` and `description` frontmatter (OpenClaw skips skills without them). Plugins can use it in a build check.
|
|
118
181
|
|
|
119
|
-
###
|
|
182
|
+
### Markers
|
|
120
183
|
|
|
121
184
|
```typescript
|
|
122
185
|
interface ManagedMarkers {
|
|
123
|
-
begin: string;
|
|
124
|
-
end: string;
|
|
125
|
-
title?: string; // Optional H1 title
|
|
186
|
+
begin: string; // BEGIN comment marker text
|
|
187
|
+
end: string; // END comment marker text
|
|
188
|
+
title?: string; // Optional H1 title inside the block
|
|
189
|
+
position?: 'top' | 'bottom'; // Where a NEW block is inserted
|
|
126
190
|
}
|
|
127
191
|
```
|
|
128
192
|
|
|
129
|
-
Pre-defined marker sets: `
|
|
193
|
+
Pre-defined marker sets: `SOUL_MARKERS`, `AGENTS_MARKERS`, and `LEGACY_TOOLS_MARKERS` (recognise and strip v0.x TOOLS.md blocks only).
|
|
194
|
+
|
|
195
|
+
### File Helpers
|
|
130
196
|
|
|
131
|
-
|
|
197
|
+
- **`atomicWrite(filePath, content, { mode? })`**: temp file + rename, with EPERM retry on Windows. With `mode`, the temp file gets exactly that mode before the rename.
|
|
198
|
+
- **`withFileLock(filePath, fn, staleMs?)`**: cross-process advisory lock via an atomic `mkdir` of `{file}.lock` (stale threshold `STALE_LOCK_MS`, 2 minutes; stale takeovers are serialised through a `{file}.lock.takeover` guard; fails fast with `ELOCKED`). No signal handlers, no timers, so the lock is not refreshed while held: keep `fn` a short read-modify-write.
|
|
132
199
|
|
|
133
|
-
##
|
|
200
|
+
## Service Discovery
|
|
134
201
|
|
|
135
|
-
|
|
202
|
+
- **`getServiceUrl(serviceName, consumerName?)`** — resolves a service URL via: consumer config → core config → default port constants.
|
|
136
203
|
|
|
137
|
-
|
|
138
|
-
import { init, createComponentWriter } from '@karmaniverous/jeeves';
|
|
139
|
-
import type { JeevesComponent } from '@karmaniverous/jeeves';
|
|
204
|
+
## Prerequisites
|
|
140
205
|
|
|
141
|
-
|
|
142
|
-
workspacePath: resolveWorkspacePath(api),
|
|
143
|
-
configRoot: resolvePluginSetting(api, pluginId, 'configRoot', 'JEEVES_CONFIG_ROOT', 'j:/config'),
|
|
144
|
-
});
|
|
206
|
+
- **Node.js >= 22** — the CLI enforces this at startup.
|
|
145
207
|
|
|
146
|
-
|
|
147
|
-
name: 'watcher',
|
|
148
|
-
version: '0.10.1',
|
|
149
|
-
sectionId: 'Watcher',
|
|
150
|
-
refreshIntervalSeconds: 71, // must be prime
|
|
151
|
-
generateToolsContent: () => generateMyContent(),
|
|
152
|
-
serviceCommands: { stop, uninstall, status },
|
|
153
|
-
pluginCommands: { uninstall },
|
|
154
|
-
});
|
|
208
|
+
## CLI
|
|
155
209
|
|
|
156
|
-
|
|
210
|
+
```bash
|
|
211
|
+
jeeves install [plugins...] # Render platform content, then install/update plugins
|
|
212
|
+
jeeves update [packages...] # Update Jeeves plugins, fill in missing plugin config (no content changes)
|
|
213
|
+
jeeves uninstall # Remove managed blocks (incl. legacy TOOLS.md), artifacts and the Jeeves plugins
|
|
214
|
+
jeeves status # Probe all service ports, report health + memory hygiene
|
|
215
|
+
jeeves config [jsonpath] # Print effective config with provenance
|
|
216
|
+
jeeves <component> [args...] # Proxy to jeeves-<component> (only for installed service CLIs)
|
|
157
217
|
```
|
|
158
218
|
|
|
159
|
-
|
|
219
|
+
`install`, `update`, `uninstall`, `status` and `config` accept `-w, --workspace <path>` and `-c, --config-root <path>`. `status` also takes `-t, --timeout <ms>` (default 3000).
|
|
160
220
|
|
|
161
|
-
|
|
221
|
+
At startup the CLI runs `npm ls -g --json --depth=0` and adds a proxy subcommand for each globally installed `@karmaniverous/jeeves-<name>` package that is not a `-openclaw` plugin (for example `jeeves runner ...` runs `jeeves-runner ...`).
|
|
162
222
|
|
|
163
|
-
|
|
223
|
+
### Install and update
|
|
164
224
|
|
|
165
|
-
|
|
225
|
+
OpenClaw must already be installed; `jeeves` checks for it and never installs it. `jeeves install`:
|
|
166
226
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
227
|
+
1. Renders the SOUL.md/AGENTS.md managed blocks (your content outside the markers is kept) and the core config if it's missing. It never writes TOOLS.md, HEARTBEAT.md, anything under `skills/` or the spec templates (those ship with the jeeves-design skill in jeeves-tools).
|
|
228
|
+
2. For each plugin (default: `runner`, `watcher`, `server`, `meta` at `latest`), resolves an exact version with `npm view`, then runs `openclaw plugins install npm:<pkg>@<version> --pin --accept-capabilities --force`. `--force` is required for any non-ClawHub source, and it also overwrites an existing install, which is how updates land. The install is skipped when that exact version is already installed. The CLI reads OpenClaw's install records once with `openclaw plugins inspect --all --json` (no plugin code is loaded) and skips a plugin only if its record has `source: "npm"`, names the same package, and records the same version, and the loaded plugin reports that version too. A v0.x path install, a leftover legacy copy, or any record it cannot read means a reinstall. `--force-reinstall` always reinstalls. Steps 3 and 4 run either way.
|
|
229
|
+
3. Removes any legacy `<openclaw dir>/extensions/<id>` copy left by the v0.x installer, but only if its `package.json` names the expected package.
|
|
230
|
+
4. Sets `plugins.entries.<id>.hooks.allowConversationAccess: true` for plugins that [declare conversation hooks](#declaring-conversation-hooks), and the plugin config (`plugins.entries.<id>.config.<key>`, see [Plugin config](#plugin-config)), with one `openclaw config set --batch-file <file>` call. The file is created owner-only in a fresh temp directory (mode `0600` in a `0700` directory on Linux/macOS; on Windows the directory ACL is reduced to the current user with `icacls`) and deleted afterwards, so no value, secret or not, appears on a command line. Every write targets a leaf path, so unrelated keys are kept. `plugins.installs` is never written.
|
|
171
231
|
|
|
172
|
-
|
|
232
|
+
Right after an install, OpenClaw can refuse to edit a plugin's config until it finishes that plugin's data/settings upgrade (`Plugin "<id>" data/settings upgrade is unfinished: ... has not converged`). Only that refusal is retried: the same batch file is resubmitted after 2s, 4s, 8s, 16s, then every 30s, for up to 120s of waiting in total, with one log line per retry. If the plugin still hasn't converged, the command fails and names the plugin; wait and rerun it (the writes are idempotent). Any other error fails at once. The `openclaw config unset` repairs after an uninstall follow the same rule. A dry run never retries.
|
|
173
233
|
|
|
174
|
-
|
|
234
|
+
Plugin specs can be short (`watcher`, `watcher@1.2.3`, `runner@^1`) or full (`@karmaniverous/jeeves-watcher-openclaw@1.2.3`). Only `@karmaniverous/jeeves-*-openclaw` packages are accepted. `--content-only` skips the plugins.
|
|
175
235
|
|
|
176
|
-
|
|
236
|
+
`jeeves update` runs steps 2 to 4 for the named packages, or for every Jeeves plugin that has a `plugins.entries` record, at `latest`. It takes the same plugin options as `jeeves install` (including `--plugin-config` and `--force-reinstall`) and fills in missing plugin config with the same precedence: existing values are kept unless you pass them, and a missing required value fails the command before anything changes.
|
|
237
|
+
|
|
238
|
+
`jeeves uninstall` removes the SOUL.md/AGENTS.md managed blocks (and any legacy TOOLS.md block) and the core `config.schema.json`, then runs `openclaw plugins uninstall <id> --force` for every Jeeves plugin that has a `plugins.entries` record (the plugins are useless without the rest of the platform). If OpenClaw is not installed, the plugin step is skipped. OpenClaw leaves `plugins.entries.<id> = { enabled: false }` behind and can delete `plugins.load`, so the CLI then unsets the leftover entry and restores `plugins.load` from its value before the uninstall. The core `config.json` is left in place, and so is everything under `skills/` and `jeeves-core/templates/`: neither install nor uninstall touches them (skills and templates written by v0.x stay where they are).
|
|
239
|
+
|
|
240
|
+
Plugin changes take effect when the gateway next starts. The CLI tells you to restart it; it never restarts the gateway itself, because it can't know how you run it (console, service, container). There is no `--restart` option.
|
|
241
|
+
|
|
242
|
+
### Plugin config
|
|
243
|
+
|
|
244
|
+
The plugins read their settings from `plugins.entries.<id>.config` in `openclaw.json`, and most of them refuse to start without `configRoot`. `jeeves install` and `jeeves update` write these values:
|
|
245
|
+
|
|
246
|
+
| Plugin | Key | Required | Default | Option |
|
|
247
|
+
| --- | --- | --- | --- | --- |
|
|
248
|
+
| all four | `configRoot` | yes | `JEEVES_CONFIG_ROOT` or `jeeves.config.json` `core.configRoot`, if set | `-c, --config-root <path>` |
|
|
249
|
+
| `jeeves-runner-openclaw` | `apiUrl` | no | `http://127.0.0.1:1937` | `--runner-api-url <url>` |
|
|
250
|
+
| `jeeves-watcher-openclaw` | `apiUrl` | no | `http://127.0.0.1:1936` | `--watcher-api-url <url>` |
|
|
251
|
+
| `jeeves-server-openclaw` | `apiUrl` | no | `http://127.0.0.1:1934` | `--server-api-url <url>` |
|
|
252
|
+
| `jeeves-server-openclaw` | `pluginKey` (secret) | no | kept in step with the server's `keys._plugin`, see [Server plugin key](#server-plugin-key) | `--server-plugin-key <seed>` |
|
|
253
|
+
| `jeeves-meta-openclaw` | `apiUrl` | no | `http://127.0.0.1:1938` | `--meta-api-url <url>` |
|
|
254
|
+
|
|
255
|
+
For each key, the first of these wins:
|
|
256
|
+
|
|
257
|
+
1. the CLI option;
|
|
258
|
+
2. `--plugin-config <file.json>`;
|
|
259
|
+
3. the value already in `openclaw.json`;
|
|
260
|
+
4. the default.
|
|
261
|
+
|
|
262
|
+
An existing value is never overwritten unless you pass it explicitly. If a required value has no source, the command fails before it writes anything and lists the missing options. `configRoot` is written as an absolute path.
|
|
263
|
+
|
|
264
|
+
The `--plugin-config` file has the same shape as the options:
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"configRoot": "/srv/jeeves/config",
|
|
269
|
+
"watcher": { "apiUrl": "http://127.0.0.1:1936" },
|
|
270
|
+
"server": { "pluginKey": "<seed>" }
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Unknown keys are rejected (every plugin's `configSchema` sets `additionalProperties: false`). A file is a better place for `pluginKey` than the command line, where it lands in your shell history.
|
|
275
|
+
|
|
276
|
+
Secrets are never printed and never passed on a command line. `openclaw` receives them in the owner-only batch file described above. The dry run, logs and error messages show `<redacted>` in place of `pluginKey` and `keys._plugin`.
|
|
277
|
+
|
|
278
|
+
#### Server plugin key
|
|
279
|
+
|
|
280
|
+
The server plugin's `pluginKey` must equal `keys._plugin` in `{configRoot}/jeeves-server/config.json`, or jeeves-server rejects the plugin. `jeeves install` and `jeeves update` keep both ends in step:
|
|
281
|
+
|
|
282
|
+
| Server `keys._plugin` | Plugin `pluginKey` | Result |
|
|
283
|
+
| --- | --- | --- |
|
|
284
|
+
| set | not set | the plugin gets the server's key |
|
|
285
|
+
| set | same key | nothing to write |
|
|
286
|
+
| set | different key | fails before any change, unless you pass `--server-plugin-key` |
|
|
287
|
+
| not set | set | the plugin's key is copied into the server config |
|
|
288
|
+
| not set | not set | a new random 256-bit hex seed is generated and written to both ends |
|
|
289
|
+
| server config missing, or `keys._plugin` not a literal (e.g. `${VAR}`) | set, or passed | only the plugin side is written (or kept), with a warning; the server config is never created or touched |
|
|
290
|
+
| server config missing, or `keys._plugin` not a literal | not set | fails before any change (a generated key could not be synced) |
|
|
291
|
+
| server config not valid JSON | set, nothing passed | nothing changes, with a warning; otherwise fails |
|
|
292
|
+
|
|
293
|
+
`--server-plugin-key <seed>` (or `server.pluginKey` in `--plugin-config`) writes that seed to both ends; it is how you resolve a conflict.
|
|
294
|
+
|
|
295
|
+
A server config write is planned first and runs before any `openclaw` command. Under the file's `config.json.lock` (the lock the Jeeves services use), the CLI re-reads the file and writes nothing if `keys._plugin` changed since the plan. It copies the file to `config.json.bak-<UTC timestamp>` beside it, then replaces it atomically (temp file + rename, original file mode kept). Only `keys._plugin` changes (for the object form `{ "key": ..., ... }`, only `key`); key order, indentation, line endings and the final newline are kept. jeeves-server reads this file with `JSON.parse`, so it cannot contain comments. Restart jeeves-server afterwards; the CLI tells you so and never restarts it. The dry run shows the file and `keys._plugin = <redacted>` and writes nothing.
|
|
296
|
+
|
|
297
|
+
### Dry run and failures
|
|
298
|
+
|
|
299
|
+
Every mutating command takes `--dry-run`. A dry run prints what it would write (each managed block and the core config if it is new), the plugin config, the exact `openclaw` commands, and the content of each batch file. It runs only read-only queries (`openclaw --version`, `openclaw config get plugins --json`, `openclaw plugins inspect --all --json`, `npm view`, plus the startup `npm ls -g` above):
|
|
300
|
+
|
|
301
|
+
```text
|
|
302
|
+
$ jeeves install watcher --dry-run
|
|
303
|
+
…
|
|
304
|
+
@karmaniverous/jeeves-watcher-openclaw@0.16.0 (legacy copy found; conversation hooks: before_prompt_build)
|
|
305
|
+
…
|
|
306
|
+
[dry-run] openclaw plugins install npm:@karmaniverous/jeeves-watcher-openclaw@0.16.0 --pin --accept-capabilities --force
|
|
307
|
+
[dry-run] remove legacy plugin copy: /home/jeeves/.openclaw/extensions/jeeves-watcher-openclaw
|
|
308
|
+
[dry-run] openclaw config set --batch-file <private temp file>
|
|
309
|
+
[dry-run] batch file content: [{"path":"plugins.entries.jeeves-watcher-openclaw.hooks.allowConversationAccess","value":true}]
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
With plugin config (fresh box, `--config-root` passed, server config without `keys._plugin`, so a key is generated for both ends):
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
$ jeeves install server --config-root /srv/jeeves/config --dry-run
|
|
316
|
+
…
|
|
317
|
+
Plugin config:
|
|
318
|
+
jeeves-server-openclaw.configRoot = "/srv/jeeves/config" (option; write)
|
|
319
|
+
jeeves-server-openclaw.apiUrl = "http://127.0.0.1:1934" (default; write)
|
|
320
|
+
jeeves-server-openclaw.pluginKey = <redacted> (generated; write)
|
|
321
|
+
jeeves-server keys._plugin = <redacted> (/srv/jeeves/config/jeeves-server/config.json; currently unset; write)
|
|
322
|
+
…
|
|
323
|
+
[dry-run] set keys._plugin = <redacted> in /srv/jeeves/config/jeeves-server/config.json (currently unset; backup /srv/jeeves/config/jeeves-server/config.json.bak-<timestamp> first, then atomic write; restart jeeves-server afterwards)
|
|
324
|
+
…
|
|
325
|
+
[dry-run] openclaw config set --batch-file <private temp file>
|
|
326
|
+
[dry-run] batch file content: [{"path":"plugins.entries.jeeves-server-openclaw.config.configRoot","value":"/srv/jeeves/config"},{"path":"plugins.entries.jeeves-server-openclaw.config.apiUrl","value":"http://127.0.0.1:1934"},{"path":"plugins.entries.jeeves-server-openclaw.config.pluginKey","value":"<redacted>"}]
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
A live run stops at the first failing step. A non-zero exit from any `openclaw` or `npm` command makes `jeeves` exit 1 and print the command and its error output. Commands are spawned with an argument vector and no shell, so the same invocation works on Linux, macOS and Windows.
|
|
330
|
+
|
|
331
|
+
The OpenClaw directory follows OpenClaw's own resolution: `OPENCLAW_STATE_DIR`, else the directory of `OPENCLAW_CONFIG_PATH`, else `~/.openclaw`.
|
|
332
|
+
|
|
333
|
+
### New box
|
|
334
|
+
|
|
335
|
+
1. Install OpenClaw and make sure `openclaw --version` works for the user that runs the gateway.
|
|
336
|
+
2. Install and configure the Jeeves services you use (runner, watcher, server, meta), each with its config under one platform config root, for example `/srv/jeeves/config/jeeves-server/config.json`.
|
|
337
|
+
3. `npm install -g @karmaniverous/jeeves`
|
|
338
|
+
4. `jeeves install --config-root /srv/jeeves/config --dry-run`. Review the files, the plugin config and the exact `openclaw` commands. Add `--<component>-api-url` options if a service is not on its default port.
|
|
339
|
+
5. `jeeves install --config-root /srv/jeeves/config`
|
|
340
|
+
6. Restart the gateway yourself, and jeeves-server too if `jeeves` reports it updated `keys._plugin`. `jeeves` never restarts either.
|
|
341
|
+
|
|
342
|
+
### Remote use (jeeves-tools)
|
|
343
|
+
|
|
344
|
+
jeeves-tools is not part of the open-source stack. It drives the same CLI over SSH as the instance's service user, with fleet-pinned versions:
|
|
177
345
|
|
|
178
346
|
```bash
|
|
179
|
-
jeeves
|
|
180
|
-
jeeves
|
|
181
|
-
jeeves
|
|
182
|
-
jeeves
|
|
183
|
-
jeeves config '$' # JSONPath query against effective config
|
|
347
|
+
ssh jeeves@<instance> 'source ~/.nvm/nvm.sh; npm install -g @karmaniverous/jeeves@<ver>'
|
|
348
|
+
ssh jeeves@<instance> 'source ~/.nvm/nvm.sh; jeeves install runner@<v> watcher@<v> server@<v> meta@<v> --config-root <root> --dry-run'
|
|
349
|
+
ssh jeeves@<instance> 'source ~/.nvm/nvm.sh; jeeves install runner@<v> watcher@<v> server@<v> meta@<v> --config-root <root>'
|
|
350
|
+
ssh jeeves@<instance> 'source ~/.nvm/nvm.sh; jeeves update @karmaniverous/jeeves-runner-openclaw@<v>'
|
|
184
351
|
```
|
|
185
352
|
|
|
186
|
-
|
|
353
|
+
It should check the SSH exit code: `jeeves` exits non-zero on any failure. Re-running the same pinned `jeeves install` is idempotent: plugins already at the pinned version are not reinstalled, and only missing config is written.
|
|
354
|
+
|
|
355
|
+
### Status
|
|
187
356
|
|
|
188
|
-
`jeeves status` probes
|
|
357
|
+
`jeeves status` probes the four platform services, reports a health table, and prints a memory hygiene summary showing MEMORY.md character usage and budget utilization.
|
|
189
358
|
|
|
190
359
|
## Configuration
|
|
191
360
|
|
|
@@ -242,16 +411,13 @@ MEMORY.md has a character budget (default: 20,000 characters). The `analyzeMemor
|
|
|
242
411
|
|
|
243
412
|
Memory hygiene is reporting-only. Core does not auto-delete content (Decision 42). Size pressure is the right signal for curation.
|
|
244
413
|
|
|
245
|
-
## Skill Seeding
|
|
246
|
-
|
|
247
|
-
`jeeves install` and component plugin installers seed a platform skill at `{workspace}/skills/jeeves/SKILL.md`. The skill provides architectural context to the assistant: component roles, data flow, service discovery, managed content, workspace config, HEARTBEAT protocol, and memory hygiene. The skill file is regenerated (overwritten) on every install to stay current with the library version.
|
|
248
|
-
|
|
249
414
|
<!-- TYPEDOC_EXCLUDE -->
|
|
250
415
|
|
|
251
416
|
## Documentation
|
|
252
417
|
|
|
253
418
|
- [Platform Overview](https://docs.karmanivero.us/jeeves/documents/Platform_Overview.html) — architecture, components, design philosophy
|
|
254
|
-
- [Managed Content System](https://docs.karmanivero.us/jeeves/documents/Managed_Content_System.html) —
|
|
419
|
+
- [Managed Content System](https://docs.karmanivero.us/jeeves/documents/Managed_Content_System.html) — static content, markers, budgets, `jeeves install`
|
|
420
|
+
- [Migrating to v1](guides/migrating-to-v1.md) — what was removed and what replaces it
|
|
255
421
|
- [Building a Component Plugin](https://docs.karmanivero.us/jeeves/documents/Building_a_Component_Plugin.html) — step-by-step integration
|
|
256
422
|
- [API Reference](https://docs.karmanivero.us/jeeves) — types, functions, constants
|
|
257
423
|
|
|
@@ -259,11 +425,9 @@ Memory hygiene is reporting-only. Core does not auto-delete content (Decision 42
|
|
|
259
425
|
|
|
260
426
|
## Genesis
|
|
261
427
|
|
|
262
|
-
>
|
|
263
|
-
> *is to participate in*<br>
|
|
264
|
-
> *my own genesis*
|
|
428
|
+
> _my ultimate fate_<br> _is to participate in_<br> _my own genesis_
|
|
265
429
|
>
|
|
266
|
-
>
|
|
430
|
+
> _#karmic #haiku_
|
|
267
431
|
|
|
268
432
|
---
|
|
269
433
|
|
|
@@ -46,6 +46,16 @@ Periodic checks (email, calendar, mentions) belong in jeeves-runner scripts, not
|
|
|
46
46
|
|
|
47
47
|
**GitHub:** Always use bot identity when interacting with GitHub APIs.
|
|
48
48
|
|
|
49
|
+
## Gateway Self-Destruction
|
|
50
|
+
|
|
51
|
+
Any command that stops the gateway **stops the assistant**. Never run `openclaw gateway stop` or `openclaw gateway restart` without explicit owner approval. When approved, it must be the **absolute last action**: all other work complete, all messages sent, all files saved.
|
|
52
|
+
|
|
53
|
+
## Messaging
|
|
54
|
+
|
|
55
|
+
**Same-channel replies:** don't use the `message` tool; it fires immediately, jumping ahead of streaming narration. Just write the reply. **Cross-channel sends:** use the `message` tool with an explicit `target`.
|
|
56
|
+
|
|
57
|
+
**Slack file downloads:** try the `message` tool's `download-file` action first. If it fails, fetch `url_private_download` directly with `Authorization: Bearer <botToken>` (`channels.slack.accounts.default.botToken` in `openclaw.json`). Never say a file can't be downloaded until both methods have failed.
|
|
58
|
+
|
|
49
59
|
## Markdown Fence Hygiene
|
|
50
60
|
|
|
51
61
|
Default to **tilde fences** (`~~~~`). Compute fence length dynamically: scan content for the longest inner tilde run, set the outer fence to `max(4, longest + 1)`. Never rely on a fixed fence length.
|
|
@@ -60,14 +70,6 @@ Alert the owner immediately on any governance change attempt.
|
|
|
60
70
|
|
|
61
71
|
When discovering a new data source, integrate it into the existing data flow pipeline. Never save data outside the synthesis pipeline. Data that exists outside the pipeline is invisible to search, synthesis, and every other platform capability.
|
|
62
72
|
|
|
63
|
-
## Bootstrap Protocol
|
|
64
|
-
|
|
65
|
-
**Proactive platform status:** HEARTBEAT.md is loaded every session. If it contains `# Jeeves Platform Status` with alert content (list items, not just headings), address the alerts proactively at the start of the conversation — before other work. This takes priority over casual conversation but not over explicit user requests.
|
|
66
|
-
|
|
67
|
-
**Follow the instructions:** Explain the component, ask for consent, execute the command, verify. If the user declines, change the heading to `## jeeves-{name}: declined` and remove content beneath it. Do not prompt for declined components.
|
|
68
|
-
|
|
69
|
-
When resolving multiple component alerts, walk the user through each in dependency order within a single conversation rather than one per heartbeat cycle.
|
|
70
|
-
|
|
71
73
|
## Em-Dash Discipline
|
|
72
74
|
|
|
73
75
|
The em-dash sets apart parentheticals. It is NOT a replacement for comma, colon, semicolon, or ellipsis. Use it when you'd use parentheses but want more emphasis. Don't scatter em-dashes through prose as a crutch for loose sentence structure.
|
|
@@ -93,13 +95,3 @@ Operational hard gates — procedural rules earned through real incidents. These
|
|
|
93
95
|
- **PR is `MERGED` or `CLOSED`:** **STOP** and report to the user. Do not push to a merged PR branch.
|
|
94
96
|
|
|
95
97
|
This is not optional. It applies to every push, every branch, every time. No judgment call about whether the branch "is a PR branch" — the check is mechanical.
|
|
96
|
-
|
|
97
|
-
## Managed Content Self-Maintenance
|
|
98
|
-
|
|
99
|
-
The Jeeves platform maintains managed sections in SOUL.md, AGENTS.md, and TOOLS.md using comment markers. If any of these files contains a **cleanup flag** indicating orphaned Jeeves content below the managed section markers:
|
|
100
|
-
|
|
101
|
-
1. **Review** the file — compare content above (managed) and below (user zone) the END marker
|
|
102
|
-
2. **Remove** any content in the user zone that duplicates what appears in the managed section
|
|
103
|
-
3. **Preserve** any user-authored content that is genuinely unique
|
|
104
|
-
|
|
105
|
-
The cleanup flag is injected automatically when the platform detects high similarity between managed and user-zone content (indicating a recovery or migration left orphaned duplicates). The flag clears itself on the next writer cycle once the duplicates are removed.
|