Skip to content

feat(email): add 1m poll interval option#164

Merged
claude-puntlabs merged 1 commit intomainfrom
feat/poll-interval-1m
Apr 18, 2026
Merged

feat(email): add 1m poll interval option#164
claude-puntlabs merged 1 commit intomainfrom
feat/poll-interval-1m

Conversation

@claude-puntlabs
Copy link
Copy Markdown
Contributor

@claude-puntlabs claude-puntlabs commented Apr 18, 2026

Summary

  • Adds 1m (1 minute) as a valid poll interval alongside the existing 5m/10m/15m/30m/1h/2h options
  • Updated: validPollIntervals map, all error messages, MCP tool descriptions, command docs, README, DESIGN.md, CHANGELOG

Test plan

  • go vet ./... clean
  • go test -race -count=1 ./internal/email/ ./internal/mcp/ — all pass
  • ValidPollInterval("1m") returns true
  • PollDuration returns 1 minute for "1m"
  • All error messages and doc strings list 1m

Bead: beadle-0sv


Note

Low Risk
Low risk: adds a new allowed value to polling interval validation and updates related messaging/docs, with small unit test adjustments.

Overview
Adds 1m as an accepted inbox polling interval end-to-end (config parsing/validation, poller startup + interval errors, and the set_poll_interval MCP tool validation).

Updates /inbox command docs, README, DESIGN, and CHANGELOG to list the new interval, and extends config unit tests to cover the 1m case.

Reviewed by Cursor Bugbot for commit afe0e85. Bugbot is set up for automated code reviews on this repo. Configure here.

5-minute minimum frustrated e2e testing and is too slow for
low-latency use cases. Adds "1m" to the valid poll intervals
alongside the existing 5m/10m/15m/30m/1h/2h options.

beadle-0sv
Copilot AI review requested due to automatic review settings April 18, 2026 12:40
@claude-puntlabs claude-puntlabs merged commit ef86bc4 into main Apr 18, 2026
9 checks passed
@claude-puntlabs claude-puntlabs deleted the feat/poll-interval-1m branch April 18, 2026 12:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds 1m as an allowed inbox polling interval across the email poller, MCP tooling, tests, and user-facing documentation.

Changes:

  • Extend validPollIntervals / validation logic to accept 1m and map it to time.Minute
  • Update MCP tool descriptions + runtime error strings to include 1m in the allowed set
  • Update docs (command docs/README/DESIGN/CHANGELOG) and tests to cover 1m

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/email/config.go Adds 1m to the allowed poll interval map and updates inline docs.
internal/email/config_test.go Adds test coverage asserting 1m is valid and maps to 1 minute.
internal/email/poller.go Updates config/poller error messages to include 1m.
internal/mcp/poll_tools.go Updates MCP tool descriptions and validation error message to include 1m.
commands/inbox.md Updates /inbox command docs to recognize and document 1m (incl. cron mapping).
README.md Updates tool/command documentation to list 1m as a supported interval.
DESIGN.md Updates design documentation to include 1m as a valid persisted poll interval.
CHANGELOG.md Records the addition of the 1m poll interval option.
.ethos/missions.jsonl Adds mission log entries related to implementing/validating the change.
.beads/issues.jsonl Adds bead beadle-0sv entry for this work.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .beads/issues.jsonl
{"id":"beadle-06m","title":"Persistent inbox polling: /inbox \u003cinterval\u003e survives session restart","description":"When the user runs '/inbox 5m' (or any interval), persist the polling interval to .claude/beadle.local.md. Add a SessionStart hook that reads this file and calls CronCreate to re-register the /inbox cron automatically. Result: inbox polling resumes on every new session without the user needing to re-run the command. The /inbox status command should show whether polling is active and whether a cron is currently registered.","status":"closed","priority":2,"issue_type":"feature","owner":"claude@punt-labs.com","created_at":"2026-03-28T13:25:14.164675-07:00","created_by":"\"jmf-pobox\"","updated_at":"2026-04-01T19:12:53.451902-07:00","closed_at":"2026-04-01T19:12:53.451902-07:00","close_reason":"Closed"}
{"id":"beadle-07h","title":"fix(inbox): /inbox auto-poll cron — nonexistent description field, session-only","description":"## Problem\n\ncommands/inbox.md #123 claims /inbox 10m creates an autonomous CronCreate loop that runs /inbox every N minutes. Two bugs make it unreliable:\n\n1. **Nonexistent CronCreate.description field.** The spec says to tag the cron job with description /inbox auto-poll and later find it via CronList with that description. The CronCreate tool schema has no description parameter — only cron, prompt, recurring, durable. CronList renders as \u003cid\u003e — \u003cinterval\u003e (recurring) [session-only]: \u003cprompt\u003e. The only durable identifier is the prompt. Cleanup logic is broken and will either fail to find the job or create duplicates on repeated /inbox NNm invocations.\n\n2. **Session-only cron.** CronCreate defaults to durable=false. When the Claude session exits, the cron dies. Next session starts with server-side polling configured but no Claude-side loop to process it.\n\n## Fix\n\nRewrite commands/inbox.md argument-routing section to remove the description field references, match auto-poll jobs by prompt suffix : /inbox, use durable: true so the cron survives session restarts, and tighten delete-before-create ordering so two consecutive /inbox 10m calls leave exactly one cron.\n\n## Verification\n\n1. Fresh session: /inbox 10m → CronList shows a recurring durable job with prompt /inbox.\n2. /inbox 10m twice in a row → still exactly one job.\n3. /inbox n → job is deleted.\n4. Exit session, restart → CronList still shows the job.","status":"closed","priority":1,"issue_type":"bug","owner":"claude@punt-labs.com","created_at":"2026-04-11T07:57:41.105374138-07:00","created_by":"J F","updated_at":"2026-04-11T08:48:30.208683585-07:00","closed_at":"2026-04-11T08:48:30.208683585-07:00","close_reason":"Merged in PR #128 (squash 0d394a7). /inbox NNm now creates a durable CronCreate job with prompt-based cleanup; autonomous loop verified end-to-end on the post-merge main branch."}
{"id":"beadle-0he","title":"list_messages: sender email not discoverable for unknown contacts","description":"Beadle has no way to surface a sender's email address for someone who is not yet in the address book. This blocks contact bootstrap on a fresh install.\n\nFacts:\n- list_messages shows the display name from the From header (e.g. 'J Freeman') but NOT the email address.\n- check_trust returns trust level + permission state but NOT the email address.\n- show_mime returns the MIME part tree (type, size) but NOT the headers.\n- read_message refuses with 'permission denied: no read permission for sender \u003cemail\u003e' — the email is in the ERROR message but not in any success response for an unpermissioned sender.\n\nDES-012 claims redacted listings 'let the owner discover unknown senders and decide whether to add them to contacts.' In practice discovery is blocked: the owner can see that an unknown sender exists but cannot learn enough about them (email address) to add them to the address book.\n\nVerified 2026-04-08 on a fresh Linux install during beadle-1aj troubleshooting. With 285 unread messages in INBOX from 7 different display names, list_messages showed the display names, check_trust and show_mime returned nothing useful, and read_message on each returned the same error. The only way to learn the actual sender address was to parse the permission-denied error message.\n\nProposed fixes (any one would close the bead):\n\n1. list_messages includes the email address next to the display name in the FROM column. Format: 'J Freeman \u003cnotifications@github.com\u003e' or two columns. Today it only shows 'J Freeman'.\n\n2. A dedicated 'unknown_senders' MCP tool that returns a grouped list of (email, display_name_samples, message_count, first_seen, last_seen) for all senders not in contacts. Single tool call, everything needed to decide what permissions to grant.\n\n3. Loosen the permission gate on the From header specifically: list_messages always shows both name AND email for unpermissioned senders, while still redacting subject/body. The From header is not sensitive content — it is the identifier the owner needs to add a contact.\n\nOption 3 is the minimum viable fix and matches the intent of DES-012. Option 2 is the ergonomic fix. Option 1 is the middle ground.\n\nRelated: the display name being misleading is filed as a separate bead (notifications@github.com shows up as 'J Freeman', 'Copilot', etc. based on who triggered the event).","status":"closed","priority":2,"issue_type":"bug","owner":"claude@punt-labs.com","created_at":"2026-04-08T10:48:04.173973766-07:00","created_by":"J F","updated_at":"2026-04-08T16:47:37.888482467-07:00","closed_at":"2026-04-08T16:47:37.888482467-07:00","close_reason":"Merged in PR #102 (squash 53cc01a)","labels":["bug","contacts","ux"]}
{"id":"beadle-0sv","title":"Add 1m poll interval option","status":"in_progress","priority":2,"issue_type":"task","owner":"claude@punt-labs.com","created_at":"2026-04-18T05:34:23.144683375-07:00","created_by":"J F","updated_at":"2026-04-18T05:34:26.381483-07:00"}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

The new bead entry beadle-0sv is left with status":"in_progress", but this PR implements the feature and even attributes it in CHANGELOG. Consider marking it closed (and adding closed_at/close_reason fields consistent with other entries) to keep bead tracking in sync with the shipped change.

Copilot uses AI. Check for mistakes.
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.

2 participants