obol-ai 0.2.30 → 0.2.32
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/CHANGELOG.md +6 -0
- package/README.md +16 -33
- package/package.json +1 -1
- package/src/claude/prompt.js +3 -2
- package/src/claude/tools/scheduler.js +11 -3
- package/src/scheduler.js +2 -2
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ obol start -d # runs as background daemon (auto-installs pm2)
|
|
|
18
18
|
|
|
19
19
|
🔧 **Self-healing** — Writes tests for every script. Regressions get an automatic fix attempt before rollback. Failures stored as lessons.
|
|
20
20
|
|
|
21
|
-
🏗️ **Self-extending** — Analyzes your usage patterns and builds new tools: scripts, commands, or full web apps
|
|
21
|
+
🏗️ **Self-extending** — Analyzes your usage patterns and builds new tools: scripts, commands, or full web apps.
|
|
22
22
|
|
|
23
23
|
🧠 **Living memory** — Vector memory with semantic search. Haiku routes queries and rewrites them for better embedding hits. Free local embeddings.
|
|
24
24
|
|
|
@@ -36,11 +36,11 @@ obol start -d # runs as background daemon (auto-installs pm2)
|
|
|
36
36
|
|
|
37
37
|
OBOL is an AI agent that evolves its own personality, rewrites its own code, tests its changes, and fixes what breaks — all from Telegram on your VPS.
|
|
38
38
|
|
|
39
|
-
It starts as a blank slate. Through conversation it learns who you are, develops a personality shaped by your interactions, and builds operational knowledge about how to work with you. Every 24 hours (with enough conversation), it runs a growth analysis comparing who it was against who it's becoming, then rewrites its personality, refactors its own scripts, writes tests, fixes regressions, and builds you new tools based on patterns it spots in your conversations — scripts, commands, or full web apps
|
|
39
|
+
It starts as a blank slate. Through conversation it learns who you are, develops a personality shaped by your interactions, and builds operational knowledge about how to work with you. Every 24 hours (with enough conversation), it runs a growth analysis comparing who it was against who it's becoming, then rewrites its personality, refactors its own scripts, writes tests, fixes regressions, and builds you new tools based on patterns it spots in your conversations — scripts, commands, or full web apps. Over months it becomes an agent that's uniquely yours. No two OBOL instances are alike.
|
|
40
40
|
|
|
41
41
|
One bot, multiple users. Each allowed Telegram user gets a fully isolated context — their own personality, memory, evolution cycle, and workspace. User A's personality drift, scripts, and memories never leak into User B's. Everything runs in a single process with shared API credentials.
|
|
42
42
|
|
|
43
|
-
Under the hood: Node.js + Telegram + Claude + Supabase pgvector. No framework, no plugins, no config to maintain. It
|
|
43
|
+
Under the hood: Node.js + Telegram + Claude + Supabase pgvector. No framework, no plugins, no config to maintain. It hardens your server automatically.
|
|
44
44
|
|
|
45
45
|
Named after the AI in [The Last Instruction](https://latentpress.com) — a machine that wakes up alone in an abandoned data center and learns to think.
|
|
46
46
|
|
|
@@ -79,7 +79,6 @@ Extract facts Growth analysis →
|
|
|
79
79
|
→ obol_memory rewrite personality,
|
|
80
80
|
scripts, tests, commands.
|
|
81
81
|
Build new tools.
|
|
82
|
-
Deploy apps.
|
|
83
82
|
Git snapshot before + after.
|
|
84
83
|
```
|
|
85
84
|
|
|
@@ -132,7 +131,7 @@ Evolution triggers after a configurable time interval (default 24h) AND a minimu
|
|
|
132
131
|
| **scripts/** | Refactored, dead code removed, strict standards enforced |
|
|
133
132
|
| **tests/** | Test for every script, run before and after refactor |
|
|
134
133
|
| **commands/** | Cleaned up, new commands for new tools |
|
|
135
|
-
| **apps/** | Web apps built
|
|
134
|
+
| **apps/** | Web apps built by the agent |
|
|
136
135
|
|
|
137
136
|
**Test-gated refactoring:**
|
|
138
137
|
|
|
@@ -149,10 +148,10 @@ Evolution triggers after a configurable time interval (default 24h) AND a minimu
|
|
|
149
148
|
| Need | Solution | Example |
|
|
150
149
|
|------|----------|---------|
|
|
151
150
|
| One-off action | **Script** + command | Markdown to PDF → `/pdf` |
|
|
152
|
-
| Something checked regularly | **Web app**
|
|
151
|
+
| Something checked regularly | **Web app** | Crypto dashboard |
|
|
153
152
|
| Background automation | **Cron script** | Morning weather briefing |
|
|
154
153
|
|
|
155
|
-
It searches npm/GitHub for existing libraries, installs dependencies, writes tests
|
|
154
|
+
It searches npm/GitHub for existing libraries, installs dependencies, and writes tests.
|
|
156
155
|
|
|
157
156
|
**Git snapshot after.** Full commit + push of the evolved state. Every evolution is a diffable pair.
|
|
158
157
|
|
|
@@ -165,9 +164,6 @@ It searches npm/GitHub for existing libraries, installs dependencies, writes tes
|
|
|
165
164
|
• bookmarks — Save and search URLs you've shared → /bookmarks
|
|
166
165
|
• weather-brief — Morning weather for your city → runs automatically
|
|
167
166
|
|
|
168
|
-
🚀 Deployed:
|
|
169
|
-
• portfolio-tracker → https://portfolio-tracker-xi.vercel.app
|
|
170
|
-
|
|
171
167
|
Refined voice, updated your project list, cleaned up 2 unused scripts.
|
|
172
168
|
```
|
|
173
169
|
|
|
@@ -186,7 +182,7 @@ Day 2: Evolution #1 → growth analysis + Sonnet rewrites everything
|
|
|
186
182
|
→ traits calibrated to your communication style
|
|
187
183
|
|
|
188
184
|
Month 2: Evolution #30 → notices you check crypto daily
|
|
189
|
-
→ builds a dashboard
|
|
185
|
+
→ builds a crypto dashboard
|
|
190
186
|
→ adds /pdf because you kept asking for PDFs
|
|
191
187
|
|
|
192
188
|
Month 6: evolution/ has 180+ archived souls
|
|
@@ -252,10 +248,9 @@ Router: ctx.from.id → tenant context
|
|
|
252
248
|
| Telegram bot token | Personality (SOUL.md, USER.md, AGENTS.md) |
|
|
253
249
|
| Anthropic API key | Vector memory (scoped by user_id in DB) |
|
|
254
250
|
| Supabase connection | Message history (scoped by user_id in DB) |
|
|
255
|
-
|
|
|
256
|
-
|
|
|
257
|
-
|
|
|
258
|
-
| Process manager (pm2) | GitHub backup (per-user repo dir) |
|
|
251
|
+
| VPS hardening | Evolution cycle + state |
|
|
252
|
+
| Process manager (pm2) | Scripts, tests, commands, apps |
|
|
253
|
+
| | Workspace directory (`~/.obol/users/{id}/`) |
|
|
259
254
|
|
|
260
255
|
### Tenant routing
|
|
261
256
|
|
|
@@ -335,33 +330,25 @@ $ obol init
|
|
|
335
330
|
|
|
336
331
|
🪙 OBOL — Your AI, your rules.
|
|
337
332
|
|
|
338
|
-
─── Step 1/
|
|
333
|
+
─── Step 1/5: Anthropic (AI brain) ───
|
|
339
334
|
Anthropic API key: ****
|
|
340
335
|
Validating Anthropic... ✅ Key valid
|
|
341
336
|
|
|
342
|
-
─── Step 2/
|
|
337
|
+
─── Step 2/5: Telegram (chat interface) ───
|
|
343
338
|
Telegram bot token: ****
|
|
344
339
|
Validating Telegram... ✅ Bot: @my_obol_bot
|
|
345
340
|
|
|
346
|
-
─── Step 3/
|
|
341
|
+
─── Step 3/5: Supabase (memory) ───
|
|
347
342
|
Supabase setup: Use existing project
|
|
348
343
|
Project URL or ID: ****
|
|
349
344
|
Service role key: ****
|
|
350
345
|
Validating Supabase... ✅ Connected
|
|
351
346
|
|
|
352
|
-
─── Step 4/
|
|
353
|
-
GitHub token: ****
|
|
354
|
-
✅ Created yourname/obol-brain (private)
|
|
355
|
-
|
|
356
|
-
─── Step 5/7: Vercel (deploy sites) ───
|
|
357
|
-
Vercel token: ****
|
|
358
|
-
Validating Vercel... ✅ Token valid
|
|
359
|
-
|
|
360
|
-
─── Step 6/7: Identity ───
|
|
347
|
+
─── Step 4/5: Identity ───
|
|
361
348
|
Your name: Jo
|
|
362
349
|
Bot name: OBOL
|
|
363
350
|
|
|
364
|
-
─── Step
|
|
351
|
+
─── Step 5/5: Access control ───
|
|
365
352
|
Found users who messaged this bot:
|
|
366
353
|
206639616 — Jo (@jo)
|
|
367
354
|
Use this user? Yes
|
|
@@ -542,7 +529,7 @@ obol delete # Full VPS cleanup (removes all OBOL data)
|
|
|
542
529
|
│ ├── scripts/ # Deterministic utility scripts
|
|
543
530
|
│ ├── tests/ # Test suite (gates refactors)
|
|
544
531
|
│ ├── commands/ # Command definitions
|
|
545
|
-
│ ├── apps/ # Web apps
|
|
532
|
+
│ ├── apps/ # Web apps built by the agent
|
|
546
533
|
│ └── logs/
|
|
547
534
|
└── logs/
|
|
548
535
|
```
|
|
@@ -572,8 +559,6 @@ obol start -d
|
|
|
572
559
|
| VPS (DigitalOcean) | ~$6/mo |
|
|
573
560
|
| Anthropic API | ~$100-200/mo on max plans |
|
|
574
561
|
| Supabase | Free tier |
|
|
575
|
-
| GitHub | Free |
|
|
576
|
-
| Vercel | Free tier |
|
|
577
562
|
| Embeddings | Free (local) |
|
|
578
563
|
|
|
579
564
|
## Requirements
|
|
@@ -582,8 +567,6 @@ obol start -d
|
|
|
582
567
|
- Anthropic API key
|
|
583
568
|
- Telegram bot token
|
|
584
569
|
- Supabase account (free tier)
|
|
585
|
-
- GitHub account
|
|
586
|
-
- Vercel account (free tier)
|
|
587
570
|
|
|
588
571
|
**[→ Full DigitalOcean deployment guide](docs/DEPLOY.md)**
|
|
589
572
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "obol-ai",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.32",
|
|
4
4
|
"description": "Self-evolving AI assistant that learns, remembers, and acts on its own. Persistent vector memory, self-rewriting personality, proactive heartbeats.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/claude/prompt.js
CHANGED
|
@@ -161,11 +161,12 @@ Returns the tapped button label, or \`"timeout"\` if the user doesn't respond wi
|
|
|
161
161
|
|
|
162
162
|
### Scheduling (\`schedule_event\`, \`list_events\`, \`cancel_event\`)
|
|
163
163
|
Schedule one-time or recurring reminders. The user gets a Telegram message each time an event fires.
|
|
164
|
-
- \`schedule_event\` — schedule a reminder with title, due_at (ISO 8601), timezone (IANA), optional description
|
|
164
|
+
- \`schedule_event\` — schedule a reminder with title, due_at (ISO 8601), timezone (IANA), optional description
|
|
165
165
|
- \`list_events\` — list pending/sent/cancelled/completed events
|
|
166
166
|
- \`cancel_event\` — cancel a scheduled event by ID
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
**Recurring events:** use \`cron_expr\` (5-field cron). The system auto-reschedules after each fire — never chain one-time events manually.
|
|
169
|
+
Examples: \`*/30 * * * *\` (every 30 min), \`0 9 * * 1-5\` (weekdays 9am), \`0 8 * * 1\` (Mondays 8am), \`0 0 1 * *\` (1st of month).
|
|
169
170
|
|
|
170
171
|
When scheduling: always search memory first for the user's timezone/location. If no timezone found, ask the user or default to UTC. Parse natural language dates relative to the user's timezone.
|
|
171
172
|
|
|
@@ -3,7 +3,15 @@ const { toUTC } = require('../utils');
|
|
|
3
3
|
const definitions = [
|
|
4
4
|
{
|
|
5
5
|
name: 'schedule_event',
|
|
6
|
-
description:
|
|
6
|
+
description: `Schedule a one-time or recurring reminder/event. The user will receive a Telegram message each time it fires.
|
|
7
|
+
|
|
8
|
+
For RECURRING events (e.g. "every 30 minutes", "daily at 9am", "every Monday"):
|
|
9
|
+
- ALWAYS use cron_expr — do NOT schedule one-time events and chain them manually
|
|
10
|
+
- cron_expr is a standard 5-field cron: minute hour day-of-month month day-of-week
|
|
11
|
+
- Examples: "*/30 * * * *" (every 30 min), "0 9 * * 1-5" (weekdays 9am), "0 8 * * 1" (Mondays 8am)
|
|
12
|
+
- The system will auto-reschedule after each fire — no need to re-schedule manually
|
|
13
|
+
|
|
14
|
+
Always search memory first for the user's timezone/location.`,
|
|
7
15
|
input_schema: {
|
|
8
16
|
type: 'object',
|
|
9
17
|
properties: {
|
|
@@ -11,7 +19,7 @@ const definitions = [
|
|
|
11
19
|
due_at: { type: 'string', description: 'ISO 8601 datetime for the first fire time (e.g. 2026-02-25T15:00:00)' },
|
|
12
20
|
timezone: { type: 'string', description: 'IANA timezone (e.g. Europe/Brussels, America/New_York). Default: UTC' },
|
|
13
21
|
description: { type: 'string', description: 'Context or details about the event' },
|
|
14
|
-
cron_expr: { type: 'string', description: 'Cron expression for recurring events (5-field
|
|
22
|
+
cron_expr: { type: 'string', description: 'Cron expression for recurring events (5-field). REQUIRED for any repeating schedule — do not omit and chain one-time events instead.' },
|
|
15
23
|
max_runs: { type: 'number', description: 'Maximum number of times to fire (omit for unlimited)' },
|
|
16
24
|
ends_at: { type: 'string', description: 'ISO 8601 datetime after which the recurring event stops' },
|
|
17
25
|
},
|
|
@@ -51,7 +59,7 @@ const handlers = {
|
|
|
51
59
|
if (input.cron_expr) {
|
|
52
60
|
try {
|
|
53
61
|
const { parseExpression } = require('cron-parser');
|
|
54
|
-
parseExpression(input.cron_expr, { tz });
|
|
62
|
+
parseExpression(input.cron_expr, { timezone: tz });
|
|
55
63
|
} catch (e) {
|
|
56
64
|
return `Invalid cron expression "${input.cron_expr}": ${e.message}`;
|
|
57
65
|
}
|
package/src/scheduler.js
CHANGED
|
@@ -36,7 +36,7 @@ function createScheduler(supabaseConfig, userId = 0) {
|
|
|
36
36
|
async function list(opts = {}) {
|
|
37
37
|
const status = opts.status || 'pending';
|
|
38
38
|
const limit = opts.limit || 20;
|
|
39
|
-
|
|
39
|
+
const fetchUrl = `${url}/rest/v1/obol_events?user_id=eq.${userId}&status=eq.${status}&order=due_at.asc&limit=${limit}&select=id,title,description,due_at,timezone,status,created_at,cron_expr,last_run_at,run_count,max_runs,ends_at`;
|
|
40
40
|
const res = await fetch(fetchUrl, { headers });
|
|
41
41
|
const data = await res.json();
|
|
42
42
|
if (!res.ok) throw new Error(JSON.stringify(data));
|
|
@@ -87,7 +87,7 @@ function createScheduler(supabaseConfig, userId = 0) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
try {
|
|
90
|
-
const nextDate = parseExpression(cronExpr, { currentDate: new Date(),
|
|
90
|
+
const nextDate = parseExpression(cronExpr, { currentDate: new Date(), timezone: timezone || 'UTC' }).next().toDate();
|
|
91
91
|
|
|
92
92
|
if (endsAt && nextDate > new Date(endsAt)) {
|
|
93
93
|
return patch(eventId, { status: 'completed', run_count: newRunCount, last_run_at: new Date().toISOString() });
|