Skip to content

Phase 1: unified detection for setup import redesign - #127

Merged
yourconscience merged 2 commits into
mainfrom
setup-import-redesign
Jul 18, 2026
Merged

Phase 1: unified detection for setup import redesign#127
yourconscience merged 2 commits into
mainfrom
setup-import-redesign

Conversation

@yourconscience

@yourconscience yourconscience commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add unified DetectedItem/DetectedSource/DetectionResult types that replace per-surface scan results with a single detection model
  • Content hashing (hashDir, hashBytes, hashMCPServer) for identity comparison across harnesses
  • Auto-resolution: items identical across all harnesses are counted as auto-resolved and excluded from review
  • Hooks excluded from detection (they flow FROM config INTO harnesses, not the reverse)
  • Managed items (symlinks to canonical) pre-filtered during detection
  • --json flag on dotagents setup emits detection result and exits
  • 8 tests covering hashing, identity marking, symlink filtering, and auto-resolution

Phase 1 of #126. Existing import flow is unchanged; --json is an early return before the current prompt-based import.

Test plan

  • go test ./... passes
  • CI green
  • Manual: dotagents setup --json emits valid JSON detection result

Summary by Sourcery

Introduce a unified detection pass for unmanaged skills, roles, and MCP servers and expose it via a new JSON-only setup mode.

New Features:

  • Add unified detection model (DetectedItem/DetectedSource/DetectionResult) for aggregating unmanaged skills, roles, and MCP servers across harnesses.
  • Add a --json flag to dotagents setup to emit the detection result as JSON and exit early.

Enhancements:

  • Implement content hashing for skills, roles, and MCP servers to determine identity and auto-resolve items that are identical across all harnesses.
  • Filter out managed items such as symlinked skills, owned roles, and already-configured MCP servers during detection.
  • Exclude hooks from detection since they are driven from the central config into harnesses rather than discovered from them.

Tests:

  • Add tests for directory hashing determinism and differences, identical-item marking, symlink/managed-skill filtering, and auto-resolution behavior in runDetection.

@sourcery-ai

sourcery-ai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Reviewer's Guide

Introduces a unified detection pipeline for setup import that scans harness configs into a single DetectionResult model, uses content hashing to deduplicate and auto-resolve identical items across harnesses, filters out managed/symlinked resources, and adds a --json flag to emit the detection result without invoking the existing interactive import flow.

Flow diagram for dotagents setup --json detection pipeline

flowchart LR
  U["User runs\n dotagents setup --json"] --> S["runSetup"]
  S -->|JSONOutput true| D["runDetection"]
  S -->|JSONOutput false| Legacy["scanNativeImports and interactive import"]

  D --> H["iterate detected agentConfig list"]
  H --> SK["detectNativeSkills"]
  H --> RO["detectNativeRoles"]
  H --> MC["detectNativeMCPServers"]

  SK --> IDX["build itemIndex[Surface:Name]"]
  RO --> IDX
  MC --> IDX

  IDX --> MI["markIdentical on each DetectedItem"]
  MI --> FLT["filter Identical items\n increment AutoResolved"]
  FLT --> RES["DetectionResult"]
  RES --> J["json.Encoder.Encode(detection)"]
Loading

File-Level Changes

Change Details Files
Add unified detection model and pipeline used by setup to scan skills, roles, and MCP servers across harnesses.
  • Define DetectedSource, DetectedItem, and DetectionResult types to model detection data in a harness-agnostic way.
  • Implement runDetection to collect skills, roles, and MCP servers per harness into a global item index, mark identical items via hashes, and compute auto-resolved vs reviewable items.
  • Introduce detectedEntry helper type and per-surface detection functions that feed data into the unified model.
cmd/dotagents/detect.go
Implement per-surface detection and content hashing for identity comparison and managed-item filtering.
  • Implement detectNativeSkills to scan harness skill roots, skip dot-prefixed entries, ignore non-directories and missing SKILL.md, filter out symlinks and directories resolving to canonical skills, and hash directory content via hashDir.
  • Implement detectNativeRoles to scan harness agent roots using harness metadata, filter non-role files and dotfiles, skip files managed by dotagents via isManagedAgentFile, normalize role names, and hash file content via hashBytes.
  • Implement detectNativeMCPServers to enumerate native MCP servers for supported harnesses, skip servers already configured in dotagents.yaml, read MCP configs, and hash their identity via hashMCPServer.
  • Add markIdentical to flag items whose source hashes all match, treating single-source items as identical, and add helpers hashDir, hashBytes, hashMCPServer, and isSymlinkOrResolvesTo for deterministic hashing and symlink/canonical resolution checks.
cmd/dotagents/detect.go
Wire detection into the setup command with a JSON output early-return path.
  • Extend runOptions with a JSONOutput boolean field and expose it via a --json CLI flag for dotagents setup.
  • Update runSetup to, when JSONOutput is set, invoke runDetection, pretty-print the resulting DetectionResult as JSON to stdout, and exit before the existing scanNativeImports/import flow.
cmd/dotagents/main.go
cmd/dotagents/setup.go
Add tests for hashing, identity marking, symlink filtering, and auto-resolution behavior.
  • Test hashDir determinism and sensitivity to content changes across directories.
  • Test markIdentical for single-source, all-matching, and differing-hash cases to ensure correct Identical flag behavior.
  • Test detectNativeSkills skips symlinked managed skills while still detecting real local skills.
  • Test runDetection auto-resolves identical skills across two harnesses and hides them from Items while incrementing AutoResolved.
  • Test isSymlinkOrResolvesTo behavior for symlink vs non-symlink paths.
cmd/dotagents/detect_test.go

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai 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.

Hey - I've found 4 issues, and left some high level feedback:

  • hashDir relies on filepath.WalkDir’s traversal order, which is not guaranteed to be consistent across filesystems or runs; consider collecting paths, sorting them, and then hashing in that deterministic order to make the directory hash truly stable.
  • markIdentical currently treats items with a single source as Identical and therefore auto-resolved, which may be surprising given the intent of “identical across all harnesses”; consider only marking items as identical when they appear in multiple harnesses with matching hashes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- hashDir relies on filepath.WalkDir’s traversal order, which is not guaranteed to be consistent across filesystems or runs; consider collecting paths, sorting them, and then hashing in that deterministic order to make the directory hash truly stable.
- markIdentical currently treats items with a single source as Identical and therefore auto-resolved, which may be surprising given the intent of “identical across all harnesses”; consider only marking items as identical when they appear in multiple harnesses with matching hashes.

## Individual Comments

### Comment 1
<location path="cmd/dotagents/detect.go" line_range="236-237" />
<code_context>
+	return out, nil
+}
+
+func markIdentical(item *DetectedItem) {
+	if len(item.Sources) < 2 {
+		item.Identical = true
+		return
</code_context>
<issue_to_address>
**issue (bug_risk):** Single-source items are treated as `Identical` and will be auto-resolved, which likely hides genuinely unique detections.

Because `markIdentical` sets `Identical = true` when `len(item.Sources) < 2`, any skill/role/MCP present in exactly one harness is never surfaced in `result.Items`. This contradicts the docstring, which implies only items from multiple sources that truly match should be auto-resolved. Suggest only marking items identical when `len(item.Sources) >= 2` and all hashes match, and keeping single-source items non-identical (or handling them in a dedicated branch).
</issue_to_address>

### Comment 2
<location path="cmd/dotagents/detect.go" line_range="143-144" />
<code_context>
+	Hash string
+}
+
+func detectNativeSkills(agent agentConfig, skillRoot string, canonicalSkills string) ([]detectedEntry, error) {
+	entries, err := os.ReadDir(skillRoot)
+	if errors.Is(err, fs.ErrNotExist) {
+		return nil, nil
</code_context>
<issue_to_address>
**issue (bug_risk):** Using an empty `skillRoot` will walk the process working directory, which is likely unintended.

If `agent.SkillRoot` is unset or resolves to `""`, `os.ReadDir(skillRoot)` will read the current working directory, potentially treating unrelated directories as skills. Consider mirroring `detectNativeRoles` and returning early when `skillRoot == ""` to avoid accidental CWD scanning.
</issue_to_address>

### Comment 3
<location path="cmd/dotagents/detect_test.go" line_range="45-46" />
<code_context>
+	if err := os.WriteFile(filepath.Join(dir2, "a.txt"), []byte("world"), 0o644); err != nil {
+		t.Fatal(err)
+	}
+	h1, _ := hashDir(dir1)
+	h2, _ := hashDir(dir2)
+	if h1 == h2 {
+		t.Fatal("different content produced the same hash")
</code_context>
<issue_to_address>
**issue (testing):** Assert that hashDir returns no error instead of discarding it

By ignoring the `hashDir` errors, this test can pass even if hashing fails. Capture the errors and fail the test if either call returns a non-nil error before comparing the hash values.
</issue_to_address>

### Comment 4
<location path="cmd/dotagents/detect_test.go" line_range="52" />
<code_context>
+	}
+}
+
+func TestMarkIdenticalSingleSource(t *testing.T) {
+	item := &DetectedItem{
+		Sources: []DetectedSource{{Hash: "abc123"}},
</code_context>
<issue_to_address>
**suggestion (testing):** Cover the zero-sources case for markIdentical to clarify intended behavior

There are tests for single- and multi-source cases, but none for when `item.Sources` is empty. Since `markIdentical` currently treats `len(Sources) < 2` as identical (making an empty item `Identical == true`), please add a test that covers this case—either to document the intended behavior or to reveal if the implementation should be changed.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread cmd/dotagents/detect.go
Comment thread cmd/dotagents/detect.go
Comment thread cmd/dotagents/detect_test.go Outdated
Comment thread cmd/dotagents/detect_test.go

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebf77d1959

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/dotagents/setup.go
Comment thread cmd/dotagents/detect.go

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c74c8464f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/dotagents/detect.go
@yourconscience
yourconscience merged commit 639249f into main Jul 18, 2026
4 checks passed
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.

1 participant