Skip to content

feat(cli): add needs-me command for recent mail that needs the user - #69

Open
jacobyoby wants to merge 2 commits into
mainfrom
feat/needs-me
Open

jacobyoby wants to merge 2 commits into
mainfrom
feat/needs-me

Conversation

@jacobyoby

Copy link
Copy Markdown
Owner

What & why

Adds nodary needs-me [--days N] [--min-score S], which prints, as JSON, incoming mail from the last N days (default 30) that comes from a Tier 3 sender or scores at least S (default 25).

Scores answer "is this suspicious?". The trust tiers already answer "does this need me?", but only the dashboard could show them. This command gives other local consumers that view without opening the database: a Claude Code pane that lists and toasts these rows, or a Mail smart mailbox.

Left out:

  • the user's own addresses (user_identities)
  • server-deleted messages
  • no-reply senders (no-reply, no.reply, donotreply, mailer-daemon, bounce, ...) unless they reach the score threshold. Replying once in a thread such a sender started can lift it to Tier 3, yet it cannot be a correspondent.

--days < 1 and --min-score outside 0-100 exit 2 before the database is opened. The decision is recorded in ADR 0003.

On a real 35k-message database this cut the 30-day view from 120 rows to about 45.

Checklist

  • uv run pytest passes (254 passed, 2 skipped)
  • uv run ruff format . && uv run ruff check . clean
  • CHANGELOG.md updated under [Unreleased]
  • No new outbound network traffic; no new persisted message content
  • Scoring changes: none. The no-reply rule is a filter in the command, not a feature, so ENGINE_VERSION is unchanged
  • New derived state: none

ty check reports the same 47 diagnostics as main, none in the changed files.

Privacy notes

Output uses the dashboard's _SCORED_MESSAGE_COLS projection and _scored_payload, so no subject, body, filename or full URL is exposed. The command only reads, and writes only to stdout.

Prints, as JSON, incoming mail from the last N days that comes from a
Tier 3 sender or scores at least --min-score. Leaves out the user's own
addresses, server-deleted messages, and unflagged no-reply senders.
Reuses the dashboard's scored-message projection, so no subject, body,
filename or full URL is exposed.

Consumed by a local Claude Code pane that lists and toasts these rows.

Docs: ADR 0003, CHANGELOG
Tests: test_needs_me_lists_scored_incoming
Verified: 254 passed/2 skipped, ruff clean, ty unchanged (47 pre-existing),
cross-checked by qwen-3.8 (cerebras lane)

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Code review skipped — your organization has no extra usage available to pay for this review.

If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.

Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.

A server-rejected password login raised imapclient's LoginError out of
cmd_sync, which stopped every later account and left last_error empty.
It is now recorded as the account's last_error and the sync moves on,
exiting 1 as for any failed account. OAuth2 accounts keep their
refresh path, and other errors still propagate.

Found when a needs-me consumer polling `nodary sync` stalled on one
account whose Google Workspace password was no longer accepted.

Tests: test_sync_continues_after_password_login_rejected (fails before)
Verified: 255 passed/2 skipped, ruff clean, ty unchanged (47 pre-existing),
cross-checked by qwen-3.8 (cerebras lane)
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