openvole 0.2.0 → 0.3.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 +98 -21
- package/dist/cli.js +41 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +31 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/openvole/openvole/main/assets/vole.png" alt="OpenVole" width="200">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">OpenVole</h1>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Micro-agent core. The smallest possible thing that other useful things can be built on top of.</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/openvole"><img src="https://img.shields.io/npm/v/openvole" alt="npm"></a>
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
14
|
+
</p>
|
|
7
15
|
|
|
8
16
|
---
|
|
9
17
|
|
|
@@ -45,7 +53,7 @@ Edit `vole.config.json`:
|
|
|
45
53
|
}
|
|
46
54
|
],
|
|
47
55
|
"skills": [],
|
|
48
|
-
"loop": { "maxIterations":
|
|
56
|
+
"loop": { "maxIterations": 25, "compactThreshold": 50 }
|
|
49
57
|
}
|
|
50
58
|
```
|
|
51
59
|
|
|
@@ -104,11 +112,12 @@ curl -fsSL https://raw.githubusercontent.com/openvole/openvole/main/presets/full
|
|
|
104
112
|
[Brain Paw] [Channel] [Tools] [In-Process]
|
|
105
113
|
Ollama Telegram Browser Compact
|
|
106
114
|
Claude Slack Shell Memory
|
|
107
|
-
OpenAI Discord MCP
|
|
108
|
-
Gemini WhatsApp Email/GitHub/Calendar
|
|
115
|
+
OpenAI Discord MCP Session
|
|
116
|
+
Gemini WhatsApp Email/Resend/GitHub/Calendar
|
|
117
|
+
xAI
|
|
109
118
|
```
|
|
110
119
|
|
|
111
|
-
|
|
120
|
+
22 official Paws: 5 Brain, 4 Channel, 8 Tool, 4 Infrastructure.
|
|
112
121
|
|
|
113
122
|
## Core Concepts
|
|
114
123
|
|
|
@@ -162,6 +171,7 @@ The Brain is a Paw — the core is LLM-ignorant. Swap models by swapping Brain P
|
|
|
162
171
|
- `@openvole/paw-claude` — Anthropic Claude models
|
|
163
172
|
- `@openvole/paw-openai` — OpenAI models
|
|
164
173
|
- `@openvole/paw-gemini` — Google Gemini models
|
|
174
|
+
- `@openvole/paw-xai` — xAI Grok models
|
|
165
175
|
|
|
166
176
|
## Features
|
|
167
177
|
|
|
@@ -182,22 +192,28 @@ The Brain is a Paw — the core is LLM-ignorant. Swap models by swapping Brain P
|
|
|
182
192
|
|
|
183
193
|
### Heartbeat
|
|
184
194
|
|
|
185
|
-
Periodic wake-up — the Brain checks `HEARTBEAT.md` and decides what to do. No user input needed.
|
|
195
|
+
Periodic wake-up — the Brain checks `HEARTBEAT.md` and decides what to do. No user input needed. Uses cron expressions:
|
|
186
196
|
|
|
187
197
|
```json
|
|
188
|
-
{ "heartbeat": { "enabled": true, "
|
|
198
|
+
{ "heartbeat": { "enabled": true, "cron": "*/30 * * * *" } }
|
|
189
199
|
```
|
|
190
200
|
|
|
191
201
|
### Persistent Scheduling
|
|
192
202
|
|
|
193
|
-
Brain-created schedules are stored in `.openvole/schedules.json
|
|
203
|
+
Brain-created schedules use cron expressions and are stored in `.openvole/schedules.json`, surviving restarts. The heartbeat is recreated from config on each startup (intervalMinutes is auto-converted to cron).
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
"0 13 * * *" — daily at 1 PM UTC
|
|
207
|
+
"*/30 * * * *" — every 30 minutes
|
|
208
|
+
"0 9 * * 1" — every Monday at 9 AM
|
|
209
|
+
```
|
|
194
210
|
|
|
195
211
|
### Memory (Source-Isolated)
|
|
196
212
|
|
|
197
213
|
Persistent memory with daily logs scoped by task source:
|
|
198
214
|
|
|
199
215
|
```
|
|
200
|
-
.openvole/memory/
|
|
216
|
+
.openvole/paws/paw-memory/
|
|
201
217
|
├── MEMORY.md # Shared long-term facts
|
|
202
218
|
├── user/ # CLI session logs
|
|
203
219
|
├── paw/ # Telegram/Slack logs
|
|
@@ -206,11 +222,47 @@ Persistent memory with daily logs scoped by task source:
|
|
|
206
222
|
|
|
207
223
|
### Sessions
|
|
208
224
|
|
|
209
|
-
Conversation continuity across messages. Auto-expiring transcripts per session ID.
|
|
225
|
+
Conversation continuity across messages. Auto-expiring transcripts per session ID. Session data lives in `.openvole/paws/paw-session/`, organized by session ID (e.g., `cli:default/`, `telegram:123/`).
|
|
210
226
|
|
|
211
227
|
### MCP Support
|
|
212
228
|
|
|
213
|
-
Bridge 1000+ MCP servers into the tool registry via `paw-mcp`. MCP tools appear alongside Paw tools — the Brain doesn't know the difference.
|
|
229
|
+
Bridge 1000+ community MCP servers into the tool registry via `paw-mcp`. MCP tools appear alongside Paw tools — the Brain doesn't know the difference.
|
|
230
|
+
|
|
231
|
+
- MCP tools are **auto-discovered at runtime** as MCP servers connect
|
|
232
|
+
- **Late tool registration** — tools appear after the engine starts, not at boot
|
|
233
|
+
- MCP config lives in `.openvole/paws/paw-mcp/servers.json` (not in the installed package)
|
|
234
|
+
|
|
235
|
+
Example `.openvole/paws/paw-mcp/servers.json`:
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"servers": [
|
|
240
|
+
{
|
|
241
|
+
"name": "resend",
|
|
242
|
+
"command": "npx",
|
|
243
|
+
"args": ["-y", "resend-mcp"],
|
|
244
|
+
"env": { "RESEND_API_KEY": "$RESEND_API_KEY" }
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Late Tool Registration
|
|
251
|
+
|
|
252
|
+
Any Paw can discover and register tools at runtime using the `register_tools` mechanism — not just MCP. Tools registered this way appear in the tool registry like any other tool. This is a generic capability of the engine, not an MCP-specific feature.
|
|
253
|
+
|
|
254
|
+
### Local Paw Config
|
|
255
|
+
|
|
256
|
+
Each Paw has its own local config directory at `.openvole/paws/<name>/`. The installed npm package stays immutable — all user configuration lives in the local paw directory.
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
.openvole/paws/
|
|
260
|
+
├── paw-memory/ ← memory data (MEMORY.md, daily logs)
|
|
261
|
+
├── paw-session/ ← session transcripts
|
|
262
|
+
└── paw-mcp/ ← MCP config (servers.json)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Example: `paw-mcp` reads its `servers.json` from `.openvole/paws/paw-mcp/`, not from `node_modules/`.
|
|
214
266
|
|
|
215
267
|
### Rate Limiting
|
|
216
268
|
|
|
@@ -230,12 +282,12 @@ Customize agent behavior with optional markdown files in `.openvole/`:
|
|
|
230
282
|
|
|
231
283
|
| File | Purpose |
|
|
232
284
|
|------|---------|
|
|
233
|
-
| `BRAIN.md` | Custom system prompt
|
|
285
|
+
| `BRAIN.md` | Custom system prompt — **overrides the default system prompt entirely** |
|
|
234
286
|
| `SOUL.md` | Agent personality and tone |
|
|
235
287
|
| `USER.md` | User profile and preferences |
|
|
236
288
|
| `AGENT.md` | Operating rules and constraints |
|
|
237
289
|
|
|
238
|
-
All Brain Paws (Ollama, Claude, OpenAI, Gemini) load these on startup.
|
|
290
|
+
All Brain Paws (Ollama, Claude, OpenAI, Gemini, xAI) load these on startup.
|
|
239
291
|
|
|
240
292
|
### Workspace
|
|
241
293
|
|
|
@@ -262,11 +314,11 @@ When context grows too large, `paw-compact` summarizes old messages while preser
|
|
|
262
314
|
|
|
263
315
|
Real-time web UI at `localhost:3001` — paws, tools, skills, tasks, schedules, live events.
|
|
264
316
|
|
|
265
|
-
## Official Paws (
|
|
317
|
+
## Official Paws (22)
|
|
266
318
|
|
|
267
319
|
All paws live in [PawHub](https://github.com/openvole/pawhub) and are installed via npm.
|
|
268
320
|
|
|
269
|
-
### Brain (
|
|
321
|
+
### Brain (5)
|
|
270
322
|
|
|
271
323
|
| Paw | Purpose |
|
|
272
324
|
|-----|---------|
|
|
@@ -274,6 +326,7 @@ All paws live in [PawHub](https://github.com/openvole/pawhub) and are installed
|
|
|
274
326
|
| `paw-claude` | Anthropic Claude models |
|
|
275
327
|
| `paw-openai` | OpenAI models |
|
|
276
328
|
| `paw-gemini` | Google Gemini models |
|
|
329
|
+
| `paw-xai` | xAI Grok models |
|
|
277
330
|
|
|
278
331
|
### Channel (4)
|
|
279
332
|
|
|
@@ -284,7 +337,7 @@ All paws live in [PawHub](https://github.com/openvole/pawhub) and are installed
|
|
|
284
337
|
| `paw-discord` | Discord bot channel |
|
|
285
338
|
| `paw-whatsapp` | WhatsApp bot channel |
|
|
286
339
|
|
|
287
|
-
### Tool (
|
|
340
|
+
### Tool (8)
|
|
288
341
|
|
|
289
342
|
| Paw | Purpose |
|
|
290
343
|
|-----|---------|
|
|
@@ -293,6 +346,7 @@ All paws live in [PawHub](https://github.com/openvole/pawhub) and are installed
|
|
|
293
346
|
| `paw-filesystem` | File system operations |
|
|
294
347
|
| `paw-mcp` | MCP server bridge |
|
|
295
348
|
| `paw-email` | Email sending |
|
|
349
|
+
| `paw-resend` | Email via Resend API |
|
|
296
350
|
| `paw-github` | GitHub integration |
|
|
297
351
|
| `paw-calendar` | Calendar integration |
|
|
298
352
|
|
|
@@ -353,8 +407,8 @@ Single `vole.config.json` — plain JSON, no imports:
|
|
|
353
407
|
"brain": "@openvole/paw-ollama",
|
|
354
408
|
"paws": ["@openvole/paw-ollama", "@openvole/paw-memory"],
|
|
355
409
|
"skills": ["clawhub/summarize"],
|
|
356
|
-
"loop": { "maxIterations":
|
|
357
|
-
"heartbeat": { "enabled": false, "
|
|
410
|
+
"loop": { "maxIterations": 25, "compactThreshold": 50 },
|
|
411
|
+
"heartbeat": { "enabled": false, "cron": "*/30 * * * *" },
|
|
358
412
|
"toolProfiles": { "paw": { "deny": ["shell_exec"] } }
|
|
359
413
|
}
|
|
360
414
|
```
|
|
@@ -367,6 +421,29 @@ OpenVole loads [OpenClaw](https://openclaw.ai) skills natively — same `SKILL.m
|
|
|
367
421
|
npx vole clawhub install summarize
|
|
368
422
|
```
|
|
369
423
|
|
|
424
|
+
## .openvole Directory Structure
|
|
425
|
+
|
|
426
|
+
```
|
|
427
|
+
.openvole/
|
|
428
|
+
├── paws/
|
|
429
|
+
│ ├── paw-memory/ ← memory data
|
|
430
|
+
│ │ ├── MEMORY.md
|
|
431
|
+
│ │ └── user/, paw/, heartbeat/
|
|
432
|
+
│ ├── paw-session/ ← session transcripts
|
|
433
|
+
│ │ └── cli:default/, telegram:123/
|
|
434
|
+
│ └── paw-mcp/ ← MCP config
|
|
435
|
+
│ └── servers.json
|
|
436
|
+
├── workspace/ ← agent scratch space
|
|
437
|
+
├── skills/ ← local and clawhub skills
|
|
438
|
+
├── vault.json ← encrypted key-value store
|
|
439
|
+
├── schedules.json ← persistent cron schedules
|
|
440
|
+
├── BRAIN.md ← custom system prompt
|
|
441
|
+
├── SOUL.md ← agent personality
|
|
442
|
+
├── USER.md ← user profile
|
|
443
|
+
├── AGENT.md ← operating rules
|
|
444
|
+
└── HEARTBEAT.md ← recurring job definitions
|
|
445
|
+
```
|
|
446
|
+
|
|
370
447
|
## Philosophy
|
|
371
448
|
|
|
372
449
|
> **If it connects to something, it's a Paw.**
|
package/dist/cli.js
CHANGED
|
@@ -575,11 +575,13 @@ var init_scheduler = __esm({
|
|
|
575
575
|
setTickHandler(handler) {
|
|
576
576
|
this.tickHandler = handler;
|
|
577
577
|
}
|
|
578
|
-
/** Load schedule data from disk without starting cron jobs (for read-only access) */
|
|
578
|
+
/** Load schedule data from disk without starting cron jobs (for read-only access). Never persists. */
|
|
579
579
|
async loadFromDisk() {
|
|
580
580
|
if (!this.savePath) return;
|
|
581
|
+
const savedPath = this.savePath;
|
|
582
|
+
this.savePath = void 0;
|
|
581
583
|
try {
|
|
582
|
-
const raw = await fs3.readFile(
|
|
584
|
+
const raw = await fs3.readFile(savedPath, "utf-8");
|
|
583
585
|
const persisted = JSON.parse(raw);
|
|
584
586
|
for (const s of persisted) {
|
|
585
587
|
const job = new Cron(s.cron, { timezone: "UTC", paused: true }, () => {
|
|
@@ -594,6 +596,7 @@ var init_scheduler = __esm({
|
|
|
594
596
|
}
|
|
595
597
|
} catch {
|
|
596
598
|
}
|
|
599
|
+
this.savePath = savedPath;
|
|
597
600
|
}
|
|
598
601
|
/** Load persisted schedules from disk and restart their jobs */
|
|
599
602
|
async restore() {
|
|
@@ -2654,6 +2657,20 @@ var PawRegistry = class {
|
|
|
2654
2657
|
const { type } = params;
|
|
2655
2658
|
return this.handleQuery(type);
|
|
2656
2659
|
});
|
|
2660
|
+
transport.onRequest("register_tools", async (params) => {
|
|
2661
|
+
const { tools } = params;
|
|
2662
|
+
if (tools && tools.length > 0) {
|
|
2663
|
+
const toolDefs = tools.map((t) => ({
|
|
2664
|
+
name: t.name,
|
|
2665
|
+
description: t.description,
|
|
2666
|
+
parameters: {},
|
|
2667
|
+
execute: async (toolParams) => this.executeRemoteTool(pawName, t.name, toolParams)
|
|
2668
|
+
}));
|
|
2669
|
+
this.toolRegistry.register(pawName, toolDefs, false);
|
|
2670
|
+
logger12.info(`Paw "${pawName}" late-registered ${tools.length} tool(s)`);
|
|
2671
|
+
}
|
|
2672
|
+
return { ok: true };
|
|
2673
|
+
});
|
|
2657
2674
|
transport.onRequest("create_task", async (params) => {
|
|
2658
2675
|
const { input, source, sessionId, metadata } = params;
|
|
2659
2676
|
if (!this.taskQueue) {
|
|
@@ -2736,6 +2753,18 @@ var PawRegistry = class {
|
|
|
2736
2753
|
if (registration.hooks?.bootstrap) {
|
|
2737
2754
|
this.bootstrapPaws.push(pawName);
|
|
2738
2755
|
}
|
|
2756
|
+
if (registration.hooks?.perceive) {
|
|
2757
|
+
const config = this.paws.get(pawName)?.config;
|
|
2758
|
+
const hookConfig = config?.hooks?.perceive;
|
|
2759
|
+
const hasTools = (registration.tools?.length ?? 0) > 0;
|
|
2760
|
+
this.perceiveHooks.push({
|
|
2761
|
+
pawName,
|
|
2762
|
+
order: hookConfig?.order ?? 100,
|
|
2763
|
+
pipeline: hookConfig?.pipeline ?? true,
|
|
2764
|
+
hasTools
|
|
2765
|
+
});
|
|
2766
|
+
this.perceiveHooks.sort((a, b) => a.order - b.order);
|
|
2767
|
+
}
|
|
2739
2768
|
if (registration.hooks?.observe) {
|
|
2740
2769
|
this.observeHookPaws.push(pawName);
|
|
2741
2770
|
}
|
|
@@ -3107,11 +3136,12 @@ async function initProject(projectRoot) {
|
|
|
3107
3136
|
await fs10.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3108
3137
|
await fs10.mkdir(path11.join(projectRoot, ".openvole", "skills"), { recursive: true });
|
|
3109
3138
|
await fs10.mkdir(path11.join(projectRoot, ".openvole", "skills", "clawhub"), { recursive: true });
|
|
3110
|
-
await fs10.mkdir(path11.join(projectRoot, ".openvole", "memory"), { recursive: true });
|
|
3111
|
-
await fs10.mkdir(path11.join(projectRoot, ".openvole", "sessions"), { recursive: true });
|
|
3112
3139
|
await fs10.mkdir(path11.join(projectRoot, ".openvole", "workspace"), { recursive: true });
|
|
3140
|
+
await fs10.mkdir(path11.join(projectRoot, ".openvole", "paws", "paw-memory"), { recursive: true });
|
|
3141
|
+
await fs10.mkdir(path11.join(projectRoot, ".openvole", "paws", "paw-session"), { recursive: true });
|
|
3142
|
+
await fs10.mkdir(path11.join(projectRoot, ".openvole", "paws", "paw-mcp"), { recursive: true });
|
|
3113
3143
|
await fs10.writeFile(
|
|
3114
|
-
path11.join(projectRoot, ".openvole", "memory", "MEMORY.md"),
|
|
3144
|
+
path11.join(projectRoot, ".openvole", "paws", "paw-memory", "MEMORY.md"),
|
|
3115
3145
|
"# Memory\n\nLong-term memory for the agent. Store important facts, user preferences, and decisions here.\n",
|
|
3116
3146
|
"utf-8"
|
|
3117
3147
|
);
|
|
@@ -3156,10 +3186,12 @@ async function initProject(projectRoot) {
|
|
|
3156
3186
|
}
|
|
3157
3187
|
logger15.info("Created vole.config.json");
|
|
3158
3188
|
logger15.info("Created .openvole/");
|
|
3159
|
-
logger15.info(" skills/
|
|
3160
|
-
logger15.info("
|
|
3161
|
-
logger15.info("
|
|
3162
|
-
logger15.info("
|
|
3189
|
+
logger15.info(" skills/ \u2014 local and ClawHub skills");
|
|
3190
|
+
logger15.info(" workspace/ \u2014 agent scratch space");
|
|
3191
|
+
logger15.info(" paws/paw-memory/ \u2014 agent memory (MEMORY.md + daily logs)");
|
|
3192
|
+
logger15.info(" paws/paw-session/ \u2014 session transcripts");
|
|
3193
|
+
logger15.info(" paws/paw-mcp/ \u2014 MCP server config");
|
|
3194
|
+
logger15.info("Created identity files (BRAIN.md, SOUL.md, USER.md, AGENT.md, HEARTBEAT.md)");
|
|
3163
3195
|
logger15.info("Created .env");
|
|
3164
3196
|
logger15.info("");
|
|
3165
3197
|
logger15.info("Next: install paws and start");
|