Skip to content

dispatch: add --me and --author flags#1135

Open
dvydra wants to merge 1 commit into
mainfrom
dispatch-me-and-author-flags
Open

dispatch: add --me and --author flags#1135
dvydra wants to merge 1 commit into
mainfrom
dispatch-me-and-author-flags

Conversation

@dvydra
Copy link
Copy Markdown
Contributor

@dvydra dvydra commented May 7, 2026

https://entire.io/gh/entireio/cli/trails/315

Summary

Adds two new flags to entire dispatch for narrowing the recap to a single contributor:

```
entire dispatch --me # just my work
entire dispatch --repos owner/repo --me
entire dispatch --repos owner/repo --author teammate@example.com --since 14d # specific person
entire dispatch --local --all-branches --me # local + all branches
```

--me and --author are mutually exclusive — ResolveOptions returns "--author and --me are mutually exclusive" if both are passed.

Why

Today entire dispatch --repos X returns everyone's work in repo X. The common standup/weekly-review framing ("what did I ship?") needs a way to narrow to the requester's own checkpoints — and a parallel ability to recap a teammate's recent work. Unblocks the recap skill in entireio/skills, which calls --me by default.

Behaviour

Cloud mode (mode_cloud.go): --me and --author flow into CreateDispatchRequest and are forwarded as JSON fields to POST /api/v1/dispatches/generate. The server resolves them to a commit_author_github_id filter (with commit_author_username fallback for rows where the github_login → id mapping hasn't backfilled). Depends on the server-side change in entirehq/entire.io#1840.

Local mode (mode_local.go): resolveLocalAuthorFilter lowercases the input email; --me resolves to git config user.email at run time. loadCommitAuthorsByCheckpoint maps checkpoint ID → author email by reading the metadata branch; filterCandidatesByAuthor applies the filter case-insensitively.

Wizard: gains an "Author scope" question — Everyone (default) / Just me / Specific person… (third option prompts for an email).

Author semantics — known difference between modes

  • Local: matches against the commit author email (from git)
  • Cloud: matches against the requester's GitHub login (the server doesn't currently resolve emails to logins — see entirehq/entire.io#1840)

Future work can unify these by adding email lookup server-side. For now, users running cloud dispatches should pass a GitHub login as --author; the email form works in --local.

Tests

  • TestResolveOptions_PropagatesAuthor / _PropagatesMe — flag plumbing through ResolveOptions
  • TestResolveOptions_RejectsAuthorAndMeTogether
  • TestResolveOptions_WhitespaceAuthorWithMeIsAllowed — empty/whitespace --author is ignored, not a conflict with --me
  • TestCloudClient_CreateDispatch_SendsAuthorAndMeWhenSet — JSON serialisation
  • mode_local_test.go adds cases for resolveLocalAuthorFilter (--author, --me, neither) and filterCandidatesByAuthor (matching, mismatching, missing-author maps)
  • dispatch_wizard_test.go covers the new scope-selection branch

Test plan

  • mise run fmt && mise run lint — clean (0 issues across all linters)
  • go test ./cmd/entire/cli/dispatch/... — all pass
  • mise run test:ci — passes on main and on this branch in CI's UTC timezone (note: there's a pre-existing AEST-flake in TestGroupCommitsByDay_SortsNewestFirst in cmd/entire/cli/activity_cmd_test.go that fails locally for users in zones where the test's hardcoded UTC times span date boundaries differently; not introduced by this PR — it fails on main too)

Follow-ups (not in this PR)

  • Server-side: extend dispatch to accept email-form --author (currently only resolves GitHub logins). Then the local/cloud author semantics align.
  • AEST timezone flake in TestGroupCommitsByDay_SortsNewestFirst — pre-existing, worth fixing separately.

🤖 Generated with Claude Code


Note

Medium Risk
Adds new user-facing filtering options that change which checkpoints are included, including new local git-log based author lookups and new cloud request fields that depend on server support.

Overview
Adds --author and --me to entire dispatch to filter the generated recap to a specific checkpoint author (with mutual exclusion enforced in ResolveOptions).

Cloud dispatch now forwards author/me in CreateDispatchRequest to the dispatch generation API, while local dispatch resolves --me via git config user.email and filters candidates by commit author on entire/checkpoints/v1.

The interactive dispatch wizard gains an Author scope step (everyone/me/specific email) and command preview now renders the new flags; tests were extended across options parsing, cloud payload serialization, and local filtering behavior.

Reviewed by Cursor Bugbot for commit 1ec45c3. Configure here.

Adds two new flags to `entire dispatch` for narrowing the recap to a
single contributor:

  entire dispatch --me                              # just my work
  entire dispatch --repos owner/repo --me
  entire dispatch --repos owner/repo --author teammate@example.com --since 14d
  entire dispatch --local --all-branches --me

Both flags are wired through `dispatch.Options.{Me, Author}` and
flow into:

- Cloud mode (`mode_cloud.go`): passed through in `CreateDispatchRequest`
  to POST /api/v1/dispatches/generate. Server resolves them to a
  `commit_author_github_id` filter (with username fallback for rows
  where the github_login → id mapping hasn't backfilled). See
  entirehq/entire.io#1840 for the server-side change this depends on.

- Local mode (`mode_local.go`): `resolveLocalAuthorFilter` lowercases
  the input email; `--me` resolves to `git config user.email`. The
  metadata-branch commit author email is matched case-insensitively
  via `loadCommitAuthorsByCheckpoint`.

`--me` and `--author` are mutually exclusive (`ResolveOptions` returns
"--author and --me are mutually exclusive").

The interactive wizard gains an "Author scope" question with three
options: Everyone (default), Just me, Specific person — the third
prompts for an email.

Tests cover:
- Flag plumbing through `ResolveOptions` (PropagatesAuthor,
  PropagatesMe, RejectsAuthorAndMeTogether,
  WhitespaceAuthorWithMeIsAllowed)
- Cloud client serialisation (SendsAuthorAndMeWhenSet)
- Local mode filter resolution (resolveLocalAuthorFilter cases) and
  candidate filtering (filterCandidatesByAuthor)
- Wizard scope selection and option mapping

Author semantics differ slightly between modes: local matches against
commit email, cloud matches against the requester's GitHub login (the
server doesn't currently resolve emails to logins). Future work can
unify these by adding email lookup server-side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1bd236e74bbd
Copilot AI review requested due to automatic review settings May 7, 2026 04:00
@dvydra dvydra requested a review from a team as a code owner May 7, 2026 04:00
Copy link
Copy Markdown
Contributor

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 contributor-scoping to entire dispatch by introducing --me and --author, enabling users to narrow dispatch recaps to a single person across both cloud and local modes.

Changes:

  • Plumbs --me / --author through CLI flag parsing and dispatch.Options, including mutual-exclusion validation.
  • Cloud mode forwards author / me fields in the dispatch generation request payload.
  • Local mode resolves --me via git config user.email and filters candidate checkpoints by metadata-branch commit author; wizard gains an “Author scope” step.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
cmd/entire/cli/dispatch.go Adds --me / --author flags and passes them into dispatch option resolution.
cmd/entire/cli/dispatch_test.go Updates CLI flag parsing tests for new parameters.
cmd/entire/cli/dispatch/options.go Adds author/me fields to resolved options and enforces mutual exclusivity.
cmd/entire/cli/dispatch/options_test.go Adds coverage for author/me propagation and mutual exclusivity.
cmd/entire/cli/dispatch/dispatch.go Extends dispatch.Options with Author/Me fields and documentation.
cmd/entire/cli/dispatch/mode_cloud.go Forwards Author/Me from options into the cloud dispatch request.
cmd/entire/cli/dispatch/cloud.go Extends CreateDispatchRequest JSON payload with author/me.
cmd/entire/cli/dispatch/cloud_test.go Adds tests ensuring JSON serialization includes/omits author/me as expected.
cmd/entire/cli/dispatch/mode_local.go Implements local author filter resolution and candidate filtering by metadata commit author email.
cmd/entire/cli/dispatch/mode_local_test.go Adds local-mode tests for --author filtering and --me email resolution.
cmd/entire/cli/dispatch_wizard.go Adds wizard “Author scope” selection and renders corresponding flags in the preview command.
cmd/entire/cli/dispatch_wizard_test.go Tests wizard scope resolution and command rendering for --me/--author.

Comment on lines +81 to +82
cmd.Flags().StringVar(&flagAuthor, "author", "", "filter to checkpoints authored by this email")
cmd.Flags().BoolVar(&flagMe, "me", false, "filter to your own checkpoints (alias for --author <self>)")
Comment on lines +37 to +39
// Author filters checkpoints to a specific author email.
// Cloud mode passes it through to the server; local mode matches it
// case-insensitively against the metadata-branch commit author.
Until string `json:"until"`
Generate bool `json:"generate"`
Voice string `json:"voice,omitempty"`
// Author filters checkpoints to a specific author email.
Comment on lines +345 to +353
Placeholder("teammate@example.com").
Value(&state.authorInput).
Validate(func(value string) error {
if state.showAuthorInput() && strings.TrimSpace(value) == "" {
return errors.New("enter an author email")
}
return nil
}),
).Title("Author email").Description("Filter to checkpoints by this email.").
Comment on lines +432 to +441
func loadCommitAuthorsByCheckpoint(ctx context.Context, repoRoot string) (map[string]string, error) {
cmd := exec.CommandContext(
ctx,
"git",
"-C",
repoRoot,
"log",
"entire/checkpoints/v1",
"--format=%ae%x00%s%x00%x00",
)
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1ec45c3. Configure here.

var exitErr *exec.ExitError
if errors.As(err, &exitErr) {
return "", nil
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

readGitUserEmail swallows fatal git exit codes

Medium Severity

readGitUserEmail treats all exec.ExitError results identically by returning ("", nil). For git config user.email, exit code 1 means "key not set" (a normal condition), while exit code 128+ indicates a real failure (e.g., corrupt .gitconfig). By not checking exitErr.ExitCode(), a genuine error is silently swallowed, and the caller produces the misleading message "requires git config user.email" instead of surfacing the actual git failure.

Fix in Cursor Fix in Web

Triggered by learned rule: Distinguish git command exit codes — exit 1 means "no results", not error

Reviewed by Cursor Bugbot for commit 1ec45c3. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants