โ† Back to Coding Agents & IDEs

hour-meter

Track elapsed time from a set epoch with tamper-evident locking

0
Source Code

Hour Meter

Life event tracker with three modes, milestone notifications, and tamper-evident verification.

Three Modes

COUNT UP โ€” Time since an event

# Quit smoking tracker
meter.py create smoke-free --start "2025-06-15T08:00:00Z" -d "Last cigarette"
meter.py milestone smoke-free -t hours -v 720 -m "๐ŸŽ‰ 30 days smoke-free!"
meter.py lock smoke-free  # โ†’ Gives you paper code to save

COUNT DOWN โ€” Time until an event

# Baby due date
meter.py create baby --start "2026-01-15" --end "2026-10-15" --mode down -d "Baby arriving!"
meter.py milestone baby -t percent -v 33 -m "๐Ÿ‘ถ First trimester complete!"

COUNT BETWEEN โ€” Journey from start to end

# Career span
meter.py create career --start "1998-05-15" --end "2038-05-15" -d "40-year career"
meter.py milestone career -t percent -v 50 -m "๐Ÿ“Š Halfway through career!"
meter.py career --meter career --rate 85 --raise-pct 2.5

Tamper-Evident Persistence

When you lock a meter, you get a paper code โ€” a short, checksummed code you can write on paper:

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘  PAPER CODE (write this down):                               โ•‘
โ•‘     318B-3229-C523-2F9C-V                                    โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Four Ways to Save (Non-Technical)

1๏ธโƒฃ PAPER โ€” Write the code on paper/sticky note

  • 20 characters with dashes, easy to copy
  • Built-in checksum catches typos when verifying
  • Keep in wallet, safe, or taped to equipment

2๏ธโƒฃ PHOTO โ€” Screenshot or photograph the lock screen

  • Store in camera roll, cloud photos
  • Visual backup, no typing required

3๏ธโƒฃ WITNESS FILE โ€” Auto-saved to ~/.openclaw/meter-witness.txt

  • Append-only log of all locked meters
  • Sync folder to Dropbox/iCloud/Google Drive for cloud backup
  • Contains paper code + full hash + timestamp

4๏ธโƒฃ EMAIL TO SELF โ€” Click the mailto: link or copy the one-liner

  • Opens your email client with pre-filled subject and body
  • Or copy the compact message: ๐Ÿ”’ my-meter | Code: XXXX-XXXX-XXXX-XXXX-C | Locked: 2026-02-02
  • Send to yourself, search inbox later to verify

5๏ธโƒฃ SENDGRID EMAIL โ€” Auto-send verification email on lock

# Set your SendGrid API key
export SENDGRID_API_KEY=SG.xxxxx
export SENDGRID_FROM_EMAIL=verified@yourdomain.com

# Lock and email in one command
meter.py lock my-meter --email you@example.com
  • Sends a beautifully formatted HTML email with paper code
  • Requires a verified sender in SendGrid (see SendGrid docs)
  • Great for automated workflows

Verifying Later

# With paper code (catches typos!)
meter.py verify my-meter "318B-3229-C523-2F9C-V"

# โ†’ โœ… VERIFIED! Paper code matches.
# โ†’ โš ๏ธ CHECKSUM ERROR! (if you have a typo)
# โ†’ โŒ MISMATCH! (if tampered)

Milestones

meter.py milestone <name> --type hours --value 1000 --message "1000 hours!"
meter.py milestone <name> --type percent --value 50 --message "Halfway!"
meter.py check-milestones  # JSON output for automation

Email Milestone Notifications (v1.3.0)

Get milestone notifications sent directly to your email:

# Create meter with email notifications
meter.py create my-meter \
  --notify-email you@example.com \
  --from-email verified@yourdomain.com \
  -d "My tracked event"

# Add milestones as usual
meter.py milestone my-meter -t hours -v 24 -m "๐ŸŽ‰ 24 hours complete!"

# When check-milestones runs and a milestone fires, email is sent automatically
meter.py check-milestones
# โ†’ Triggers milestone AND sends email notification

Email includes:

  • ๐ŸŽฏ Milestone message
  • โฑ๏ธ Current elapsed time
  • ๐Ÿ“ Meter description

Requires SENDGRID_API_KEY environment variable.

Milestone Notifications: Heartbeat vs Cron

Recommended: HEARTBEAT (~30 min resolution)

  • Add to HEARTBEAT.md: Run meter.py check-milestones and notify triggered
  • Batches with other periodic checks
  • Cost-efficient: shares token usage with other heartbeat tasks
  • Good for most use cases (quit tracking, career milestones, etc.)

ACTION: Triggers (Agent Automation)

Prefix milestone messages with ACTION: to trigger agent execution instead of just posting:

# Just posts the message
meter.py milestone my-meter -t hours -v 24 -m "๐ŸŽ‰ 24 hours complete!"

# Triggers agent to EXECUTE the instruction
meter.py milestone my-meter -t hours -v 24 -m "ACTION: Check the weather and post a summary"

Configure in HEARTBEAT.md:

- If message starts with "ACTION:", execute it as an instruction
- Otherwise, post the message to the configured channel

Alternative: CRON (precise timing)

  • Use when exact timing matters (e.g., countdown to event)
  • โš ๏ธ Cost warning: Cron at 1-minute intervals = 1,440 API calls/day = expensive!
  • If using cron, keep intervals โ‰ฅ15 minutes to manage costs
  • Best for one-shot reminders, not continuous monitoring

Rule of thumb: If 30-minute resolution is acceptable, use heartbeat. Save cron for precision timing.

Quick Reference

meter.py create <name> [--start T] [--end T] [--mode up|down|between] [-d DESC]
meter.py lock <name>                # Seal + get paper code
meter.py verify <name> <code>       # Verify paper code
meter.py check <name>               # Status + progress
meter.py milestone <name> -t hours|percent -v N -m "..."
meter.py check-milestones           # All milestones (JSON)
meter.py witness [--show] [--path]  # Witness file
meter.py list                       # All meters
meter.py career [--meter M] [--rate R] [--raise-pct P]
meter.py export [name]              # JSON export

SendGrid Email Webhook Server

Receive real-time notifications when recipients open, click, bounce, or unsubscribe from your meter verification emails.

Setup

# Start webhook server with Discord webhook (recommended)
python sendgrid_webhook.py --port 8089 --discord-webhook https://discord.com/api/webhooks/xxx/yyy

# Or process events manually (for agent to post)
python sendgrid_webhook.py --process-events
python sendgrid_webhook.py --process-events --json

Discord Webhook Setup (Recommended)

  1. In your Discord channel, go to Settings > Integrations > Webhooks
  2. Click New Webhook, copy the URL
  3. Pass to --discord-webhook or set DISCORD_WEBHOOK_URL env var

SendGrid Setup

  1. Go to SendGrid > Settings > Mail Settings > Event Webhook
  2. Click "Create new webhook" (or edit existing)
  3. Set HTTP POST URL to: https://your-domain.com/webhooks/sendgrid
  4. Select all event types under Actions to be posted:
    • Engagement data: Opened, Clicked, Unsubscribed, Spam Reports, Group Unsubscribes, Group Resubscribes
    • Deliverability Data: Processed, Dropped, Deferred, Bounced, Delivered
    • Account Data: Account Status Change
  5. Click "Test Integration" to verify - this fires all event types to your webhook
  6. Important: Click Save to enable the webhook!
  7. (Optional) Enable Signed Event Webhook for security and set SENDGRID_WEBHOOK_PUBLIC_KEY

SendGrid Webhook Setup

Event Types

Event Emoji Description
delivered โœ… Email reached recipient
open ๐Ÿ‘€ Recipient opened email
click ๐Ÿ”— Recipient clicked a link
bounce โš ๏ธ Email bounced
unsubscribe ๐Ÿ”• Recipient unsubscribed
spamreport ๐Ÿšจ Marked as spam

Environment Variables

SENDGRID_WEBHOOK_PUBLIC_KEY    # For signature verification (optional)
SENDGRID_WEBHOOK_MAX_AGE_SECONDS  # Max timestamp age (default: 300)
WEBHOOK_PORT                   # Server port (default: 8089)
DISCORD_WEBHOOK_URL            # Discord webhook URL
WEBHOOK_LOG_FILE               # Log file path

The 80,000 Hours Concept

Career as finite inventory: 40 years ร— 2,000 hrs/year = 80,000 hours.

meter.py career --hours-worked 56000 --rate 85 --raise-pct 2.5
# โ†’ 12.3 years remaining, $2.4M earning potential