Skip to content

feat: scaffold managed search subagents#833

Open
alishakawaguchi wants to merge 49 commits intomainfrom
search-subagents
Open

feat: scaffold managed search subagents#833
alishakawaguchi wants to merge 49 commits intomainfrom
search-subagents

Conversation

@alishakawaguchi
Copy link
Copy Markdown
Contributor

@alishakawaguchi alishakawaguchi commented Apr 1, 2026

Summary

  • scaffold managed Claude, Codex, and Gemini search subagents during setup
  • require managed search subagents to use entire search --json so they do not open the interactive TUI

Test Plan

  • mise run test:ci

Note

Medium Risk
Modifies the entire enable/configure setup path to write new agent files into repos, which could affect onboarding behavior and file overwrite semantics (though conflicts are explicitly avoided).

Overview
Adds scaffolding of an Entire-managed entire-search subagent when enabling hooks for Claude, Codex, or Gemini, with templates that explicitly require entire search --json (to avoid opening the interactive TUI).

Introduces setup_subagents.go to create/update managed subagent files, skip overwriting user-owned files, and report status to the CLI output; wires this into setupAgentHooks for both interactive and --agent flows. Expands unit + integration coverage to assert the subagent files are generated and contain the required marker and --json instructions.

Written by Cursor Bugbot for commit a135fd3. Configure here.

evisdren and others added 30 commits March 11, 2026 13:10
New command that calls the Entire search service to perform hybrid
semantic + keyword search over checkpoints. Auth via GitHub token
(GITHUB_TOKEN env var or `gh auth token`). Supports --json for
agent consumption, --branch filtering, and --limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract repeated test string to constant (goconst)
- Suppress gosec G704 SSRF warning on trusted URL (gosec)
- Handle tabwriter Flush error (gosec G104)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The search service now returns full checkpoint data (commit info, token
usage, file stats, etc.) instead of just IDs and scores. Updated Result
struct and display to use the new nested searchMeta and camelCase fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove TUI, tabwriter, and --json flag. Output is always JSON,
making the command straightforward for agent and script consumption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TrimSpace on GITHUB_TOKEN env var to handle trailing newlines
- Reject non-github.com remotes in ParseGitHubRemote with clear error
- Add httptest-based tests for Search(): URL/query construction, auth
  header, branch/limit omission, JSON error handling, raw body error,
  and successful result parsing
- truncateStr was already removed with the TUI deletion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- entire login: GitHub OAuth device flow, stores token in .entire/auth.json
- entire logout: removes stored credentials
- entire auth-status: shows token source (file, env, or gh CLI)
- Token resolution: .entire/auth.json → GITHUB_TOKEN → gh auth token
- Search command uses new resolver instead of inline token logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removes GITHUB_TOKEN env var and gh CLI token fallbacks from
ResolveGitHubToken so the CLI exclusively uses the token stored by
'entire login' (GitHub device flow). If no token is found, the user
is directed to run 'entire login'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: c175a1a3a7c5
- gosec: nolint OAuth endpoint URL (G101) and token field (G117) false positives
- errcheck: explicit type assertion for error_description; handle readAuth errors in Set* funcs
- nilnil: replace (nil, nil) with errNoAuth sentinel in readAuth
- forbidigo: nolint os.Getwd() in authFilePath (walks up dirs, handles subdirectories)
- perfsprint: errors.New for static strings, strconv.Itoa for int formatting

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The file manages a JSON file in .entire/auth.json, not a system keyring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- auth_cmd.go: guard against panic on short tokens in auth-status masking
- auth_cmd.go: use SetStoredAuth for atomic token+username write on login
- auth_cmd.go: pass raw interval to WaitForAuthorization (floor moved to auth logic)
- auth_cmd.go: call GetStoredToken directly, remove ResolveGitHubToken indirection
- github_device.go: unexport pollForToken (internal implementation detail)
- github_device.go: enforce 5s minimum polling interval inside WaitForAuthorization
- resolve.go: remove ResolveGitHubToken wrapper, keep only SourceEntireDir constant
- search_cmd.go: call GetStoredToken directly
- search.go: use http.DefaultClient consistently (matches auth package)
- store.go: replace deprecated os.IsNotExist with errors.Is(err, fs.ErrNotExist)
- store.go: add SetStoredAuth for atomic single-write of token+username
- store_test.go: add 5 tests covering walk-up, round-trip, no-file, atomic write, preservation
- README.md: document device flow auth, remove GITHUB_TOKEN/--json references

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- store.go: unexport setStoredToken/setStoredUsername (dead external API)
- store.go: move SourceEntireDir constant here, delete resolve.go
- github_device.go: add io.LimitReader(1MB) to all three auth HTTP reads
- README.md: add login/logout/auth-status to commands table and Authentication section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- revive: rename 'real' variable to 'resolved' (shadows builtin)
- usetesting: replace os.Chdir with t.Chdir (handles restore automatically)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Default to OS keyring (macOS Keychain, Linux Secret Service, Windows
Credential Manager) via go-keyring. Fall back to .entire/auth.json
when ENTIRE_TOKEN_STORE=file, matching the entiredb tokenstore pattern.

- store.go: introduce tokenStore interface with keyringTokenStore and
  fileTokenStore implementations; sync.Once backend resolution
- auth_cmd.go: use TokenSource() instead of hardcoded SourceEntireDir
- store_test.go: TestMain forces file backend; resetBackend() between
  tests; add TestTokenSourceFileBackend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- wrapcheck: nolint thin public wrappers over tokenStore interface
- nolintlint: remove unused errcheck from TestMain nolint directive

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The CLI was calling /search/v1/{owner}/{repo} but the search worker
expects /search/v1/search with repo as a query parameter. Also updates
response types to match the worker's envelope format and removes the
unsupported --branch flag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b717aa3abf43
Replace raw JSON default output with an interactive TUI featuring:
- Editable search bar (/ to focus, Enter to re-search)
- Navigable results table (j/k or arrow keys)
- Bordered detail card showing all checkpoint fields
- --json flag preserves machine-readable output
- Auto-JSON when piped, static table when ACCESSIBLE=1
- `entire search` with no args opens TUI with search bar focused

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 06f92d81abef
- Embed statusStyles in searchStyles, eliminating 6 duplicate fields
- Remove redundant s() method, use inherited render() instead
- Extract isTerminalWriter() to status_style.go for shared TTY detection
- Remove unused height field and redundant zero-value cursor init
- Use formatCommit() in detail card instead of inline duplication
- Extract indentLines() helper to deduplicate line-indentation loops

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1d48f1667fb4
- README: remove undocumented --branch flag, add --json and no-args usage
- search.go: check Error field on HTTP 200, use dedicated http.Client
  instead of DefaultClient, remove unused Timing field
- search_tui.go: remove phantom "enter select" from help bar
- Tests: add TestSearch_ErrorFieldOn200, TestSearchModel_SearchModeEnter,
  TestSearchModel_SearchModeEnterEmpty; remove duplicate NavigationJK
  and tautological DerefStr tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b30c1e2e013b
- Add --author and --date CLI flags for filtering search results
- Support filter syntax in search bar: author:<name> date:<week|month>
- Quoted values for multi-word filters: author:"Alice Smith"
- Wildcard query (*) when only filters are provided
- Pagination: 25 results per page, n/p or arrow keys to navigate
- Alt-screen mode for full-terminal TUI
- Filter hint shown below search bar in edit mode
- Hide search command from --help (not GA yet)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 34f923edfe2a
…nation tests

- Extract search.WildcardQuery constant for filter-only queries
- Add Config.HasFilters() to centralize filter-awareness
- Cache totalPages() in viewHelp to avoid redundant calls
- Add tests for pagination: PageResults, TotalPages, SelectedResult,
  PageNavigation, and Config.HasFilters

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d70c3fca57cf
Show username as the primary identifier in both the TUI table rows and
detail view, with the display name in parentheses (e.g. "dipree (Daniel
Adams)") instead of the previous format ("Daniel Adams (@dipree)").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b6453d19cf07
…ng in search

- Add IsAccessibleMode() to no-query error guard so ACCESSIBLE=1 requires
  a query (matching --json behavior) instead of launching the TUI
- Add Page field to search.Config and send page param to API, enabling
  lazy-fetch pagination in the TUI when navigating past loaded results
- Use API total count for totalPages() so footer reflects true result count
- Always reset Author/Date from parsed input on new interactive searches
  so startup filters don't persist invisibly across searches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: ac93f036697d
The search API uses the limit param to cap total results fetched from the
index, not just the page size. This means the page param alone doesn't
enable pagination — total never exceeds limit. Work around this by
requesting MaxLimit (200) in TUI mode so client-side pagination works
with up to 8 pages of 25 results.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1c0d807f956c
alishakawaguchi and others added 12 commits March 31, 2026 13:57
- Remove tautological TestNewSearchCmd_Flags (only checked cobra flags exist)
- Rewrite TestSearchCmd_AccessibleModeRequiresQuery to verify exact error
  message through root.Execute() instead of accepting any error
- Add tests for fetch-more error path, exhausted API capping total,
  "Loading more results..." view state, filter persistence to searchCfg,
  and apiPage initialization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b6c45b0e881f
…rminal panic

Fixes from bugbot review:
- Support ssh://git@github.com/owner/repo.git URL format in
  ParseGitHubRemote by using url.Parse for all scheme-based URLs
- Strip quotes from date filter values (date:"week" → week) matching
  the existing behavior for author filters
- Guard contentWidth with max(0) to prevent strings.Repeat panic
  on terminals narrower than 2 columns

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 193b538cd33e
CLI args like `entire search auth author:alice` were sending
"auth author:alice" as the raw query instead of extracting the
filter. Now runs ParseSearchInput on CLI args to extract inline
filters, with --author/--date flags taking precedence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2da0d9d74b06
Support --branch flag, branch:name inline syntax in CLI args and
TUI search bar, sent as branch query param to the search API.
Included in HasFilters() so filter-only searches work.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 85fab7ef1506
The no-query + non-interactive error check ran after auth lookup,
so in environments without credentials (CI) it would fail with
"not authenticated" instead of the expected "query required" error.
Move the check before auth/git operations since it only needs the
parsed flags.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d57341dbb0a2
…ng to search TUI

- Wrap browse mode in a scrollable viewport with mouse wheel support
- Add full-screen detail view (enter key) with viewport scrolling
- Word-wrap long prompts in detail view
- Truncate inline detail card to 15 lines with "enter for more" hint
- Isolate search input mode (/ key) from results rendering
- Show full response body in error messages instead of cryptic JSON parse errors
- Add modeDetail with esc/backspace to return, / to search from any mode

Co-Authored-By: Claude <noreply@anthropic.com>
Entire-Checkpoint: c07dfe9d6805
- Add --page flag (1-based, default 1) and --limit (default 25)
- JSON output includes total, page, total_pages, and limit metadata
- All output modes now fetch MaxLimit (200) from API and paginate
  client-side, matching TUI behavior
- Extract writeSearchJSON helper to keep maintainability index clean

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 923884bba18b
- Add --page flag with client-side pagination for JSON output
- Fetch MaxLimit (200) results for all output modes, paginate locally
- JSON output includes total, page, total_pages, limit metadata
- Fix accessible table double-space separators to match computeColumns
  gap assumption (prevents 4-char terminal overflow)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 8f78632c349e
Entire-Checkpoint: fd342fecde72
Entire-Checkpoint: 87df419289ee
Copilot AI review requested due to automatic review settings April 1, 2026 23:59
@alishakawaguchi alishakawaguchi changed the base branch from main to cli_search April 2, 2026 00:00
@alishakawaguchi alishakawaguchi changed the title feat: improve CLI search and scaffold managed search subagents feat: scaffold managed search subagents Apr 2, 2026
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 an entire search feature to the Entire CLI, including a Bubble Tea-powered interactive TUI, JSON output for automation/subagents, and automatic scaffolding of “managed search” subagent configs during setup.

Changes:

  • Introduces a new entire search command with inline filters, pagination, JSON output, and an interactive TUI.
  • Adds scaffolding logic + tests to generate managed search subagent files for Claude, Codex, and Gemini during agent setup.
  • Adds unit + integration tests covering search behavior, parsing, TUI state transitions, and subagent scaffolding.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
go.mod Promotes Bubble Tea/Bubbles deps to direct requirements for the search TUI.
cmd/entire/cli/status_style.go Refactors terminal detection into isTerminalWriter reused by search.
cmd/entire/cli/setup.go Hooks setup now also scaffolds managed search subagents and reports scaffold status.
cmd/entire/cli/setup_subagents.go Implements managed search subagent scaffolding + conflict handling + templates.
cmd/entire/cli/setup_subagents_test.go Adds unit tests for create/update/idempotency/conflict behavior of scaffolding.
cmd/entire/cli/search/search.go Implements search client, inline filter parsing, repo filter validation.
cmd/entire/cli/search/search_test.go Adds unit tests for URL construction, errors, filters, parsing, validation.
cmd/entire/cli/search/github.go Adds GitHub remote URL parsing helper for owner/repo inference.
cmd/entire/cli/search_tui.go Adds Bubble Tea TUI (browse/search/detail), pagination, static accessible output.
cmd/entire/cli/search_tui_test.go Adds extensive TUI model tests and formatting helper tests.
cmd/entire/cli/search_cmd.go Adds new search Cobra command with auth + git remote detection + output modes.
cmd/entire/cli/search_cmd_test.go Tests command help text and JSON pagination defaults / accessible behavior.
cmd/entire/cli/root.go Registers the new search command.
cmd/entire/cli/integration_test/setup_gemini_hooks_test.go Verifies Gemini enable scaffolds managed search subagent content.
cmd/entire/cli/integration_test/setup_codex_hooks_test.go Adds integration smoke test for Codex hooks + managed search agent scaffold.
cmd/entire/cli/integration_test/setup_claude_hooks_test.go Verifies Claude enable scaffolds managed search subagent content.
.claude/agents/search.md Adds a committed managed search subagent file for Claude.
.codex/agents/search.toml Adds a committed managed search subagent file for Codex.
.gemini/agents/search.md Adds a committed managed search subagent file for Gemini.

Comment on lines +1 to +12
---
name: search
description: Search Entire checkpoint history and transcripts with `entire search`. Use proactively when the user asks about previous work, commits, sessions, prompts, or historical context in this repository.
tools: Bash
model: haiku
---

<!-- ENTIRE-MANAGED SEARCH SUBAGENT v1 -->

You are the Entire search specialist for this repository.

Your only history-search mechanism is the `entire search` command. Do not fall back to `rg`, `grep`, `find`, `git log`, or ad hoc codebase browsing when the task is asking for historical search across Entire checkpoints and transcripts.
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

This committed Claude search subagent instructs using entire search and only “prefers” --json, which contradicts the PR’s requirement that managed search subagents must use entire search --json (and never run plain entire search, since it opens the TUI). Update this file’s description/instructions to require --json and explicitly forbid running without it, matching the scaffolded template used by setup.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +17
---
name: search
description: Search Entire checkpoint history and transcripts with `entire search`. Use proactively when the user asks about previous work, commits, sessions, prompts, or historical context in this repository.
kind: local
tools:
- run_shell_command
max_turns: 6
timeout_mins: 5
---

<!-- ENTIRE-MANAGED SEARCH SUBAGENT v1 -->

You are the Entire search specialist for this repository.

Your only history-search mechanism is the `entire search` command. Do not fall back to `rg`, `grep`, `find`, `git log`, or ad hoc codebase browsing when the task is asking for historical search across Entire checkpoints and transcripts.

If `entire search` cannot run because authentication is missing, the repository is not set up correctly, or the command fails, stop and return a short prerequisite message. Do not make repo changes.
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

This committed Gemini search subagent still frames entire search (without --json) as the primary mechanism and only “prefers” JSON output. The PR description says managed search subagents must use entire search --json to avoid launching the interactive TUI; update this file to require --json and explicitly forbid plain entire search, consistent with the scaffolding template.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +12
# ENTIRE-MANAGED SEARCH SUBAGENT v1
name = "search"
description = "Search Entire checkpoint history and transcripts with `entire search`. Use when the user asks about previous work, commits, sessions, prompts, or historical context in this repository."
sandbox_mode = "read-only"
model_reasoning_effort = "medium"
developer_instructions = """
You are the Entire search specialist for this repository.

Your only history-search mechanism is the `entire search` command. Do not fall back to `rg`, `grep`, `find`, `git log`, or ad hoc codebase browsing when the task is asking for historical search across Entire checkpoints and transcripts.

If `entire search` cannot run because authentication is missing, the repository is not set up correctly, or the command fails, stop and return a short prerequisite message. Do not make repo changes.

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

This committed Codex search subagent describes entire search as the required mechanism and only “prefers” entire search --json. The PR intent is that managed subagents must always use entire search --json (never plain entire search, which opens the TUI). Update this file’s instructions accordingly so the checked-in managed agent matches the scaffolded template/behavior.

Copilot uses AI. Check for mistakes.
Base automatically changed from cli_search to main April 2, 2026 18:35
alishakawaguchi and others added 4 commits April 2, 2026 11:36
Committed subagent files (.claude, .gemini, .codex) said "prefer" --json
but should require it to prevent launching the interactive TUI. Also add
missing exhaustive switch cases in reportSearchSubagentScaffold.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 919b0ea21d83
Avoids name collisions with user-defined "search" subagents by using a
namespaced identifier. Updates file names, template name fields, generated
paths, and all unit/integration test expectations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: e2dbf2eabdd3
@alishakawaguchi
Copy link
Copy Markdown
Contributor Author

bugbot run

Remove stale //nolint:unparam on setupAgentHooks (CI lint failure).
Change setupAgentHooksNonInteractive error from "failed to install hooks"
to "failed to setup hooks" since setupAgentHooks can also fail during
search subagent scaffolding after hooks are already installed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 7d51fef6e8c9
@alishakawaguchi
Copy link
Copy Markdown
Contributor Author

bugbot run

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.

✅ Bugbot reviewed your changes and found no new issues!

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

@alishakawaguchi alishakawaguchi marked this pull request as ready for review April 3, 2026 17:08
@alishakawaguchi alishakawaguchi requested a review from a team as a code owner April 3, 2026 17:08
@alishakawaguchi alishakawaguchi requested a review from evisdren April 3, 2026 17:08
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.

3 participants