Skip to content

th pearls: schedulable pearls that speak up in the prime hook when due#176

Merged
brentrager merged 2 commits into
mainfrom
th-01aa6a-pearl-schedule
Jul 6, 2026
Merged

th pearls: schedulable pearls that speak up in the prime hook when due#176
brentrager merged 2 commits into
mainfrom
th-01aa6a-pearl-schedule

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

A pearl you want to revisit later (after a deploy, next week, in 2h) has no way to resurface on its own — it just sits in the backlog until someone re-reads the whole list. Brent asked for pearls to "start speaking up in hooks when a scheduled pearl is up."

Solution

Add an optional scheduled_at to pearls and surface due ones through the existing session-priming hook.

  • th pearls schedule <id> <when> — set it; omit <when> to clear. <when> is relative (+2h, 30m, 2d, 1w, tomorrow, now; leading - = past) or absolute (2026-07-10, 2026-07-10 09:00, RFC3339), parsed as UTC.
  • th pearls due — pearls whose time has arrived (scheduled_at <= now, not closed, soonest-first).
  • Prime hookth prime now prints a ⏰ Scheduled & due section above Ready to work, so a scheduled pearl automatically speaks up at the next session start / compaction once it comes due. show/ready/list render a marker.

Storage mirrors closed_at exactly (nullable DATETIME, idempotent ADD COLUMN IF NOT EXISTS migration for existing Dolt stores).

The one non-obvious bit

Due comparison uses a Rust Utc::now() literal, not Dolt NOW(). Dolt's NOW() returns the server's local time while scheduled_at is stored as UTC, so scheduled_at <= NOW() was off by the local UTC offset (a pearl 1h in the past read as not-yet-due on an EDT box). Caught in end-to-end smoke; a store-level regression test (test_due_scheduled_uses_utc_not_dolt_local_now) guards it with a ±1h window that would flip under the bug.

Verification

  • cargo test -p smooai-smooth-cli -p smooai-smooth-pearls -p smooai-smooth-diver → 469 passed. New tests: schedule_tests::{relative_offsets,keywords,absolute_forms,garbage_is_rejected} (parser) + test_due_scheduled_uses_utc_not_dolt_local_now (TZ-correct query).
  • cargo fmt --check clean, cargo clippy clean on touched crates.
  • End-to-end smoke against a throwaway repo: -1h past → due + surfaced in prime; +90m future → not due; clear → gone; absolute past date → due.
  • Docs updated in the same PR (docs/Engineering/Using-th-CLI.md).

🤖 Generated with Claude Code

Pearls gain an optional scheduled_at so a work item can be set aside now and
resurface itself later, instead of being lost in the backlog until someone
re-reads it.

- `th pearls schedule <id> <when>` sets it; omit <when> to clear. <when> is
  relative (+2h / 30m / 2d / 1w / tomorrow / now, leading `-` allowed for past)
  or absolute (2026-07-10, 2026-07-10 09:00, RFC3339), parsed as UTC.
- `th pearls due` lists pearls whose time has arrived (scheduled_at <= now,
  not closed, soonest-first).
- The prime hook (SessionStart/PreCompact) now prints a "⏰ Scheduled & due"
  section above "Ready to work" — a scheduled pearl automatically speaks up at
  the next session start once it comes due. `show`/`ready`/`list` render a ⏰
  marker.

Storage mirrors closed_at (nullable DATETIME, idempotent ADD COLUMN IF NOT
EXISTS migration). Due comparison uses a Rust Utc::now() literal, NOT Dolt
NOW() — Dolt NOW() returns server-local time while scheduled_at is stored UTC,
so `<= NOW()` would be off by the local offset. Regression test guards it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ff431e8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/smooth Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager brentrager enabled auto-merge (squash) July 6, 2026 03:11
@brentrager brentrager merged commit 792f479 into main Jul 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant