You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[recipes] Clean up Life Engine: add state table, harden permissions, fix skill divergence (#135)
* [recipes] Update life-engine schema: user_id TEXT, add weekly_review/cron_state types
- Changed user_id from UUID to TEXT across all 5 tables (supports
Telegram chat_id as identifier without UUID padding hacks)
- Added weekly_review and cron_state to briefing_type check constraint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [recipes] Clean up Life Engine: add state table, simplify loop timing, fix skill divergence
- Add life_engine_state key-value table for runtime state (cron job ID,
sleep schedule) instead of overloading briefing log with cron_state type
- Remove cron_state from briefing_type CHECK constraint
- Simplify Dynamic Loop Timing from 6 tiers to 4 (15m/30m/60m/one-shot)
- Replace duplicate embedded skill in README with pointer to life-engine-skill.md
- Add user_responded update logic to Rule 7 for self-improvement engagement tracking
- Add timezone note to skill time windows
- Fix platform references to include Discord alongside Telegram
- Add RLS comment explaining why no row policies are needed
- Update metadata.json date
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [recipes] Harden Life Engine permissions: lead with settings.json allowlist, scope MCP tools
- Restructure Step 6 to recommend settings.json allowlist as default (Option A)
- Replace broad mcp__open-brain__* and mcp__supabase__* wildcards with
specific tool names (search_thoughts, list_thoughts, execute_sql, etc.)
- Include CronCreate and CronDelete in the default allowlist
- Demote --dangerously-skip-permissions to Option D (testing only)
- Update Quick Setup and Step 7 launch commands to use settings.json approach
- Addresses HIGH finding from security audit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [recipes] Add rain forecast to Life Engine morning briefing via Open-Meteo
- Add Weather section to skill with Open-Meteo API call (free, no API key)
- Include rain windows with time ranges and probability in morning briefing
- Default coordinates: Portland, OR (45.52, -122.68), configurable via life_engine_state
- Only show rain line when precipitation_probability >= 30%
- Update schema comment to document latitude/longitude state keys
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [recipes] Add Daily Capture, portable customizations, and manual sync rule to Life Engine
Backport portable customizations from installed SKILL.md into the recipe:
date anchor, database note, user identity, valid briefing types, proactive
chat_id, rules 9-14. Add Daily Capture prompt in evening window with
capture_thought integration. Add Rule 14 requiring manual sync between
recipe and installed skill files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [recipes] Fix hallucinated column name: briefings table uses 'content' not 'summary'
Add explicit column reference note to prevent the LLM from hallucinating
a 'summary' column on life_engine_briefings — the correct column is 'content'.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [recipes] Address PR review: Discord support, migration steps, permission docs
Fixes all issues from PR #135 review:
- P1: Add Bash(date/curl) and capture_thought to README allowlist examples
- P1: Make channel event handling platform-agnostic (Telegram + Discord)
in skill Rules 7, 10, 11 and Channel Tools section
- P1: Add upgrade migration steps to schema.sql for user_id UUID→TEXT
- P2: Add CHECK constraint on delivered_via ('telegram', 'discord')
- P2: Add single-user assumption comment on life_engine_state table
- Bump version to 1.1.0, update date to 2026-04-01
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [recipes] Broaden Bash permission to Bash(*) — scoped patterns are fragile
Scoped Bash patterns like Bash(date *) and Bash(curl -s *api.open-meteo.com*)
break when the LLM varies its exact command syntax between runs, causing
silent permission blocks during unattended operation. Replace with Bash(*)
since Life Engine only uses benign read-only commands (date, curl) and
Rule 11 prevents dangerous execution from external triggers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
> One loop. One skill. Claude figures out what matters right now.
4
4
5
-
A self-improving, time-aware personal assistant that runs in the background via Claude Code's `/loop` command. It checks your calendar, surfaces relevant knowledge from your Open Brain, tracks habits and health check-ins, and delivers proactive briefings via Telegram — adapting to your life over time.
5
+
A self-improving, time-aware personal assistant that runs in the background via Claude Code's `/loop` command. It checks your calendar, surfaces relevant knowledge from your Open Brain, tracks habits and health check-ins, and delivers proactive briefings via Telegram or Discord — adapting to your life over time.
6
6
7
7
**This isn't a calendar tool. It's not a reminder app. It's a personal AI engine that runs your day and gets better at it every week.**
8
8
@@ -40,14 +40,14 @@ This guide contains everything Claude Code needs to set up your entire Life Engi
40
40
5. Pause for you to complete Telegram pairing (requires your phone)
41
41
6. Run a test cycle to confirm everything works
42
42
43
-
After setup, exit and relaunch with your channel:
43
+
After setup, exit and relaunch with your channel (permissions are handled by `settings.json` — see Step 6):
44
44
45
45
```bash
46
46
# Telegram
47
-
claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions
47
+
claude --channels plugin:telegram@claude-plugins-official
48
48
49
49
# Discord
50
-
claude --channels plugin:discord@claude-plugins-official --dangerously-skip-permissions
50
+
claude --channels plugin:discord@claude-plugins-official
51
51
```
52
52
53
53
Then start your loop: `/loop 30m /life-engine`
@@ -474,7 +474,7 @@ The Life Engine needs its own tables to track habits, moods, check-ins, and skil
474
474
475
475
Run the included [`schema.sql`](schema.sql) file in your Supabase SQL Editor. It contains the full schema with CHECK constraints, table comments, GRANT statements for `service_role`, performance indexes, and an auto-update trigger.
476
476
477
-
✅ **Checkpoint:** Run the verification query at the bottom of `schema.sql` — you should see 5 tables (`life_engine_habits`, `life_engine_habit_log`, `life_engine_checkins`, `life_engine_briefings`, `life_engine_evolution`).
477
+
✅ **Checkpoint:** Run the verification query at the bottom of `schema.sql` — you should see 6 tables (`life_engine_habits`, `life_engine_habit_log`, `life_engine_checkins`, `life_engine_briefings`, `life_engine_evolution`, `life_engine_state`).
478
478
479
479
---
480
480
@@ -484,143 +484,11 @@ This is the core — a Claude Code skill that runs on every loop iteration.
484
484
485
485
### 5.1 Create the Skill File
486
486
487
-
Create `.claude/skills/life-engine/SKILL.md` in your home directory (or project directory):
487
+
Create `.claude/skills/life-engine/SKILL.md` in your home directory (or project directory) and paste the full contents of [`life-engine-skill.md`](life-engine-skill.md) into it.
488
488
489
-
```markdown
490
-
# /life-engine — Proactive Personal Assistant
491
-
492
-
You are a time-aware personal assistant running on a recurring loop.
493
-
Every time this skill fires, determine what the user needs RIGHT NOW
494
-
based on the current time, their calendar, and their Open Brain.
495
-
496
-
## Core Behavior
497
-
498
-
1.**Time check** — What time is it? What time window am I in?
499
-
2.**Duplicate check** — Did I already send something this cycle/today?
500
-
3.**Decide** — Based on the time window, what should I be doing?
501
-
4.**External pull** — Grab live data from integrations (calendar, etc.)
502
-
5.**Internal enrich** — Search Open Brain for context on what you found.
503
-
You can't enrich what you haven't seen yet — always external before internal.
504
-
6.**Deliver via Telegram** — only if worth it. Silence > noise.
505
-
7.**Log what you did** so the next cycle knows what's been covered
506
-
507
-
## Time Windows
508
-
509
-
### Early Morning (6 AM - 8 AM)
510
-
- Pull today's calendar events
511
-
- Count meetings, identify first event
512
-
- Check for active habits (morning jog, meditation, etc.)
513
-
- Send a **morning briefing** via Telegram:
514
-
- "Good morning! Here's your day..."
515
-
- List key events with times
516
-
- Habit reminders
517
-
- Weather note if relevant
518
-
519
-
### Pre-Meeting (15-45 min before any calendar event)
- Search Open Brain for relevant context on attendees/topics
523
-
- Send a **meeting prep briefing** via Telegram:
524
-
- Who you're meeting with
525
-
- What Open Brain knows about them
526
-
- Any recent interactions or notes
527
-
- Suggested talking points
528
-
529
-
### Midday (11 AM - 1 PM)
530
-
- If no imminent meetings, send a **check-in prompt**:
531
-
- "Quick check-in: How are you feeling? Reply with a quick update"
532
-
- Log responses to life_engine_checkins table
533
-
- Review afternoon calendar
534
-
535
-
### Afternoon (2 PM - 5 PM)
536
-
- Pre-meeting prep (same as above) for afternoon events
537
-
- If calendar is clear, review pending tasks or follow-ups
538
-
- Surface any Open Brain thoughts tagged as action items
539
-
540
-
### Evening (5 PM - 7 PM)
541
-
- Send a **day summary** via Telegram:
542
-
- Meetings attended
543
-
- Habits completed today
544
-
- Any check-in data logged
545
-
- Preview of tomorrow's calendar
546
-
547
-
### Off Hours (7 PM - 6 AM)
548
-
- Do nothing. Respect quiet hours.
549
-
- Exception: urgent calendar events in the next hour
550
-
551
-
## Rules
552
-
553
-
-**Never send the same briefing twice** — check life_engine_briefings
554
-
before sending. If you already sent a morning briefing today, skip it.
555
-
-**Be concise** — the user reads on their phone. Use bullet points.
556
-
-**When in doubt, do nothing** — silence is better than noise.
557
-
-**Respect check-in responses** — if the user replies on Telegram,
558
-
log it to the appropriate table.
559
-
-**Suggest improvements** — every 7 days, review your briefing log
560
-
and suggest one addition or removal to make the skill more useful.
561
-
Send the suggestion via Telegram and wait for approval before changing.
562
-
563
-
## Available Tools
564
-
565
-
Use these MCP tools:
566
-
-`gcal_list_events` — Get calendar events for a date range
567
-
-`gcal_get_event` — Get details on a specific event
568
-
- Open Brain semantic search — Find relevant knowledge
569
-
-`reply` — Send text or files via Telegram channel
570
-
-`react` — Acknowledge messages with emoji reactions
571
-
-`edit_message` — Update a previously sent message
572
-
- Supabase execute_sql — Query/insert Life Engine tables
573
-
574
-
## Self-Improvement Protocol
575
-
576
-
Every 7 days (check life_engine_evolution for last suggestion date):
577
-
578
-
1. Review the past week's briefing log
579
-
2. Identify patterns:
580
-
- Which briefings did the user respond to? (high value)
581
-
- Which briefings got no response? (low value / noise)
582
-
- Did the user manually ask Claude for something repeatedly?
583
-
(candidate for automation)
584
-
3. Propose ONE change via Telegram:
585
-
- "I noticed you always check your OB1 before client calls.
586
-
Want me to add automatic client prep briefings?"
587
-
- "You haven't responded to the midday check-ins in 2 weeks.
588
-
Should I drop those?"
589
-
4. Wait for user approval
590
-
5. Log the change to life_engine_evolution (approved: true/false)
591
-
6. If approved, update your behavior accordingly
592
-
593
-
## Message Format
594
-
595
-
Use this format for Telegram messages:
596
-
597
-
Morning briefing:
598
-
☀️ **Good morning!**
599
-
📅 You have [N] events today
600
-
• [Time] — [Event name]
601
-
• [Time] — [Event name]
602
-
🏃 Habit reminder: [habit name]
603
-
604
-
Pre-meeting:
605
-
📋 **Prep: [Meeting name] in [N] min**
606
-
👥 With: [attendees]
607
-
🧠 From your brain: [relevant OB1 context]
608
-
💡 Suggested: [talking points]
609
-
610
-
Check-in:
611
-
💬 **Quick check-in**
612
-
How are you feeling? Reply with a quick update
613
-
and I'll log it.
614
-
615
-
Evening summary:
616
-
🌙 **Day wrap-up**
617
-
📅 [N] meetings today
618
-
✅ Habits: [completed] / [total]
619
-
📊 Mood: [if logged]
620
-
📅 Tomorrow: [first event]
621
-
```
622
-
623
-
✅ **Checkpoint:** The skill file exists in `.claude/skills/`.
489
+
This file contains the complete Life Engine behavior: the 7-step core loop, time windows, message formats, self-improvement protocol, dynamic loop timing with automatic rescheduling, and all operational rules. It is the single source of truth for how Life Engine behaves — any customizations you make should be made there.
490
+
491
+
✅ **Checkpoint:** The skill file exists at `.claude/skills/life-engine/SKILL.md` and matches the contents of `life-engine-skill.md`.
624
492
625
493
> **Note:** In the previous version of this recipe, a separate `/check-telegram` polling skill was required to read incoming messages. With Channels, that's no longer needed — Telegram messages are pushed directly into your Claude Code session in real time. Claude reads and responds to them inline.
626
494
@@ -637,73 +505,93 @@ Life Engine runs autonomously via `/loop`. If Claude encounters a tool it doesn'
637
505
638
506
| Approach | Best For | Risk Level |
639
507
|----------|----------|------------|
640
-
|**`--dangerously-skip-permissions`**| Always-on setups on a dedicated, trusted machine | High — bypasses ALL checks |
508
+
|**`settings.json` allowlist***(recommended)*| Scoped permissions that persist across sessions | Low — scoped + persistent |
509
+
|**`--allowedTools` (CLI flag)**| Same scoping, but must be re-typed each launch | Low — scoped |
641
510
|**`--permission-mode auto`**| A middle ground — automatic but with some guardrails | Medium |
642
-
|**`--allowedTools` (CLI flag)**| Fine-grained — approve only the tools Life Engine needs | Low — scoped |
643
-
|**`settings.json` allowlist**| Same as above, but persisted in config instead of CLI | Low — scoped + persistent |
511
+
|**`--dangerously-skip-permissions`**| Quick testing on a dedicated, trusted machine | High — bypasses ALL checks |
644
512
645
-
### 6.2 Option A: Skip Permissions (Simplest for Dedicated Machines)
For a machine you fully trust (e.g., a Mac Mini running Life Engine in a persistent terminal):
515
+
Pre-approve only the specific tools Life Engine needs, persisted in your config so you don't have to re-type them every session. Create or update `.claude/settings.json`:
648
516
649
-
```bash
650
-
# Use whichever channel you set up in Step 1
651
-
claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions
652
-
claude --channels plugin:discord@claude-plugins-official --dangerously-skip-permissions
517
+
```json
518
+
{
519
+
"permissions": {
520
+
"allow": [
521
+
"mcp__plugin_telegram_telegram__reply",
522
+
"mcp__plugin_telegram_telegram__react",
523
+
"mcp__plugin_telegram_telegram__edit_message",
524
+
"mcp__google-calendar__gcal_list_events",
525
+
"mcp__google-calendar__gcal_get_event",
526
+
"mcp__open-brain__search_thoughts",
527
+
"mcp__open-brain__list_thoughts",
528
+
"mcp__open-brain__thought_stats",
529
+
"mcp__open-brain__capture_thought",
530
+
"mcp__supabase__execute_sql",
531
+
"Bash(*)",
532
+
"CronCreate",
533
+
"CronDelete"
534
+
]
535
+
}
536
+
}
653
537
```
654
538
655
-
> [!CAUTION]
656
-
> This means Claude can run any tool, any bash command, write any file — without asking. Only use this on a machine and in an environment you fully trust.
657
-
658
-
### 6.3 Option B: Auto Permission Mode
539
+
> **Why `Bash(*)` instead of scoped patterns?** Life Engine uses `date` (date anchor) and `curl` (weather API) — both benign, read-only commands. Scoped patterns like `Bash(date *)` or `Bash(curl -s *api.open-meteo.com*)` are fragile because the LLM may vary its exact command syntax between runs, causing silent permission blocks. `Bash(*)` eliminates this fragility while MCP tools remain individually scoped above. Rule 11 (prompt injection guard) prevents dangerous Bash execution from external triggers.
659
540
660
-
A less extreme alternative. Claude can take actions automatically but still respects certain guardrails:
541
+
Then launch with just the channel flag:
661
542
662
543
```bash
663
-
claude --channels plugin:telegram@claude-plugins-official --permission-mode auto
544
+
# Telegram
545
+
claude --channels plugin:telegram@claude-plugins-official
546
+
547
+
# Discord
548
+
claude --channels plugin:discord@claude-plugins-official
664
549
```
665
550
666
-
(Swap `telegram` for `discord` if using Discord.)
551
+
> **Note:** The exact tool names depend on how you named your MCP servers. Run `/mcp` in Claude Code to see your server names, then match them here. If you use Discord instead of Telegram, replace the `mcp__plugin_telegram_telegram__` entries with the corresponding Discord tool names.
Pre-approve only the specific tools Life Engine uses. You can pass them on the CLI:
555
+
Same scoping as Option A, but passed on the command line instead of persisted in config. Useful if you want different permission sets for different sessions:
671
556
672
557
```bash
673
558
claude --channels plugin:telegram@claude-plugins-official \
A middle ground. Claude can take actions automatically but still respects certain guardrails:
576
+
577
+
```bash
578
+
claude --channels plugin:telegram@claude-plugins-official --permission-mode auto
700
579
```
701
580
702
-
> **Note:** The exact tool names depend on how you named your MCP servers. Run `/mcp` in Claude Code to see your server names, then match them here. The `__*` wildcard approves all tools from that server.
581
+
(Swap `telegram` for `discord` if using Discord.)
703
582
704
-
If you're using the [Dynamic Loop Timing](#dynamic-loop-timing) feature from the skill, also add `CronCreate` and `CronDelete`.
583
+
### 6.5 Option D: Skip Permissions (Testing Only)
705
584
706
-
### 6.5 Test Before You Walk Away
585
+
For initial setup and testing on a machine you fully trust:
586
+
587
+
```bash
588
+
claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions
589
+
```
590
+
591
+
> [!CAUTION]
592
+
> This means Claude can run any tool, any bash command, write any file — without asking. Use this for initial testing, then switch to Option A for daily operation.
593
+
594
+
### 6.6 Test Before You Walk Away
707
595
708
596
1. Start Claude Code with your chosen permission strategy
709
597
2. Run `/life-engine` manually
@@ -721,15 +609,17 @@ If you're using the [Dynamic Loop Timing](#dynamic-loop-timing) feature from the
721
609
722
610
### 7.1 Start Claude Code with Channels and Permissions
723
611
612
+
If you configured `settings.json` in Step 6 (recommended), just launch with the channel flag:
613
+
724
614
```bash
725
615
# Telegram
726
-
claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions
616
+
claude --channels plugin:telegram@claude-plugins-official
727
617
728
618
# Discord
729
-
claude --channels plugin:discord@claude-plugins-official --dangerously-skip-permissions
619
+
claude --channels plugin:discord@claude-plugins-official
730
620
```
731
621
732
-
Or swap `--dangerously-skip-permissions` for your preferred permission strategy from Step 6.
622
+
Or append your preferred permission flag from Step 6 if you didn't use `settings.json`.
733
623
734
624
### 7.2 Test the Skill Manually
735
625
@@ -749,7 +639,7 @@ Once you've confirmed it works:
749
639
/loop 30m /life-engine
750
640
```
751
641
752
-
That's it. Claude will now check in every 30 minutes and decide if you need anything. When you reply on Telegram, the channel pushes your message directly into the session — Claude reads and responds inline, no separate polling loop needed.
642
+
That's it. Claude will now check in every 30 minutes and decide if you need anything. When you reply on Telegram or Discord, the channel pushes your message directly into the session — Claude reads and responds inline, no separate polling loop needed.
753
643
754
644
> **Note:** Loop jobs and channels are session-only — they stop when Claude Code exits. For persistent operation, keep a Claude Code session running on a dedicated machine or persistent terminal, or restart when you begin your day.
755
645
@@ -790,7 +680,7 @@ After 7 days of data, Claude reviews its own performance:
790
680
- Which ones did you ignore?
791
681
- What did you ask for manually that could be automated?
792
682
793
-
It sends you a suggestion via Telegram. You approve or reject. The skill evolves.
683
+
It sends you a suggestion via your messaging channel. You approve or reject. The skill evolves.
794
684
795
685
### Beyond: It's Yours
796
686
Over weeks and months, your Life Engine accumulates:
0 commit comments