Skip to content

[recipes] Clean up Life Engine: add state table, harden permissions, fix skill divergence#135

Merged
justfinethanku merged 8 commits into
NateBJones-Projects:mainfrom
air-captain:claude/affectionate-haslett
Apr 13, 2026
Merged

[recipes] Clean up Life Engine: add state table, harden permissions, fix skill divergence#135
justfinethanku merged 8 commits into
NateBJones-Projects:mainfrom
air-captain:claude/affectionate-haslett

Conversation

@air-captain
Copy link
Copy Markdown
Contributor

Summary

  • Add life_engine_state key-value table for runtime state (cron job ID, sleep schedule) — replaces the cron_state briefing type workaround with a proper system state table
  • Simplify Dynamic Loop Timing from 6 tiers to 4 (15m / 30m / 60m / one-shot) for cleaner reschedule logic
  • Remove duplicate embedded skill from README — Step 5 now points to life-engine-skill.md as the single source of truth, eliminating a 130-line divergent copy
  • Harden permissions approach — restructure Step 6 to lead with settings.json allowlist (scoped, persistent) as the recommended default; demote --dangerously-skip-permissions to testing-only; replace broad mcp__supabase__* wildcards with specific tool names
  • Fix skill-to-schema consistency — add user_responded update logic, timezone note, remove phantom suggestion_type and cron_state references
  • Fix platform references — consistently say "Telegram or Discord" where both apply

Test plan

  • Cross-reference all table/column/type references in life-engine-skill.md against schema.sql — all 9 QA checks pass
  • Verify schema.sql creates 6 tables with no destructive SQL
  • Verify README contains no embedded skill code (only pointer to life-engine-skill.md)
  • Verify settings.json allowlist includes all tools Life Engine needs (reply, react, edit_message, gcal_list_events, gcal_get_event, search_thoughts, list_thoughts, thought_stats, execute_sql, CronCreate, CronDelete)
  • Run /life-engine skill to confirm it executes a full cycle with the updated instructions

🤖 Generated with Claude Code

air-captain and others added 4 commits March 22, 2026 11:02
…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>
…, 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>
…owlist, 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>
…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>
@matthallett1
Copy link
Copy Markdown
Collaborator

@claude

@matthallett1
Copy link
Copy Markdown
Collaborator

@claude summarize this PR

@matthallett1
Copy link
Copy Markdown
Collaborator

@claude review this PR

1 similar comment
@matthallett1
Copy link
Copy Markdown
Collaborator

@claude review this PR

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 30, 2026

Claude finished @matthallett1's task in 2m 12s —— View job


PR Review

  • Gather context (CLAUDE.md, CONTRIBUTING.md)
  • Read changed files
  • Review for alignment, clarity, completeness, safety, value, and design patterns
  • Post final review

Overall: ✅ Approve with minor notes

This is a solid cleanup PR that makes the recipe significantly more maintainable. The single biggest win is removing the 130-line duplicate embedded skill — that alone justifies the PR. The permissions restructure and life_engine_state table are both genuine improvements. A few things worth noting:


What Works Well

Removing the embedded skill duplicate is the right call. A divergent copy is a maintenance liability, and pointing Step 5 at life-engine-skill.md as the single source of truth is clean and clear.

Permissions restructure directly addresses the #1 failure mode ("Life Engine stopped responding"). Leading with the settings.json allowlist and demoting --dangerously-skip-permissions to testing-only is exactly the right hierarchy. The risk table is a nice addition.

life_engine_state table is a proper fix for the cron_state briefing type workaround. Key-value for runtime state is the right pattern here — simple, flexible, and doesn't pollute the user-facing briefing log.

Schema hygiene is good: RLS enabled, GRANTs present, indexes added, auto-update trigger for life_engine_state, verification query updated to expect 6 tables.

user_responded update logic in Rule 7 of the skill closes a gap — the self-improvement protocol was querying this field without anything writing it.


Issues to Address

1. life_engine_state has no user_id column — all other Life Engine tables have user_id TEXT NOT NULL, but life_engine_state is keyed only on key. This works fine for a single-user setup, but silently assumes one Life Engine instance per Supabase project. A brief comment in the schema explaining this single-user assumption (and the implication: if you want multi-user, prefix keys with your user ID) would prevent confusion. schema.sql:115

2. Skill shows Telegram-specific channel event format onlylife-engine-skill.md:17 shows <channel source="telegram" chat_id="..." ...>. The PR description says "Fix platform references — consistently say 'Telegram or Discord' where both apply," but the skill still only documents the Telegram channel event format. Discord events presumably use a different source attribute. A user running Discord would be confused. life-engine-skill.md:17

Fix this →

3. delivered_via column has no CHECK constraintlife_engine_briefings.delivered_via TEXT DEFAULT 'telegram' accepts any string. With Discord now supported as a first-class option, a CHECK (delivered_via IN ('telegram', 'discord')) would prevent typos and make the column self-documenting. Minor, but easy to add. schema.sql:82

Fix this →


Nitpicks (no action required)

  • The hardcoded coordinates in the weather curl example (latitude=45.52&longitude=-122.68) look like they need to be manually changed, but the skill correctly says to read from life_engine_state first. A comment like # replace with your actual lat/lon, or store in life_engine_state would clarify this is illustrative. life-engine-skill.md:159

  • The one-shot cron behavior (recurring: false in the sleep window) is load-bearing but unexplained. A brief inline comment in the reschedule logic block would help future readers understand why the sleep window creates a one-shot vs. a recurring job.

  • metadata.json version is still 1.0.0 despite this being at least the 3rd round of changes to the recipe. Consider bumping to 1.1.0 per semver.


Issues 1 and 2 are worth fixing before merge. Issue 3 is a nice-to-have. The rest are optional polish.
|

Copy link
Copy Markdown
Collaborator

@matthallett1 matthallett1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good cleanup overall — the duplicate skill removal and permissions restructure are solid wins. However, Codex review (gpt-5.4) caught three issues, two of which are functional regressions:

P1: Bash missing from the unattended allowlist. The skill now uses curl for weather fetches, but the recommended settings.json allowlist doesn't include Bash. The first morning weather check will block on a permission prompt, breaking the unattended loop for users who follow the docs. Fix: add Bash(curl:*) to the allowlist example.

P1: Discord reply events ignored. The skill rule at line ~240 only fires for <channel source="telegram">. On a Discord setup, check-in replies and YES/NO approvals never match, so user_responded stays false and the self-improvement logic breaks. The README advertises Discord as first-class, but the skill doesn't support it.

P2: No upgrade migration. Changing user_id from UUID to TEXT inside CREATE TABLE IF NOT EXISTS doesn't update existing installs. Users who already have the tables need explicit ALTER TABLE ... TYPE text migration steps, or they'll get runtime errors when storing Telegram/Discord identifiers.

Happy to re-review once these are addressed!

… 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>
@github-actions github-actions Bot added the recipe Contribution: step-by-step recipe label Apr 1, 2026
air-captain and others added 3 commits March 31, 2026 19:43
…' 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>
…sion docs

Fixes all issues from PR NateBJones-Projects#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>
…agile

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>
@alanshurafa
Copy link
Copy Markdown
Collaborator

Review feedback from @matthallett1 has been addressed across commits 6edb477 and 26910eb:

  1. P1 — Bash permissions: Broadened to Bash(*) since scoped patterns were fragile. Documented in settings.json allowlist example.
  2. P1 — Discord support: Added Discord reply event matching alongside Telegram.
  3. P2 — Migration: Added upgrade migration steps for existing installs (UUID → TEXT column change).

Ready for re-review.

@justfinethanku
Copy link
Copy Markdown
Collaborator

Thanks for the outstanding contribution. We took a final pass on the packaging, README clarity, and overall fit with OB1, and this is in good shape to land.

I’m merging this now so people can start using it. Really appreciate the work you put into this.

@justfinethanku justfinethanku merged commit 0ed8a64 into NateBJones-Projects:main Apr 13, 2026
1 check passed
corruptmemory pushed a commit to corruptmemory/OB1 that referenced this pull request Apr 15, 2026
…fix skill divergence (NateBJones-Projects#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 NateBJones-Projects#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>
gleesonb pushed a commit to gleesonb/OB1 that referenced this pull request May 12, 2026
…fix skill divergence (NateBJones-Projects#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 NateBJones-Projects#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

recipe Contribution: step-by-step recipe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants