Deterministic insights and review-only suggestions#48
Open
tony wants to merge 14 commits into
Open
Conversation
4 tasks
tony
added a commit
that referenced
this pull request
Jul 4, 2026
…decoupled architecture why: PR #48 (stacked on #47) was authored on the monolith; rebasing onto the ADR-0010 layered master dropped its facade-era hunks (descriptions, MCP models, the insights/suggestions CLI render layer, facade re-exports and dispatch), leaving the branch red. what: - Home INSIGHTS/SUGGESTIONS_DESCRIPTION in _text (+ CLI example groups). - Home the insight/suggestion MCP models and export them from agentgrep.mcp. - Re-land the dropped insights/suggestions CLI render layer, de-coupled from the facade; wire InsightsArgs/SuggestionsArgs dispatch in main(). - Facade re-exports; de-couple insights.py; restore cli/index cards. - Doc-console fixes + extend the doc harness data-dependent-empty set to the insights/suggestions read-only query commands. run_similarity remains exact-only (near-dup cascade follows).
tony
added a commit
that referenced
this pull request
Jul 5, 2026
…decoupled architecture why: PR #48 (stacked on #47) was authored on the monolith; rebasing onto the ADR-0010 layered master dropped its facade-era hunks (descriptions, MCP models, the insights/suggestions CLI render layer, facade re-exports and dispatch), leaving the branch red. what: - Home INSIGHTS/SUGGESTIONS_DESCRIPTION in _text (+ CLI example groups). - Home the insight/suggestion MCP models and export them from agentgrep.mcp. - Re-land the dropped insights/suggestions CLI render layer, de-coupled from the facade; wire InsightsArgs/SuggestionsArgs dispatch in main(). - Facade re-exports; de-couple insights.py; restore cli/index cards. - Doc-console fixes + extend the doc harness data-dependent-empty set to the insights/suggestions read-only query commands. run_similarity remains exact-only (near-dup cascade follows).
tony
added a commit
that referenced
this pull request
Jul 6, 2026
…decoupled architecture why: PR #48 (stacked on #47) was authored on the monolith; rebasing onto the ADR-0010 layered master dropped its facade-era hunks (descriptions, MCP models, the insights/suggestions CLI render layer, facade re-exports and dispatch), leaving the branch red. what: - Home INSIGHTS/SUGGESTIONS_DESCRIPTION in _text (+ CLI example groups). - Home the insight/suggestion MCP models and export them from agentgrep.mcp. - Re-land the dropped insights/suggestions CLI render layer, de-coupled from the facade; wire InsightsArgs/SuggestionsArgs dispatch in main(). - Facade re-exports; de-couple insights.py; restore cli/index cards. - Doc-console fixes + extend the doc harness data-dependent-empty set to the insights/suggestions read-only query commands. run_similarity remains exact-only (near-dup cascade follows).
why: The insights analysis and suggestion workflows have different ownership boundaries and failure modes from the DB cache. Recording them as separate ADRs keeps the architecture reviewable while preserving the deterministic-first insight decision and the review-only suggestion boundary. what: - Add ADR 0006 for deterministic insights, variants, omissions, and optional semantic backends. - Add ADR 0007 for reviewable suggestion skills and AGENTS.md/skill change semantics. - Register both ADRs in the development architecture decision index.
why: ADR 0006 needs the DB index to carry deterministic similarity features and persisted artifact tables before the insight engines can land. Deferring feature extraction by default keeps db sync responsive while inline mode populates the feature cache during sync itself. what: - Add the record_features table plus insight-run, cluster, variant-edge, omission-finding, and suggestion artifact schema to DbStore. - Add simhash/minhash/quality-flag feature builders with a batched missing-feature refresh API and feature-refresh progress reporting. - Add db sync --features defer|inline, features-deferred counters in sync results, progress lines, and human summaries. - Extend db status and the db_status MCP payload with feature and artifact counts, and cover feature modes and refresh with tests.
why: ADRs 0006 and 0007 call for deterministic insight outputs and review-only instruction suggestions over the DB index. The engines generate persisted, evidence-backed artifacts without calling an LLM and without editing instruction files. what: - Add InsightEngine with similarity variant edges, omission findings, bounded persisted listings, count APIs, and live analyze progress with feature-refresh and artifact-write counters. - Add the review-only SuggestionEngine with persisted suggestion artifacts rendered for human review. - Add agentgrep insights analyze|list|explain and suggestions list|show|render with human summaries by default and explicit JSON and NDJSON modes. - Add the read-only insights_list and suggestions_list MCP tools with bounded payloads and totals. - Cover engines, CLI contracts, progress rendering, and MCP payloads with regression tests.
why: The insights and suggestions command groups should follow the existing CLI documentation contract, with feature explanations under /insights/ and the MCP tool surface documented alongside the other read-only tools. what: - Add argparse-backed CLI pages for insights analyze|list|explain and suggestions list|show|render with grid cards and toctree entries. - Add the /insights/ feature guide and suggestions workflow page. - Register insights_list and suggestions_list across the MCP docs, reference pages, and docs-build shim. - Extend rendered-doc regression coverage to the new command pages.
why: The insight and suggestion listing tools opened the cache through the migration path without closing it, leaking one SQLite connection per MCP call and writing schema metadata from surfaces documented as read-only. The insights and suggestions CLI commands leaked their per-call connections the same way. what: - Open the insights_list and suggestions_list helpers read-only and close them via the runtime context manager. - Close the per-call runtime in run_insights_command and run_suggestions_command on every exit path. - Assert both tool helpers and the CLI path leave their connections closed.
why: The schema-version-mismatch rebuild dropped only the base tables, so feature rows and insight artifacts survived a rebuild with stale contents keyed to regenerated record ids — breaking ADR 0008's promise that a mismatch recreates the schema empty. what: - Extend the rebuild drop list with the feature and artifact tables, children before parents. - Seed features and variant edges in the rebuild test, assert every status count is zero afterward, and assert sqlite_master matches a fresh create so future drop/create drift fails mechanically.
why: insights list and explain, suggestions show and render, and suggestions list without a target only read persisted artifacts, yet they opened the cache through the migration path, which writes schema metadata on every call and creates a missing cache as a side effect. The db status surfaces and the MCP listing tools already follow the read-only contract. what: - Route the read-only insights and suggestions actions through a shared read-only open with the db-status semantics: empty payloads for missing caches without creating the file, and clean errors for foreign files. - Keep writable opens for insights analyze and suggestions list with a target. - Cover missing-cache list behavior for both command groups and pin the read actions to read-only captured opens.
why: Suggestion listings fetched every persisted row while the sibling insight listings were explicitly bounded with totals and truncation flags. Suggestion rows accumulate across targets and runs, so the list surfaces need the same page discipline. what: - Add count_suggestions and a limit parameter to list_suggestions, backed by a confidence-order index. - Add --limit to suggestions list with parse-time validation, and emit a bounded payload with total, returned, and truncated fields plus a matching human summary. - Extend the suggestions_list MCP tool and response model with limit, total, and truncation fields. - Cover parser cases, the bounded CLI payload, and the bounded MCP payload, and document the new flag and response shape.
why: The lazy-import rule reserves function-local imports for heavy modules that hurt CLI cold-start. json is a cheap stdlib module, and insights.py is itself only imported by insight commands. what: - Move the json import from InsightEngine._record_run to module level.
why: simhash_hex, minhash_signature, and format_db_deferred_count are pure, offline-runnable helpers whose siblings all carry Examples blocks; the doctest guidance covers them the same way. what: - Add Examples sections to the two feature-signature helpers and the deferred-count formatter.
…files why: The insight and suggestion listing tools returned an empty payload for a missing cache file but surfaced a raw tool error for a file that exists and is not a SQLite database — inconsistent with db_status and the CLI read surfaces, which treat both the same way. what: - Catch sqlite3.DatabaseError around the read-only opens in _insights_list_sync and _suggestions_list_sync and return the same empty payload the missing-file branch uses, extracted into shared builders. - Cover both tools against a plain-text cache file with named cases.
why: master already defines ADR 0006 (public-cli-mcp-surface-contract) and ADR 0007 (query-language-comparison). Rebasing this branch onto master left two same-numbered ADR files on disk. Move the insights and suggestion-skill ADRs to the next free numbers after the stacked DB ADRs (0015/0016) so ADR numbers stay unique. what: - Rename agentic-insights-engine 0006 -> 0017. - Rename suggestion-skills-and-agent-instruction-changes 0007 -> 0018. - Update the ADR toctree order.
…decoupled architecture why: PR #48 (stacked on #47) was authored on the monolith; rebasing onto the ADR-0010 layered master dropped its facade-era hunks (descriptions, MCP models, the insights/suggestions CLI render layer, facade re-exports and dispatch), leaving the branch red. what: - Home INSIGHTS/SUGGESTIONS_DESCRIPTION in _text (+ CLI example groups). - Home the insight/suggestion MCP models and export them from agentgrep.mcp. - Re-land the dropped insights/suggestions CLI render layer, de-coupled from the facade; wire InsightsArgs/SuggestionsArgs dispatch in main(). - Facade re-exports; de-couple insights.py; restore cli/index cards. - Doc-console fixes + extend the doc harness data-dependent-empty set to the insights/suggestions read-only query commands. run_similarity remains exact-only (near-dup cascade follows).
why: run_similarity only clustered exact normalized-hash duplicates; the persisted MinHash/SimHash sketches went unused. This consumes them to surface near-duplicate prompt variants deterministically, without an LLM or new dependencies. what: - db.py: iter_feature_rows() + DbFeatureRow load the persisted MinHash signature and record text per record (INNER JOIN record_features). - insights.py: a near-dup cascade after the exact pass — LSH-band the 16-hash MinHash signature to generate candidates, verify with exact token-set Jaccard (>= 0.6), cluster with dict-based union-find, and write near_duplicate_prompt clusters + near_duplicate variant edges (idempotent edge/cluster ids; deterministic ordering). - Tests cover detection, exact/near separation, threshold, transitive clustering, and run determinism.
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.
Motivation — why deterministic insights + review-only suggestions
Once history is a durable local read model (#47), the higher-value questions are interpretive, not retrieval: which prompts are duplicates or the same intent across projects (variant edges), which recurring instruction is absent from a given
AGENTS.md/ skill surface (omission findings), and which of those should become a reviewable instruction-change suggestion. The need is to surface recurring asks, forgotten-but-similar past conversations, and instruction-change candidates — without an LLM and without unbounded pairwise comparison.LLM-free-by-default is a trust requirement: results must be reproducible and evidence-backed, and normal search must stay a read-only local evidence surface. An LLM reaches this surface only by explicitly invoking a CLI/MCP tool, never implicitly (ADR 0017/0018). Semantic/vector backends stay an optional later extra, never a required dependency.
The problem being solved
ranking.py:collapse_near_duplicatesis a nestedWRatioloop, and RapidFuzz'sprocess.cdistmaterializes a fulllen(a)×len(b)score matrix (process_py.py). Both are correct for a small already-retrieved result page and wrong for global clustering. The discipline that makes it cheap is cpython'sdifflib.get_close_matches: a strict cheap→expensive admissible cascade (difflib.py).AGENTS.md/ skills. They render for human review as a diff and never auto-edit files or call an LLM (ADR 0004's query/plan/execute/sink separation, applied to a mutation-shaped surface).Design inspiration
The deterministic similarity cascade — map
difflib's discipline onto the persisted sketches.get_close_matchesrunsreal_quick_ratio(O(1) length bound) →quick_ratio(multiset overlap) →ratio(full), admitting only survivors to each stage. Port that shape at scale: LSH-band collision (cheapest gate over the storedminhash_json) → SimHash-Hamming / MinHash-overlap estimate (medium) → exact token-set Jaccard verify (authoritative) → dict-based union-find clustering (~15 lines, path compression). Add difflib's free prunes: a length-ratio gatemin(|A|,|B|)/max(|A|,|B|) ≥ thresholdbefore the Jaccard verify (bounds), and anautojunk-style corpus-document-frequency drop of ubiquitous shingles (__chain_b). semhash validates the clustering shape — greedy keep-first-representative over the candidate set (semhash.py). All sketches arehashlib-only (never the process-randomizedhash()), with the algorithm + params recorded as provenance so a run is re-derivable.The optional semantic tier — always an extra over the same SQLite file. Gate it behind
agentgrep[semantic]: a pure-numpy static embedding (model2vec: tokenize → gather → mean-pool, no torch —model.py) behind anEncoderProtocol whose default is the substring/no-op path; vicinity's default backend is exact brute-force numpy cosine (basic.py), so no ANN dependency for the common case. When installed, store vectors in the same DB via sqlite-vec'svec0virtual table (README) and back the FTS candidate generator with external-content FTS5, exactly as sqlite-rag keeps everything in one SQLite file (database.py).Review-only suggestions — propose-don't-apply, borrowed from git and jj. Render each suggestion as a
difflib.unified_diffagainst the live target and persist a pre-image fingerprint on the artifact — the way a unified diff's extended header records blob identity (diff-generate-patch.adoc). A future opt-insuggestions applyshould mirrorgit apply: a--checkdry-run that reports applies-cleanly / drift without touching the file (git-apply.adoc), atomic write on a clean pre-image match, and refuse-on-drift by default (atomicity). Make it undoable like jj — append a content-hashed apply-op sosuggestions apply --undorestores the pre-image and history is never destroyed (op_store.rs,operation/restore.rs). Because rendered evidence is prompt-derived, route it through a span-based redactor (presidio's analyze→anonymize split; a small built-in recognizer set for emails, home-dir →~, tokens —replace.py).Rendering + MCP DX, pi-minimal, one emitter → three surfaces. Keep
to_mermaid(run),rank_rows(run),to_unified_diff(suggestion)as pure functions returningstr/rows. Emit the insight graph as a fencedmermaidflowchart LR(clusters assubgraph, variant edges asA -->|0.82| B, oneclassDefper cluster), bounded like Mermaid's ownmaxEdgescap with a terse%% N more omittedfooter (grammar). Human CLI mode stays calm — RichTable(box=None, show_edge=False)(box.py); the TUI feeds the same rows into the existingOptionList.insights_list/suggestions_listreturn typed Pydantic models (autooutput_schema+structured_content,readOnlyHint) with per-run artifacts as templated resourcesagentgrep://insights/{run_id}(ToolResult, templates); an eventual interactivesuggestions applymaps naturally toContext.elicitfor the human-approve step (context.py).Stacked on #47 — retarget to
masterafter it merges; until then the diff below is insights/suggestions only.Summary
record_featurestable (simhash/minhash/quality flags) plus insight-run, cluster, variant-edge, omission-finding, and suggestion schema.db sync --features defer|inlinedefers expensive feature extraction by default, with a batched missing-feature refresh API for insight runs.agentgrep insights analyze|list|explaincomputes similarity variant edges (simhash/minhash candidates confirmed by token-set Jaccard) and omission findings against a--targetfile, persisting runs, clusters, and evidence rows with provenance — no LLM involved.insights listpages with a default limit backed by a confidence-order index,explainis count-only, and listing payloads render as human summaries by default with explicit--json/--ndjson.agentgrep suggestions list|show|renderturns insight evidence into persisted instruction-change suggestions for AGENTS.md/skill surfaces. Suggestions render for human review; agentgrep never edits instruction files or calls an LLM automatically.insights_listandsuggestions_listwith bounded listing payloads and result totals.Changes by area
Storage
src/agentgrep/db.py: feature builders, the feature/artifact schema,--featuressync modes with deferred counters,refresh_missing_featureswith progress reporting, and similarity-row iteration.Engines
src/agentgrep/insights.py:InsightEnginewith similarity and omission analysis, bounded listings, and count APIs.src/agentgrep/suggestions.py:SuggestionEngineproducing persisted, review-onlySuggestionArtifactrows tied to insight evidence.CLI
src/agentgrep/cli/parser.py,src/agentgrep/cli/render.py: theinsightsandsuggestionscommand groups, analyze progress rendering, bounded listing and suggestion formatters, parse-time--targetrequirement for omission runs.MCP
src/agentgrep/mcp/tools/insight_tools.py,src/agentgrep/mcp/models.py: two read-only tools with pydantic response models and capability registration.Docs
ADRs 0006–0007; per-command CLI pages for
insightsandsuggestions; the/insights/feature section; MCP tool documentation.Design decisions
Test plan
tests/test_db_index.py— feature modes, batched feature refresh with progress, deferred counterstests/test_cache_cli.py—insights/suggestionsCLI contracts: bounded listings, human summaries, analyze progress, early exit,--targetrequirement, JSON/NDJSON stdouttests/test_agentgrep_mcp.py— bounded MCP listing payloads with totalstests/test_widgets.py— rendered command-page docs for both groupsruff check/ruff format,ty check,uv run pytest(incl. doctests),just build-docs