Extract entire investigate into the entire-investigate plugin - #2515
Merged
Merged
Conversation
Moves the multi-agent investigation command out of this repository and into github.com/entireio/entire-investigate, where it ships as an external command. `entire investigate` keeps working: the dispatcher resolves `entire-investigate` on $PATH once the plugin is installed (`entire plugin install investigate`). Removed: cmd/entire/cli/investigate/ (and its flowchart subpackage), the investigate bridge, cmd/entire/cli/agentlaunch/ (investigate was its only consumer), the integration test, the labs and agent-help entries, and the root registration. 13k lines. Kept, deliberately: everything investigation-related that the CLI reads on its own behalf. session.KindAgentInvestigate and the run-id/topic fields, provenance's ENTIRE_INVESTIGATE_* names, and the checkpoint metadata's HasInvestigation/InvestigateRunID/InvestigateTopic are the contract the plugin writes and this CLI consumes — condensation sets the umbrella flag from the session kind, the lifecycle hook adopts the env vars, and `entire status` and `entire explain` report both. None of that moves with the command. settings.InvestigateConfig becomes an unread json.RawMessage ----------------------------------------------------------- The plugin now owns its configuration in .entire/investigate.local.json. The `investigate` key here cannot simply be deleted: settings are decoded with DisallowUnknownFields, so a leftover block makes the settings load fail, and that disables the whole CLI in the repository rather than just the moved command. Every repo that ran the built-in command has one, in the untracked local file the picker wrote. The field is therefore retained as a raw message that nothing reads — the same treatment LocalDev already gets — with regression tests covering both halves: a leftover key still loads and does not disturb the rest of the file, and it no longer reaches the agent-instruction trust gate. That gate loses its investigate arm. It can only gate fields the CLI understands, and the CLI no longer feeds this one to anything; the plugin applies the equivalent check to its own file, which has no committed counterpart at all. The provenance tests that used investigate.always_prompt as their vehicle are converted to a review worker prompt rather than deleted — they cover the gate's layering and verification logic, not the moved command. docs/architecture/external-commands.md gains a section stating that settings are not a plugin extension point, since this is the first extraction to hit it and the next author will need the same answer. Drive-by: `go mod tidy` demotes go-runewidth to indirect (investigate's TUI was its only direct consumer), and filesystem-safety.md's "eighteen files call settings.Load directly" was already stale before this change — it is 22 now, so the claim is reworded to stop tracking an exact count. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M2QRA3AZADW2PVC6Y71P0KEG
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings remain.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Extracts entire investigate into an external plugin while preserving lifecycle metadata, checkpoints, and legacy settings compatibility.
Changes:
- Removes the built-in investigation implementation and registration.
- Retains legacy settings as unread raw JSON.
- Updates trust handling, documentation, and dependencies.
Review notes:
- Moderate (1 vote): Complexity tooling still references the removed investigate command.
- Nit (2 votes): A settings comment still describes the removed investigate trust gate.
- Moderate (1 vote): Plugin help may display
entire-investigateinstead of the compatibleentire investigatepath. - Moderate (2 votes): Generated plugin configuration is not automatically ignored by Git.
- Critical (1 vote): Plugin
.entirepath handling does not validate against symlink redirection.
File summaries
| File | Summary |
|---|---|
README.md |
Removes the built-in investigate command listing. |
go.mod |
Demotes go-runewidth to an indirect dependency. |
docs/security-and-privacy.md |
Documents plugin prompt-trust behavior. |
docs/development/filesystem-safety.md |
Updates filesystem-safety references. |
docs/development/cli-conventions.md |
Removes built-in investigate references. |
docs/development/checkpoint-implementation.md |
Updates checkpoint documentation. |
docs/architecture/external-commands.md |
Documents plugin settings constraints. |
cmd/entire/cli/settings/settings.go |
Preserves legacy investigate settings as raw JSON. |
cmd/entire/cli/settings/settings_test.go |
Adds legacy-settings compatibility coverage. |
cmd/entire/cli/settings/agent_prompt_trust.go |
Removes CLI-owned investigate prompt gating. |
cmd/entire/cli/settings/agent_prompt_trust_test.go |
Retargets trust tests to review prompts. |
cmd/entire/cli/root.go |
Removes built-in command registration. |
cmd/entire/cli/lifecycle_test.go |
Uses retained provenance constants. |
cmd/entire/cli/labs.go |
Removes the investigate labs entry. |
cmd/entire/cli/investigate/tui_text.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/tui_sink.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/tui_sink_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/tui_model_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/tui_detail.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/tui_detail_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/testdata/prompt-with-always.txt |
Removed with the moved prompt tests. |
cmd/entire/cli/investigate/testdata/prompt-mid-loop.txt |
Removed with the moved prompt tests. |
cmd/entire/cli/investigate/testdata/prompt-first-round.txt |
Removed with the moved prompt tests. |
cmd/entire/cli/investigate/state_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/show.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/show_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/prompt.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/prompt_yn.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/prompt_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/progress.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/progress_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/picker.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/picker_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/notify_internal_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/multipicker.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/multipicker_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/manifest_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/fix.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/fix_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/findings.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/findings_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/env.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/env_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/cmd_internal_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/clean.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/clean_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate/bootstrap.go |
Removed and moved to the external plugin. |
cmd/entire/cli/investigate/bootstrap_test.go |
Removed with the moved implementation. |
cmd/entire/cli/investigate_bridge.go |
Removes the investigate bridge. |
cmd/entire/cli/investigate_bridge_test.go |
Removes bridge tests. |
cmd/entire/cli/experimental_wiring_test.go |
Removes investigate wiring coverage. |
cmd/entire/cli/agentlaunch/launch.go |
Removes the investigate-only launch helper. |
cmd/entire/cli/agentlaunch/launch_test.go |
Removes launch-helper tests. |
cmd/entire/cli/agent_help_cmd.go |
Removes investigate agent-help metadata. |
cmd/entire/cli/agent_help_cmd_test.go |
Updates agent-help expectations. |
Review details
Suppressed comments (2)
cmd/entire/cli/investigate/cmd.go:1
- Removing this package leaves the current complexity renderer broken:
tools/complexity/render.pystill callscommand("investigate.NewCommand")and includesINVinEXP_TOTAL, but the regenerated CLI reach graph can no longer contain that root, so report generation raisesKeyError. Please remove or replace that complexity metric and update the feature paths as part of the extraction.
docs/architecture/external-commands.md:243 - The plugin's root command overrides Cobra's original
Use: "investigate [seed-doc]"with"entire-investigate [seed-doc]", so generated help/usage now identifiesentire-investigaterather than the existingentire investigatecommand. That contradicts the PR's byte-identical compatibility claim; preserve the old displayed command path (or add an explicit compatibility exception and help snapshot).
- Files reviewed: 67/67 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…ate-plugin # Conflicts: # docs/development/cli-conventions.md
provenance's package comment and IsEntry both cited agentlaunch as the caller that strips provenance markers before spawning a fix agent. That package moved to the entire-investigate plugin, so the names now describe a contract that crosses a process boundary: review is in this repository, the plugin imports provenance for the same constants. IsEntry itself is unchanged and still has an in-repo caller in review/env.go. gitdir's OpenPathIn comment pointed at investigate.StateStore as the example of the stronger anchoring form. The store still exists and still reaches gitdir through OpenAt; only its address changed. Found by Entire Gates on this PR (01M2QS2RCT9Y). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M2QTQW5AK7JGC6MNKX8XTBDN
loadForWorktreeRoot listed investigate.always_prompt among the fields enforceAgentPromptTrust gates. The investigate arm was removed with the command, and this PR's own regression test asserts the key is no longer gated, so the comment contradicted the code it sits above. Found by review on this PR. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M2QZTAFF4GW6D1C57YGVW8X1
pjbgf
previously approved these changes
Sep 17, 2026
`entire investigate` was a built-in until this PR moved it to a plugin, so a user who types it has every reason to expect the command to exist. Without the offer it now answers an established command with Cobra's "unknown command for entire" — accurate, and no help at all. `graph` already had this treatment, as the one name the dispatcher offered to install rather than falling through. onDemandInstallPluginName becomes onDemandInstallPluginNames, with offersOnDemandInstall as the single predicate the resolver asks. The set stays narrow on purpose, and membership is not a reward for being official: `run` and `upgrade` are both index-listed and both stay out. The offer is a prompt defaulting to Yes that ends in a downloaded binary linked onto $PATH, so it belongs only to names this CLI previously answered itself. A regression test pins both directions, because the cost of a wrong addition is not a failed lookup. One prerequisite is worth stating where the next person will look: a name in the set must be resolvable through the plugin index, since the install path looks it up there and nowhere else. `investigate` is not indexed yet, so until it is, this converts one unhelpful message into another — the prompt resolves, finds nothing, and says so. It becomes useful the moment the index entry lands, and the alternative was shipping the plugin with the CLI having no answer for its own former command. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M2R110H1XV8PZKSZG13XX5VR
The catalog clone refreshes on a 24-hour TTL, so a plugin added today stays invisible to a cached copy for up to a day. The on-demand path then reports that the plugin "is not listed in the plugin index" — blaming the catalog for being wrong when the local copy is merely old, and pointing the user at the one thing that is already correct. That is not a corner case. It is the window immediately after a plugin is published, which is exactly when someone tries to install it. Hit for real with entire-investigate: the index entry had already merged, and `entire investigate` still reported it unlisted. A miss now forces one refresh and re-checks before reporting. The cost is confined: it runs only on a path that was about to fail and exit non-zero, only for the names in onDemandInstallPluginNames, and never on the hit path. Offline it cannot make things worse either — SyncPluginIndex falls back to the stale copy with a logged warning instead of failing, so the worst case is the same miss and the same message. The message says "refreshed for this check" rather than claiming the data is current, because that fallback means a refresh can be attempted without producing fresher data. The regression test primes the cache with a catalog that predates the entry, adds the entry upstream, and asserts the install resolves to the newly indexed repository. It fails with the forced sync removed, reproducing the reported error verbatim. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M2R397V7J2TKYJ85CTNQWQQW
A reviewer reading `Investigate json.RawMessage` reasonably asks whether unvalidated bytes are being carried through the merge. They are not, and the reason was not written down. A json.RawMessage is only ever populated by a decoder that scanned the value to find its end, so malformed content fails the surrounding parse before it reaches the field. mergeJSON puts two gates in front of it: a strict EntireSettings decode, then the map decode it takes the raw block from. Validating the bytes again in mergeInvestigate could never fail. What the field does promise is the other half: any well-formed value is accepted and none of it is interpreted. The shape of an old investigate block stopped being this CLI's business when the command left, and checking it would re-couple the two. Tests pin both halves — arbitrary content kept verbatim, a scalar accepted as readily as an object, and malformed or truncated input rejected by the parse rather than by a field-level check. Raised as finding 01M2R3DWP2K8 on this PR's trail, which read the missing validation as a silent-acceptance risk. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M2RGCE2TR2K16R0YZ80VS8KR
gtrrz-victor
approved these changes
Sep 21, 2026
Soph
added a commit
that referenced
this pull request
Sep 21, 2026
#2515 landed on main and removed the investigate entry from labs.go, which this branch had edited to use a constant — the one conflict, resolved by taking main's deletion. That merge also moved the goconst pressure rather than removing it. The three occurrences of the `investigate` literal are now lifecycle.go's kindLabel, plugin.go's onDemandInstallPluginNames (which arrived with #2515), and the allowlist entry this branch adds. So the constants this branch introduced before the merge are the wrong ones: cmdInvestigate and sessionKindLabelInvestigate are both reverted, and a single investigatePluginName in plugin.go — beside selfUpdatePluginName, whose single use makes that the established shape there — takes the dispatcher's occurrence out of the count. That leaves two literals, below the threshold, and keeps officialPlugins a uniform table of plain strings rather than one symbol among four literals. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M31QY4ZDYWFPBD8R0YH9CDRS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://entire.io/gh/entireio/cli/trails/1362
Summary
Moves
entire investigateinto entireio/entire-investigate, removing ~13k lines of built-in command code. Existing invocations and flags work unchanged once the plugin is installed.investigate, alongsidegraph, and refreshes a stale plugin index once before reporting a missing entry.investigatesettings without breaking settings loading. Configuration and prompt-trust enforcement now belong to the plugin; existing trust-gate tests are retained using review prompts.Installation and migration
Run
entire plugin install investigate(v0.1.0 is published), or accept the install prompt fromentire investigate.To retain existing configuration, copy the old
investigateobject into.entire/investigate.local.json; otherwise regenerate it withentire investigate --edit. Legacy settings blocks are safely ignored.Verification
mise run checkpasses (format, lint, unit, integration, and canary).GOOS=windows go vet ./...passes; CI is green.