Skip to content

feat(003): Discover & Acquire — search + remote add + index (manifest→frontmatter)#8

Merged
so0k merged 17 commits into
mainfrom
003-search-remote
May 31, 2026
Merged

feat(003): Discover & Acquire — search + remote add + index (manifest→frontmatter)#8
so0k merged 17 commits into
mainfrom
003-search-remote

Conversation

@so0k
Copy link
Copy Markdown
Contributor

@so0k so0k commented May 31, 2026

What

The first end-to-end consumer loop — init → search → add → verify — plus the origin-side index generator that keeps discovery honest. Merges roadmap 003 (search) + 004 (remote add).

  • search [QUERY] [--topic …] — query-first (token-AND substring over name/description/topics, deterministic order), reads the origin's index.json (fetched per call for a remote origin).
  • remote add <skill> [--pin <ref>] — fetches the skill subtree from a GitHub origin (sparse git clone, token via os.exec, no local checkout) with reproducible immutable pins; gates the convention version; writes commit+treeSha+resolved version.
  • index — origin-side generator producing the catalog from each skill's SKILL.md frontmatter.
  • Manifest migration (commit 1): skills move from a sibling skill.toml to SKILL.md agentskills.io frontmatter + metadata.x-skillrig.* (gopkg.in/yaml.v3). skill.toml dropped.

Process (SpecLedger, fully exercised)

Specify → Clarify (5 research spikes: manifest format, catalog lifecycle, auth/token, remote-git testing, search/index) → Plan → Verify-workflow (2 reviewers → 14 findings, all remediated) → Implement-workflow → Checkpoint → adversarial review (caught a green-but-hollow remote keystone: 10 skipped tests, no remote search, no file:// seam) → Remediation (hard no-skip gate) → cold re-review ("real, not theater" — 0 CRITICAL/HIGH) → F1/F2/F3 closure.

Design artifacts, spikes, and the full review trail live under specledger/003-search-remote/ (spec, spec-tech, plan, research/, data-model, contracts/, quickstart, reviews/003-review.md, sessions/…-checkpoint.md).

Testing evidence

  • make check: golangci-lint 0 issues, all tiers pass.
  • go test -count=1 ./...: pass; all 11 remote TestQuickstart_* RUN+PASS, 0 skipped acceptance scenarios (only 2 git-on-PATH guards).
  • Remote tests run against a real file:// bare-repo substrate (genuine git clone, RAW-git tree-SHA oracle, no circular oracle, no httptest).

Related / residual (non-blocking)

  • Partially addresses Deprecated Terminology review #7 (Deprecated Terminology review): scrubbed skill.tomlSKILL.md confusion in ARCHITECTURE/ROADMAP/CLAUDE.md (CLAUDE.md gains an explicit deprecation note). The constitution.md §III/§IX terminology touch-ups remain (governance-gated amendment; list recorded in ARCHITECTURE/ROADMAP).
  • Origin-template (skillrig/origin-template) frontmatter migration is committed locally (79d23f4), not yet pushed.
  • Constitution IX skill trigger-evals for the extended skillrig skill not yet run.

🤖 Generated with Claude Code

so0k and others added 15 commits May 30, 2026 22:07
Combine roadmap 003 (search) and 004 (remote add) into one consumer-side
MVP slice: discover a skill in the org library and vendor it straight from
the remote library, no local checkout required. Completes the
init -> search -> add -> verify loop.

- spec.md: user-facing contract (US1 discover, US2 remote acquire, US3
  reproducible --pin, US4 distinct/navigable failures), 24 FRs, 8 SCs,
  Assumptions A1-A6, edge cases. No transport/auth/git mechanics.
- spec-tech.md: technical companion (input to /plan) — the 002
  local-checkout seam being replaced, convention-version gate,
  fingerprint/pin semantics, failure taxonomy, network test tier, and the
  7 open decisions deferred to /clarify.
- checklists/requirements.md: quality gate, all items pass.

Co-evolution deliverables baked in: FR-023 reconcile the origin-template
catalog schema (currently drops tags); FR-024 update ROADMAP.md +
ARCHITECTURE-v0.md with the 003+004 merge and local-vs-remote seam.

Also adds .agents/commands/specledger.verify-workflow.md (workflow-based
cross-artifact verification command).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Routed 4 high-uncertainty areas to spikes (S1 manifest format, S2 catalog
lifecycle, S3 auth/token, S4 remote-git testing) and settled 2 decisions
from reviewer comments:

- Local-vs-remote (A1 SETTLED): the tool never caches a remote; origin is
  either a remote OWNER/REPO (fetched) or an explicit local path. Confirmed
  against 002 code (it overloaded OWNER/REPO as <consumerRepoRoot>/OWNER/REPO
  and ran git on a local working tree; no file://, no remote).
- Pin recording: lock records commit + treeSha + resolved human-readable
  version/tag (humans reason about versions; verify uses treeSha).

spec.md: added Clarifications/Session 2026-05-31 (6 Q->A), updated FR-008/011/013,
Key Entities, Assumptions (A1 settled, A4 pending S3). spec-tech.md: §8 rewritten
into firm decisions + spike backlog S1-S4; folded in skill.toml->frontmatter
history as S1's working hypothesis (drop skill.toml for agentskills.io frontmatter
+ x-skillrig.* metadata).

Resolved 8 reviewer comments; 12 left open as live spike trackers. Feature is
NOT plan-ready until S1-S4 close.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ex in scope

All four clarify-phase spikes complete (research/2026-05-31-*.md); findings
folded into spec-tech.md §8b and propagated to the user-facing spec. Two
outcomes expand scope:

- S1 (manifest): migrate to agentskills.io frontmatter + metadata.x-skillrig.*;
  drop skill.toml. requires lives under x-skillrig (NOT allowed-tools). Small,
  in-slice (commit 1 of 003). Adds gopkg.in/yaml.v3 — a divergence from the
  "no new dependencies" note, flagged for FR-024.
- S2 (catalog): skillrig index ships IN 003 (single-tip generator, full
  regenerate from HEAD, GC=YAGNI). Reverses the original consume-only lean —
  search is meaningless against a drifting hand-maintained catalog, and the
  generator is thin once S1's parser exists (AP-04 by construction).
- S3 (auth): os.exec token order GH_TOKEN > GITHUB_TOKEN > `gh auth token`;
  failure classes split by stderr (exit 128); inject via git -c http.extraHeader;
  GHE deferred. Corrects architecture §8b.2's mise precedence claim.
- S4 (testing): file:// bare repo for happy/integrity + existing commandContext
  stub seam for auth/unreachable/transient; no httptest. Add AuthError/
  UnreachableError typed in the fetch layer.

spec.md: added US5 (origin maintainer regenerates catalog), FR-025..028
(catalog generation), SC-009, A7/A8 (scope), updated FR-023/024, settled the
local-vs-remote edge case. All 20 reviewer comments resolved.

Feature is now PLAN-READY (/specledger.plan).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
/specledger.plan output, consuming the four completed spikes (no
re-investigation):

- plan.md: tech context (yaml.v3 accepted, shell git, no httptest),
  Constitution Check (all gates pass; §III httptest/skill.toml touch-ups
  flagged for FR-024), project structure (new pkg/skillcore/{fetch,catalog}.go
  + cli/{search,index}.go), 6-step build sequence, complexity tracking
  (yaml.v3 + index-in-consume-only, both justified).
- research.md: D1-D7 consolidated from spikes S1-S4 (Decision/Rationale/
  Alternatives) + prior work (001/002).
- data-model.md: SKILL.md frontmatter manifest (metadata.x-skillrig.*),
  single-tip catalog, lock entry (no schema change — Version already carries
  the resolved tag), typed errors (Auth/Unreachable/NotFound/IncompatibleConvention),
  origin form classification; ground-truth samples per boundary.
- contracts/: search.md (Query), add-remote.md (Vendor Mutation + --pin),
  index.md (origin-side generator).
- quickstart.md: US1-US5 -> TestQuickstart_* with output-shape asserts +
  the two ground-truth oracles (fetched treeSha == raw git; index == committed).
- CLAUDE.md: Active Technologies updated (yaml.v3).

Plan-complete; ready for /specledger.tasks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ending)

Reviewer flagged the tag/git-tag collision (skillrig uses git tags for
version pins, name-vSEMVER). Recorded in spec.md Clarifications:
- search is query-first: positional [QUERY] matches name+description;
  topic narrowing is a secondary filter.
- label concept renamed away from "tag" → metadata.x-skillrig.topics.
- filter flag name open (--topic vs -f/--filter); matching algorithm,
  git-friendly searchable-index storage, flag surface, and any indexing
  library being settled in Spike S5 (search-index-architecture). New
  indexing/search deps pre-approved.

Full artifact rename deferred to the S5 fold (one coherent pass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Search/index architecture settled (research/2026-05-31-search-index-architecture.md):

- Query-first: search [QUERY...] is case-insensitive token-AND substring over
  name+description+topics; deterministic order (relevance bucket then name);
  no fuzzy/semantic/TF-IDF (N6). --topic is a separate exact-string filter.
- tag→topic rename (--topic, topics[], metadata.x-skillrig.topics): agentskills.io
  defines no such field, GitHub "topics" reinforces it, removes the git-tag/
  version-pin collision. Flag --topic not --filter (one dimension, YAGNI).
- Flat index.json + in-memory filter is sufficient (index structures YAGNI
  below ~10k docs). STDLIB ONLY — no search dependency (sahilm/fuzzy is the
  post-v0 escape hatch if forgiving matching is ever wanted).

Swept across spec.md (US1, FR-002/002a, Topic entity, A3, US5 scenario),
data-model.md (manifest/catalog topics + new §5b search matcher), contracts/
search.md (query semantics + ordering), quickstart.md (query/ordering tests),
research.md (D8), spec-tech.md (S5 resolved + surface), plan.md. Reviewer
comment resolved. Historical S1/S2 spike narrative left as recorded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lls)

Folds the S5 agent's plan edits + S5 reference cleanup:
- step 5 (search) reworded to the S5 matcher: stdlib-only SearchCatalog
  (token-AND substring over name+description+topics, fixed-bucket score
  then name) + exact-string --topic filter.
- new step 6 "seed the origin with more skills" so search/--topic get real
  multi-entry TestQuickstart_* coverage: use `npx skills add --copy` (NOT
  `sl skill add` — errors outside a SpecLedger project, installs to
  .claude/skills/); commit only skills/<name>/, drop the ~25 dot-dir copies;
  enrich each SKILL.md with metadata.x-skillrig.* (else index emits no
  topics/version); regenerate via skillrig index.
- co-evolution renumbered 6→7; Input/structure refs updated to S1–S5.

Verified: both repos clean (agent tested in a temp dir, no stray artifacts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Avoids the embedded-string parse fragility hit while authoring the 003
verification (a /* glob, unescaped backtick/apostrophe, or mis-counted paren
in a long embedded prompt breaks the whole JS workflow script).

- Add .specledger/templates/review-report-template.md (the report format the
  merge agent fills — single source of truth, inspectable/editable on disk).
- Refactor .agents/commands/specledger.verify-workflow.md: the workflow script
  is now minimal — each reviewer reads an on-disk FEATURE_DIR/reviews/
  _reviewer-brief.md (authored per-run, carries the SKILLS line + focus areas);
  the merge agent reads the report template. New execution step 4 authors the
  brief. Thunks built with an explicit for-loop (clearer paren balance than the
  nested parallel(Array.from(...)) one-liner).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
/specledger.verify-workflow (2 Opus reviewers + merge): 0 CRITICAL, 1 HIGH,
5 MEDIUM, 6 LOW, 2 INFO; 5 coverage gaps. Report saved to reviews/003-review.md;
all findings remediated (C1 per the exact-match ==1 decision; "fix all now").

- C1 (HIGH): convention-version gate = exact-match ==1 (lower/absent now FAIL,
  not silently pass). data-model §2/§5, search.md step3, spec-tech.md:51 +
  TestQuickstart_SearchConventionBoundary.
- C2: distinct typed NoSuchVersionError (not a NotFoundError message variant);
  test asserts the discriminator.
- C3: deterministic --pin rule (bare semver→tag_scheme expand; else literal
  ref/SHA) + AddPinTagFormEquivalent test.
- C4: tag→topic stragglers (spec-tech:33,102; index.md:42; research:13).
- C5/C6/C8/C9: added AddHelpExamples, AddDryRun, IndexNotInOrigin,
  IndexMissingVersion quickstart scenarios (close the 5 coverage gaps).
- C7: index reads skillrigConvention from .skillrig-origin.toml (not hardcoded).
- C10: matcher name unified on Search(); C11: data-model D1–D8; C12: US1/US2
  traceability FRs; C13: search.md help header; C14: plan enumerates the
  constitution §III/§IX touch-ups for the FR-024 sweep.

Gate: go build ./... clean; every prior coverage gap now has a TestQuickstart_*.
Scaffolding (_reviewer-brief/_report-template) removed. Clear for implement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implemented via /specledger.implement-workflow (11-agent pipeline, gated on
make check; the experiment skips the sl issue ledger). make check green:
golangci-lint 0 issues; all tiers pass uncached (integration 3.27s); 60
TestQuickstart_* scenarios.

Manifest migration (commit-1 of the slice):
- pkg/skillcore/manifest.go: SKILL.md YAML frontmatter via gopkg.in/yaml.v3
  (drops skill.toml); metadata.x-skillrig.* (topics, version, namespace,
  convention-version, requires). Fixtures migrated; skill.toml deleted.

skillcore (single impl, AP-04):
- catalog.go: Catalog/ParseCatalog/GenerateCatalog (reads convention from
  .skillrig-origin.toml, C7), CheckConvention exact-match ==1 (C1), stdlib
  deterministic Search (token-AND substring + bucket+name order, S5/D8).
- fetch.go: remote fetch (git clone --sparse), stderr→typed errors.
- git.go: Clone/FetchSparse + ResolveGitHubToken (GH_TOKEN>GITHUB_TOKEN>
  gh auth token via os.exec; http.extraHeader injection — S3/D4).
- errors.go: AuthError/UnreachableError/NotFoundError/NoSuchVersionError(C2)/
  IncompatibleConventionError + ClassifyGitError.
- add.go: remote path + --pin resolution (semver→tag_scheme else literal, C3).

CLI (presentation-only): search.go (Query), index.go (generator), extended
add.go (remote + --pin + navigational error mapping); registered in root.go.

Docs/skill co-evolution (FR-023/024): cli.md (search/index/remote-add surface),
ROADMAP + ARCHITECTURE-v0 (003+004 merge, frontmatter+yaml.v3, on-merge catalog,
constitution touch-up list), skillrig skill references/{search,index}.md + add.md.
(Separate skillrig-origin repo migration remains, noted as the residual FR-023.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 CRITICAL / 0 HIGH. All 14 verify findings present in code+tests (spot-checked);
make check green, 60 TestQuickstart_* pass. 3 tracked items before merge:
FR-023 residual (skillrig-origin repo not yet frontmatter), Constitution IX skill
evals not run, constitution.md §III/§IX amendment (team-approval, list recorded).
…pable

Corrects the prior "0 CRITICAL" checkpoint. Cold-context Opus review found
3 CRITICAL + 1 HIGH (all verified): search never fetches a remote catalog
(C1); remote add untestable — cloneURL hardcodes github, originPattern rejects
file://, 10 remote tests t.Skip-ped, fetch path 0% (C2); --pin misclassifies
missing/private repo as NoSuchVersion (C3); remote add skips the convention
gate (H1); index.json/search --json emit PascalCase requires keys behind a
circular oracle (M1). Root cause: no file://-or-local-path origin seam.

Lesson: a test that exists != runs; grep t.Skip at checkpoint.
…LAUDE.md

Per review of docs/ + skill + CLAUDE.md after the 003 manifest migration:
- CLAUDE.md: explicit DEPRECATED note — skill metadata is SKILL.md frontmatter
  (agentskills.io + metadata.x-skillrig.*, yaml.v3); skill.toml removed; the
  [[requires]] TOML notation now means metadata.x-skillrig.requires; go-toml
  retained only for .skillrig config TOML.
- ARCHITECTURE-v0.md: lint scores SKILL.md frontmatter (not skill.toml validity);
  OpenClaw nugget + open-Q11 reworded to the frontmatter manifest; §4.1 gains a
  [[requires]]→metadata.x-skillrig.requires notation note.
Remaining skill.toml mentions are deliberate deprecation context (dropped/migrated).
ROADMAP/cli.md/README/skill files already used frontmatter.
…+ tested

Focused remediation workflow (4 phases, HARD gate: no skipped acceptance tests;
10 remote scenarios MUST run+pass). Independently verified: make check green,
go test -count=1 all pass, 11 remote TestQuickstart_* RUN+PASS, 0 skipped
acceptance scenarios, fresh `skillrig index` emits lowercase + unescaped requires.

- FIX-1 (root): config.Origin gains a LOCAL form (Path + IsLocal()) accepting
  file:// + filesystem-path origins; pkg/skillcore cloneURL derives the transport
  from the form. Delivers FR-011 local-path mode AND unblocks the S4 file://
  bare-repo test substrate.
- C1: search.go fetches index.json remotely per call (skillcore.FetchCatalog),
  not os.ReadFile of a local checkout.
- C3/M2: classifyFetchError only returns NoSuchVersionError on a failed --pin ref
  checkout (repo+skill exist), distinct from missing/private repo.
- H1: acquireRemote gates skillrigConvention (gateRemoteConvention) before vendoring.
- M1: Require gains json tags; catalog marshals with SetEscapeHTML(false) (>= no
  longer >=); committed index.json fixture regenerated lowercase+unescaped;
  IndexMatchesCommitted de-circularized (asserts lowercase keys + unescaped >=).
- L1/L2: commit-SHA pin fetch; Origin populated on Auth/Unreachable.
- Un-skipped + wired all 10 remote scenarios to a real file:// bare-repo substrate
  with the RAW-git treeSha oracle; new fetch_test.go + resolvePin/classify coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cold re-review verdict: the remote keystone is genuinely built + honestly
tested (file:// substrate is a real bare-repo clone, raw-git oracle, no
circular dependency). 4 findings, 0 CRITICAL/HIGH; F1/F2/F3 closed, F4
documented as a conscious won't-fix.

- F1 (MEDIUM): TestQuickstart_AddRemoteConventionMismatch — a convention-2
  file:// origin makes remote `add` exit 1 (IncompatibleConvention) writing
  nothing; pins gateRemoteConvention (H1) end-to-end. + newRemoteOriginConvention helper.
- F2 (MEDIUM, security): TestAuthConfigArgs (base64 x-access-token header
  format) + TestClone_TokenInjectionArgvOrder (the -c http.extraHeader global
  flag precedes `clone`; token never in the URL). New pkg/skillcore/auth_test.go.
- F3 (LOW): ClassifyGitError now maps local-git stderr ("Could not read from
  remote repository", "does not appear to be a git repository") to
  UnreachableError, so a missing/unreachable file:// origin renders the distinct
  "could not reach" message. + TestClassifyGitError_LocalUnreachable.
- F4: accepted/won't-fix (asymmetric convention gating on the 002 local-checkout
  add path; consistent with 002, operator-controlled, FR-006 remote path IS gated).

Gate: make check 0 lint; go test -count=1 all pass; new tests run+pass; only the
two git-on-PATH t.Skip guards remain. Session log updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 31, 2026

Review Summary by Qodo

(Agentic_describe updated until commit c3e95c7)

Discover & Acquire — search + remote add + index (manifest→frontmatter)

✨ Enhancement 🧪 Tests 📝 Documentation

Grey Divider

Walkthroughs

Description
  **End-to-end consumer loop implementation: init → search → add → verify**
• **Search command** (skillrig search [QUERY] [--topic …]): Query-first discovery with token-AND
  substring matching over skill name/description/topics, deterministic ordering, reads remote
  index.json per call
• **Remote add with pinning** (skillrig add  [--pin ]): Fetches skill subtrees from GitHub origins
  via sparse git clone with token authentication, reproducible immutable pins (bare semver expansion
  or literal refs), convention version gating
• **Index generator** (skillrig index): Origin-side catalog production from SKILL.md
  frontmatter, deterministic output for discovery
• **Manifest migration**: Skills move from skill.toml to SKILL.md agentskills.io frontmatter
  with metadata.x-skillrig.* namespacing (YAML via gopkg.in/yaml.v3)
• **Local origin support**: File-based origins with file:// URLs and path normalization for
  testing and local workflows
• **Typed error classification**: AuthError, UnreachableError, NotFoundError,
  NoSuchVersionError, IncompatibleConventionError with origin identity and auth-flag population
• **Remote git transport**: Credential injection via environment (not argv), sparse no-checkout
  clones, token resolution from GH_TOKEN/GITHUB_TOKEN/gh auth token
• **Comprehensive test coverage**: 1546-line integration suite (11 remote TestQuickstart_*
  scenarios, 0 skipped), 691-line unit tests, golden fixture validation, determinism checks, injected
  git failure scenarios
• **Documentation**: Architecture updates for frontmatter format, CLI design patterns, feature
  specification with 28 functional requirements and 5 research spikes
Diagram
flowchart LR
  A["Consumer: search<br/>Query origin catalog"] -->|"token-AND<br/>deterministic"| B["Catalog<br/>index.json"]
  B -->|"fetch remote<br/>or local"| C["Origin<br/>SKILL.md files"]
  D["Consumer: add --pin"] -->|"resolve pin<br/>gate convention"| E["Remote fetch<br/>sparse clone"]
  E -->|"GitHub token<br/>env injection"| F["Vendored skill<br/>tree-SHA + commit"]
  G["Origin: index"] -->|"walk skills<br/>parse frontmatter"| C
  G -->|"deterministic<br/>output"| B
  H["Manifest migration"] -->|"TOML → YAML<br/>frontmatter"| C

Loading

Grey Divider

File Changes

1. test/searchindex_quickstart_test.go 🧪 Tests +1546/-0

Integration tests for search, index, and remote add features

• Adds comprehensive integration test suite for search, index, and remote add features with 1546
 lines of test scenarios
• Implements search/index fixture helpers (catalogSkill, catalogFile, searchConsumer,
 bootstrapOriginRepo, writeSkillMD)
• Tests search functionality: listing, query matching, ordering determinism, topic filtering,
 convention gates, and JSON output
• Tests index generation: catalog production, determinism, golden fixture matching, frontmatter
 validation, and origin repo requirements
• Tests remote add with file:// substrate: reproducible pins, dry-run, idempotency, divergence
 handling, and injected git failures (auth/unreachable/not-found)
• Validates convention gates, version resolution, and end-to-end search against remote origins

test/searchindex_quickstart_test.go


2. pkg/skillcore/catalog_test.go 🧪 Tests +691/-0

Unit tests for catalog, search, and error classification

• Adds 691 lines of unit tests for catalog generation, search, convention checking, and git error
 classification
• Tests GenerateCatalog against golden fixture with byte-identical output and determinism validation
• Tests Search ordering by relevance buckets (exact-name > name-substring > topic > description),
 lexicographic tiebreaks, token-AND queries, and topic filtering
• Tests CheckConvention exact-match boundary (only convention 1 passes; 0, 2, and absent all fail)
• Tests ClassifyGitError stderr-to-typed-error mapping for auth/unreachable/not-found classes with
 raw error unwrapping
• Tests ResolveGitHubToken precedence (GH_TOKEN > GITHUB_TOKEN > gh auth token) with gh binary
 stubbing
• Tests ParseManifest metadata.x-skillrig.* key lifting (namespace, version, topics, requires)

pkg/skillcore/catalog_test.go


3. pkg/skillcore/add.go ✨ Enhancement +243/-33

Remote-fetch form and pin resolution for add command

• Extends AddOptions with remote-fetch form: Owner, Repo, RepoURL, Local, SkillPath, Pin fields for
 GitHub origin support
• Adds isRemote() and cloneURL() methods to AddOptions for form selection and git transport URL
 derivation
• Introduces acquired struct to unify local-path and remote-fetch source acquisition with tree-SHA,
 commit, version, and cleanup
• Refactors Add() to use acquireSource() dispatcher, supporting both local checkout (002 behavior)
 and remote git fetch (003 feature)
• Implements acquireLocal() for existing local-path form and acquireRemote() for new remote-fetch
 with convention gating
• Adds gateRemoteConvention() to enforce exact-match convention check before any remote subtree is
 fetched or vendored
• Implements resolvePin() with deterministic --pin rule: bare semver expansion via name-vSEMVER tag
 scheme, literal refs/SHAs pass through
• Changes manifest source from skill.toml to SKILL.md (frontmatter-based)

pkg/skillcore/add.go


View more (60)
4. internal/config/origin.go ✨ Enhancement +111/-16

Local origin support with file:// URLs and path normalization

• Extends Origin struct with Path field to support LOCAL form (filesystem path or file:// URL)
 alongside REMOTE OWNER/REPO form
• Adds IsLocal() method to discriminate between LOCAL and REMOTE origin forms
• Adds CloneURL() method to render git transport target: file:// for LOCAL,
 https://github.com/OWNER/REPO.git for REMOTE
• Updates String() to render LOCAL origins as Path verbatim, REMOTE as OWNER/REPO[@REF]
• Extends ParseOrigin() to classify input into LOCAL or REMOTE form with isLocalForm() and
 normalizeLocalPath() helpers
• Implements normalizeLocalPath() to canonicalize file:// URLs and expand ~/ prefixes against $HOME,
 making relative paths absolute
• Adds isLocalForm() to detect path markers (file://, /, ./, ../, ~/, ~) that select LOCAL form
 unambiguously

internal/config/origin.go


5. internal/cli/addverify_test.go 🐞 Bug fix +1/-1

Update add error mapping test signature

• Updates mapAddError() call signature to include origin parameter for error context in add command
 error handling

internal/cli/addverify_test.go


6. internal/cli/root.go ✨ Enhancement +2/-0

Register search and index subcommands

• Registers newSearchCmd() and newIndexCmd() subcommands in registerSubcommands()
• Adds search and index commands to the CLI command tree alongside existing init, add, and verify
 commands

internal/cli/root.go


7. pkg/skillcore/fetch_test.go 🧪 Tests +404/-0

Fetch and pin resolution test coverage

• Comprehensive test suite for pin resolution logic (TestResolvePin), validating bare semver
 expansion and full tag literal handling
• Tests for fetch error classification (TestClassifyFetchError) ensuring clone-phase failures
 never become version errors
• Tests for local unreachable origins (TestClassifyGitError_LocalUnreachable) covering file:// and
 path-based origins
• Validates that error classification populates origin identity and authentication flags for CLI
 navigation

pkg/skillcore/fetch_test.go


8. internal/cli/add.go ✨ Enhancement +186/-31

Remote skill acquisition with pin support

• Added --pin flag to acquire immutable versions (bare semver or literal git ref)
• Refactored origin acquisition logic into addOptionsFor() to classify and handle local checkout
 vs. remote fetch forms
• Added isLocalCheckout() helper to detect local origin checkouts on disk
• Extended error mapping with remote-specific errors (NotFoundError, AuthError,
 UnreachableError, IncompatibleConventionError)
• Added shared error rendering functions (mapNotFoundError, mapAuthError, mapUnreachableError,
 mapConventionError)

internal/cli/add.go


9. pkg/skillcore/git.go ✨ Enhancement +304/-1

Remote git transport with credential injection

• Added runEnv() method to inject GitHub credentials via GIT_CONFIG_* environment variables
 (kept out of argv)
• Implemented Clone() for sparse, no-checkout git clones with token authentication
• Implemented FetchSparse() and fetchSparseInto() for skill subtree checkout with phase-aware
 error tagging
• Implemented FetchFile() for catalog fetching without materializing a working tree
• Added ResolveGitHubToken() and ghAuthToken() to resolve credentials from GH_TOKEN,
 GITHUB_TOKEN, or gh auth token
• Added authConfigEnv() to safely inject credentials via environment (research D4)

pkg/skillcore/git.go


10. pkg/skillcore/catalog.go ✨ Enhancement +389/-0

Origin catalog generation and search

• New file implementing catalog generation and search: GenerateCatalog() walks origin skills and
 produces index.json
• Implemented FetchCatalog() to fetch and parse origin's index.json with error classification
• Implemented Search() with deterministic token-AND matching over name/description/topics and
 relevance-bucket ordering
• Added CheckConvention() for exact-match convention version gating (C1)
• Implemented manifest parsing integration via ParseManifest() and catalog entry projection

pkg/skillcore/catalog.go


11. internal/cli/search.go ✨ Enhancement +289/-0

Skill discovery search command

• New command implementing skillrig search [QUERY...] for discovering skills from configured
 origin
• Resolves origin and loads catalog via local checkout or remote fetch (FIX-2, FIX-7)
• Implements deterministic search with token-AND query matching and topic filtering
• Maps skillcore errors to navigational UsageError values with what/why/fix prose
• Handles convention version gating and catalog read/parse failures distinctly

internal/cli/search.go


12. pkg/skillcore/fetch.go ✨ Enhancement +202/-0
 Remote skill fetch with error classification

pkg/skillcore/fetch.go


13. pkg/skillcore/manifest.go ✨ Enhancement +163/-21

Manifest migration to SKILL.md frontmatter

• Migrated from TOML (skill.toml) to YAML frontmatter in SKILL.md files
• Implemented extractFrontmatter() to parse YAML frontmatter between --- fences
• Refactored manifest parsing to lift namespaced metadata.x-skillrig.* keys into Manifest struct
• Added validateManifest() to enforce name == directory and version presence contracts
• Added helpers (metaString, metaStrings, metaRequires, mapString) for safe metadata
 extraction
• Updated Require struct with JSON tags for catalog serialization (FIX-5)

pkg/skillcore/manifest.go


14. internal/cli/index.go ✨ Enhancement +164/-0

Origin catalog generation command

• New command implementing skillrig index for origin-side catalog generation
• Calls skillcore.GenerateCatalog() to walk skills and produce deterministic index.json
• Validates origin repo presence and handles write failures with navigational errors
• Renders summary with skill count and convention version from parsed catalog
• Supports --out flag to write catalog to custom path

internal/cli/index.go


15. pkg/skillcore/manifest_test.go 🧪 Tests +106/-24

Manifest parsing tests for YAML frontmatter

• Updated tests to use YAML frontmatter format instead of TOML
• Added writeSkillMd() helper to write SKILL.md files with proper directory structure
• Extended error cases to cover missing frontmatter, malformed YAML, name/directory mismatch, and
 missing version
• Refactored test data to include namespaced metadata.x-skillrig.* fields and nested requires

pkg/skillcore/manifest_test.go


16. pkg/skillcore/errors.go Error handling +164/-0

Typed error classes for remote fetch failures

• Added AuthError for authentication failures (credential rejected)
• Added UnreachableError for network/connectivity failures
• Added NotFoundError for missing origin/skill with unauthenticated flag (D4)
• Added NoSuchVersionError for missing pinned version (C2, distinct from missing skill)
• Added IncompatibleConventionError for convention version mismatch (C1)
• Implemented ClassifyGitError() to map git stderr to typed errors with local origin support (F3)
• Added helpers (isRepoNotFound, containsAny) for stderr pattern matching

pkg/skillcore/errors.go


17. pkg/skillcore/auth_test.go 🧪 Tests +125/-0

Token injection security tests

• Tests for authConfigEnv() validating empty token yields no env, non-empty yields GIT_CONFIG
 triple
• Tests for Clone() token injection via environment (F2), ensuring credential never appears in
 argv
• Added captureCommandContext() helper to inspect git invocations and their environment
• Validates security invariant that base64 credential lives only in GIT_CONFIG_VALUE_0, not argv

pkg/skillcore/auth_test.go


18. pkg/skillcore/helpers_test.go 🧪 Tests +23/-1

Test helper update for YAML frontmatter

• Updated sampleSkillMd to use YAML frontmatter format with namespaced metadata.x-skillrig.*
 fields
• Added representative skill metadata including namespace, version, convention, topics, and requires

pkg/skillcore/helpers_test.go


19. internal/config/origin_test.go 🧪 Tests +22/-1

Support local-form origins in origin parsing tests

• Added wantPathSuffix field to test cases to support local-form origin testing (absolute paths
 and file:// URLs)
• Updated test logic to validate local origins have empty Owner/Repo and matching path suffix
 via IsLocal() method
• Removed "missing owner" error case (/my-skills) and replaced it with two new local-form test
 cases
• Added validation that local forms are correctly identified and absolute paths are no longer
 treated as errors

internal/config/origin_test.go


20. internal/cli/output.go ✨ Enhancement +99/-0

Add search and index result rendering functions

• Added searchResultJSON struct and renderSearchResult() function to format search results in
 both human-readable and JSON output modes
• Added searchEmptyFooter constant and truncateDesc() helper for compact human output (80-char
 truncation)
• Added indexResult struct and renderIndexResult() function to format index generation results
• Added indexFooterHint constant for next-step guidance in index output

internal/cli/output.go


21. pkg/skillcore/add_test.go 🧪 Tests +10/-10

Update idempotency test for manifest name contract

• Renamed test from TestAdd_IdempotentWhenManifestNameDiffersFromDir to
 TestAdd_IdempotentByManifestName to reflect post-migration contract
• Updated test fixture to use matching directory and manifest name (terraform-plan-review) per new
 parse contract
• Simplified test comments to remove references to name/directory drift, which is no longer allowed
 after manifest migration

pkg/skillcore/add_test.go


22. test/skillcore_quickstart_test.go 🧪 Tests +3/-2

Update quickstart test for SKILL.md manifest migration

• Updated sampleVersion comment to reference SKILL.md frontmatter
 (metadata.x-skillrig.version) instead of skill.toml
• Removed skill.toml from the list of files checked in assertVendoredMatchesOrigin() function
• Reflects migration from separate manifest file to single SKILL.md frontmatter

test/skillcore_quickstart_test.go


23. .agents/skills/qodo-manage-rules/scripts/qodo_rules.py ✨ Enhancement +326/-0

Add Qodo rules management CLI script

• New Python script for managing Qodo coding rules via API (list, get, search, find, load,
 set-state, update)
• Implements read operations (unrestricted) and write operations (default dry-run with --apply
 flag)
• Handles token resolution from $QODO_API_KEY env or ~/.qodo/auth.key file
• Supports semantic search, literal substring matching, and filtering by scope; includes
 full-document PUT read-modify-write pattern

.agents/skills/qodo-manage-rules/scripts/qodo_rules.py


24. docs/ARCHITECTURE-v0.md 📝 Documentation +68/-42

Migrate architecture docs to SKILL.md frontmatter and add index generator

• Updated skill manifest documentation to reflect migration from skill.toml to SKILL.md
 frontmatter with metadata.x-skillrig.* namespacing
• Added skillrig index command to the command table as origin-side catalog generator
• Updated CLI surface description to clarify consumer-side commands and origin-side index
 generator (CI-run, local-filesystem only)
• Corrected documentation on skillrig lint to reference SKILL.md frontmatter instead of
 skill.toml; updated origin template description and catalog generation details
• Added detailed 4.1 section on frontmatter format with YAML examples, rationale for the migration,
 and dependency justification (gopkg.in/yaml.v3)
• Expanded section 9 on discovery/index generation with single-tip, full-regenerate semantics and
 why index ships in-repo
• Added section 9a documenting co-evolution deliverables (FR-023, FR-024) and constitution touch-ups
• Corrected mise token-resolution precedence and added clarification on skillrig's own token
 resolution via os.exec
• Updated references to skill.toml throughout to SKILL.md frontmatter or metadata.x-skillrig.*
 fields

docs/ARCHITECTURE-v0.md


25. specledger/003-search-remote/spec.md 📝 Documentation +234/-0

Add feature specification for search and remote add

• New feature specification for "Discover & Acquire Skills" combining roadmap 003 (search) and 004
 (remote add)
• Defines user scenarios for discovery, remote vendoring, pinned versions, failure modes, and
 catalog generation
• Documents five acceptance scenarios per user story with priority levels (P1/P2)
• Specifies 28 functional requirements (FR-001 through FR-028) covering search, remote add, pinning,
 trust, and catalog generation
• Records assumptions (A1–A8) and success criteria (SC-001 through SC-009) with measurable outcomes
• Includes clarifications from 2026-05-31 session resolving manifest format, catalog lifecycle,
 auth, and testing approaches

specledger/003-search-remote/spec.md


26. docs/design/cli.md 📝 Documentation +77/-22

Document search, remote add, index, and error classification

• Updated search command status to [implemented] and added index command as origin-side
 generator
• Added --pin  flag to add command examples and usage documentation
• Documented three distinct remote-fetch failure classes (AuthError, UnreachableError,
 NotFoundError) with example error messages
• Added IncompatibleConventionError and NoSuchVersionError as distinct error types for
 convention mismatch and missing versions
• Updated search output examples to use --topic flag (renamed from --tag) and clarified
 query-first semantics (token-AND substring matching)
• Documented --pin and --topic as command-specific flags with consistent meaning across commands
• Expanded "Pin vs. branch ref" section explaining two-step resolution (semver expansion via
 tag_scheme, literal git ref fallback)
• Updated command patterns table to reflect local-path and remote OWNER/REPO origin classification
 for add
• Added origin-side index generator as non-consumer pattern; clarified offline/network/auth-aware
 constraints for each command
• Updated AP-04 anti-pattern to include parallel fetch/catalog/search implementations as violations
• Clarified execution layer primitives to include frontmatter parse, fetch, catalog, and search
 matcher in skillcore

docs/design/cli.md


27. go.mod Dependencies +1/-0

Add yaml.v3 dependency for frontmatter parsing

• Added gopkg.in/yaml.v3 v3.0.1 as a new dependency for YAML frontmatter parsing
• Supports the migration from skill.toml to SKILL.md frontmatter with standard agentskills.io
 format

go.mod


28. .agents/commands/specledger.verify-workflow.md Additional files +107/-0

...

.agents/commands/specledger.verify-workflow.md


29. .agents/skills/qodo-manage-rules/README.md Additional files +75/-0

...

.agents/skills/qodo-manage-rules/README.md


30. .agents/skills/qodo-manage-rules/SKILL.md Additional files +119/-0

...

.agents/skills/qodo-manage-rules/SKILL.md


31. .agents/skills/qodo-manage-rules/evals/trigger-eval-set.json Additional files +23/-0

...

.agents/skills/qodo-manage-rules/evals/trigger-eval-set.json


32. .agents/skills/qodo-manage-rules/references/api-contract.md Additional files +86/-0

...

.agents/skills/qodo-manage-rules/references/api-contract.md


33. .agents/skills/qodo-manage-rules/references/loading-rules.md Additional files +77/-0

...

.agents/skills/qodo-manage-rules/references/loading-rules.md


34. .agents/skills/qodo-manage-rules/references/managing-derived-rules.md Additional files +61/-0

...

.agents/skills/qodo-manage-rules/references/managing-derived-rules.md


35. .agents/skills/skillrig/SKILL.md Additional files +46/-33

...

.agents/skills/skillrig/SKILL.md


36. .agents/skills/skillrig/references/add.md Additional files +33/-17

...

.agents/skills/skillrig/references/add.md


37. .agents/skills/skillrig/references/index.md Additional files +63/-0

...

.agents/skills/skillrig/references/index.md


38. .agents/skills/skillrig/references/search.md Additional files +73/-0

...

.agents/skills/skillrig/references/search.md


39. .agents/skills/skillrig/references/verify.md Additional files +3/-3

...

.agents/skills/skillrig/references/verify.md


40. .specledger/memory/constitution.md Additional files +21/-8

...

.specledger/memory/constitution.md


41. .specledger/templates/review-report-template.md Additional files +35/-0

...

.specledger/templates/review-report-template.md


42. CLAUDE.md Additional files +7/-6

...

CLAUDE.md


43. docs/ROADMAP.md Additional files +12/-8

...

docs/ROADMAP.md


44. go.sum Additional files +3/-0

...

go.sum


45. specledger/003-search-remote/checklists/requirements.md Additional files +36/-0

...

specledger/003-search-remote/checklists/requirements.md


46. specledger/003-search-remote/contracts/add-remote.md Additional files +45/-0

...

specledger/003-search-remote/contracts/add-remote.md


47. specledger/003-search-remote/contracts/index.md Additional files +42/-0

...

specledger/003-search-remote/contracts/index.md


48. specledger/003-search-remote/contracts/search.md Additional files +45/-0

...

specledger/003-search-remote/contracts/search.md


49. specledger/003-search-remote/data-model.md Additional files +170/-0

...

specledger/003-search-remote/data-model.md


50. specledger/003-search-remote/plan.md Additional files +104/-0

...

specledger/003-search-remote/plan.md


51. specledger/003-search-remote/quickstart.md Additional files +71/-0

...

specledger/003-search-remote/quickstart.md


52. specledger/003-search-remote/research.md Additional files +86/-0

...

specledger/003-search-remote/research.md


53. specledger/003-search-remote/research/2026-05-31-auth-token-resolution.md Additional files +255/-0

...

specledger/003-search-remote/research/2026-05-31-auth-token-resolution.md


54. specledger/003-search-remote/research/2026-05-31-catalog-generation-lifecycle.md Additional files +172/-0

...

specledger/003-search-remote/research/2026-05-31-catalog-generation-lifecycle.md


55. specledger/003-search-remote/research/2026-05-31-remote-git-testing.md Additional files +244/-0

...

specledger/003-search-remote/research/2026-05-31-remote-git-testing.md


56. specledger/003-search-remote/research/2026-05-31-search-index-architecture.md Additional files +154/-0

...

specledger/003-search-remote/research/2026-05-31-search-index-architecture.md


57. specledger/003-search-remote/research/2026-05-31-skill-manifest-format.md Additional files +145/-0

...

specledger/003-search-remote/research/2026-05-31-skill-manifest-format.md


58. specledger/003-search-remote/reviews/003-review.md Additional files +91/-0

...

specledger/003-search-remote/reviews/003-review.md


59. specledger/003-search-remote/sessions/003-search-remote-checkpoint.md Additional files +121/-0

...

specledger/003-search-remote/sessions/003-search-remote-checkpoint.md


60. specledger/003-search-remote/spec-tech.md Additional files +108/-0

...

specledger/003-search-remote/spec-tech.md


61. test/testdata/sample-origin/index.json Additional files +32/-0

...

test/testdata/sample-origin/index.json


62. test/testdata/sample-origin/skills/terraform-plan-review/SKILL.md Additional files +14/-0

...

test/testdata/sample-origin/skills/terraform-plan-review/SKILL.md


63. test/testdata/sample-origin/skills/terraform-plan-review/skill.toml Additional files +0/-23

...

test/testdata/sample-origin/skills/terraform-plan-review/skill.toml


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 31, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (5) 📎 Requirement gaps (0)

Context used
✅ Compliance rules (platform): 148 rules

Grey Divider


Action required

1. Hardcoded page size stop 🐞 Bug ≡ Correctness ⭐ New
Description
cmd_find terminates pagination using page * 50 >= total, assuming the API returns exactly 50
rules per page; if the page size differs, find can stop early and silently miss matching rules.
This makes find produce incomplete results while list paginates based on observed counts.
Code

.agents/skills/qodo-manage-rules/scripts/qodo_rules.py[R140-150]

Evidence
cmd_list paginates based on len(rules) >= totalCount, but cmd_find uses a fixed page * 50
heuristic, which will be wrong if the API’s page size isn’t 50 and can cause early termination.

.agents/skills/qodo-manage-rules/scripts/qodo_rules.py[99-108]
.agents/skills/qodo-manage-rules/scripts/qodo_rules.py[127-153]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`cmd_find` uses a hardcoded `50` to decide when to stop paging the `/rules` catalog, which can prematurely stop scanning and miss matches.

### Issue Context
This script is intended to reliably resolve rule IDs from partial text; missing pages defeats that goal.

### Fix Focus Areas
- .agents/skills/qodo-manage-rules/scripts/qodo_rules.py[127-153]

### Suggested fix
Mirror `cmd_list`’s approach: keep a running count of rules seen (or use `len(rules_accumulated)`), and stop when `seen >= totalCount` or when the returned `rules` array is empty—do not assume a fixed page size.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Unapproved gopkg.in/yaml.v3 dependency 📘 Rule violation § Compliance
Description
go.mod adds gopkg.in/yaml.v3, which is outside the approved dependency allowlist. This can
introduce supply-chain and audit risk by expanding the transitive dependency surface.
Code

go.mod[8]

Evidence
Rule 831401 restricts new Go module dependencies to a small approved set. The diff shows a new
require entry for gopkg.in/yaml.v3, which violates that allowlist.

Rule 831401: Disallow new Go module dependencies beyond approved set
go.mod[5-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`go.mod` introduces a new module dependency (`gopkg.in/yaml.v3`) that is not in the approved allowlist.

## Issue Context
Compliance rule 831401 allows new dependencies only for `github.com/spf13/cobra` and `github.com/pelletier/go-toml/v2`.

## Fix Focus Areas
- go.mod[5-9]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. FetchSkill uses HTTPS clone 📘 Rule violation ⌂ Architecture
Description
The new fetch path derives https://github.com/... clone URLs and runs git clone, which performs
runtime network access. This violates the requirement that application code must not attempt any
network calls under any condition.
Code

pkg/skillcore/fetch.go[R123-136]

Evidence
Rule 782313 prohibits runtime network access. FetchRequest.cloneURL() constructs an
https://github.com/... URL, and gitClient.Clone() runs git clone against that URL, which will
initiate outbound network access when executed.

Rule 782313: Disallow runtime network access in application code
pkg/skillcore/fetch.go[123-136]
pkg/skillcore/git.go[108-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Application code introduced in this PR performs runtime network access by cloning over HTTPS.

## Issue Context
Compliance rule 782313 disallows any runtime network access in application code (TCP/UDP/HTTP/DNS), regardless of destination.

## Fix Focus Areas
- pkg/skillcore/fetch.go[90-136]
- pkg/skillcore/git.go[108-136]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (6)
4. Integration test lacks build tag 📘 Rule violation ⌂ Architecture
Description
test/searchindex_quickstart_test.go adds integration-style tests (execing the real binary) without
the required //go:build integration tag. This causes integration tests to run in default unit-test
runs and violates the integration tagging requirement.
Code

test/searchindex_quickstart_test.go[R1-35]

Evidence
Rule 782685 requires integration test files to start with //go:build integration. The new
test/searchindex_quickstart_test.go file begins with a regular comment and package quickstart
without the required build tag.

Rule 782685: Integration tests must use //go:build integration build tag
test/searchindex_quickstart_test.go[1-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new integration test file was added without the required `//go:build integration` build tag.

## Issue Context
These `TestQuickstart_*` tests execute the real built binary and use git substrate setup, which meets the definition of integration tests.

## Fix Focus Areas
- test/searchindex_quickstart_test.go[1-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Ignored c.run error return 📘 Rule violation ≡ Correctness
Description
fetchSparseInto discards the error from c.run(...) when running git fetch, which can hide
failures and lead to incorrect downstream behavior. Error-returning calls must be checked or
explicitly suppressed with a justified //nolint:errcheck.
Code

pkg/skillcore/git.go[R211-217]

Evidence
Rule 782713 requires checking all error returns or explicitly discarding them with
//nolint:errcheck and justification. The diff shows _, _ = c.run(...) with no check and no
//nolint:errcheck comment.

Rule 782713: All error returns must be checked
pkg/skillcore/git.go[211-223]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A call that returns an error is ignored via `_, _ = ...` without a justified suppression.

## Issue Context
The code comment says the fetch failure is "classified with the clone phase", but the implementation currently discards the error entirely.

## Fix Focus Areas
- pkg/skillcore/git.go[211-223]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Catalog fetch ignores @ref 🐞 Bug ≡ Correctness
Description
pkg/skillcore fetches index.json via git show <ref>:index.json without first fetching <ref>,
so origins configured as OWNER/REPO@branch can fail even when reachable. This breaks search and
remote add convention-gating because FetchCatalog forwards Origin.Ref into FetchFile.
Code

pkg/skillcore/git.go[R286-294]

Evidence
The code path explicitly allows origins with @REF and forwards that ref to catalog fetching, but
FetchFile never fetches the ref before trying to read a blob from it, so any ref not already
present locally can fail.

pkg/skillcore/git.go[250-297]
pkg/skillcore/catalog.go[97-114]
internal/config/origin.go[111-150]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FetchFile` clones and immediately runs `git show <ref>:<file>`; when `ref` is a non-default branch (e.g. origin configured as `OWNER/REPO@develop`), that ref commonly does not exist locally after clone, so the show fails.

## Issue Context
`FetchCatalog` passes the configured origin ref (or HEAD) to `FetchFile`, and origin parsing explicitly supports `OWNER/REPO[@REF]`.

## Fix Focus Areas
- pkg/skillcore/git.go[250-297]
- pkg/skillcore/catalog.go[97-114]
- internal/config/origin.go[111-150]

## Implementation notes
- In `FetchFile`, after `Clone(...)`, run an explicit `git fetch --depth 1 origin <ref>` (or equivalent) before `git show`.
- Prefer showing from a fetched, unambiguous revision (e.g. `FETCH_HEAD:<file>` after fetch) to avoid relying on local branch creation.
- Keep error phase classification consistent (`stepClone` vs `stepCheckout`) so callers still get correct typed errors.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Token passed via argv ✓ Resolved 🐞 Bug ⛨ Security
Description
GitHub tokens are embedded into git command-line arguments via `-c http.extraHeader=Authorization:
Basic <base64(token)>`, which exposes the token to local process inspection while git runs. This is
a credential leak risk on shared machines/CI runners.
Code

pkg/skillcore/git.go[R90-106]

Evidence
The code constructs an argv element containing the Authorization header derived from the token, and
then executes git using that argv; this directly exposes the token in the running process command
line.

pkg/skillcore/git.go[29-56]
pkg/skillcore/git.go[90-106]
pkg/skillcore/git.go[108-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`authConfigArgs` injects the token using `git -c http.extraHeader=...`, putting a base64-encoded token into process argv. On many systems, other processes/users can read argv (and base64 is reversible), leaking the credential.

## Issue Context
`gitClient.run` executes `git` with the provided args via `exec.CommandContext`, so anything in `args` is visible in the running process command line.

## Fix Focus Areas
- pkg/skillcore/git.go[29-57]
- pkg/skillcore/git.go[90-136]

## Implementation notes
- Stop passing the token via argv.
- Prefer a mechanism that does not place secrets in the command line, e.g. configure the header via environment-based git config (`GIT_CONFIG_COUNT`/`GIT_CONFIG_KEY_0`/`GIT_CONFIG_VALUE_0` or `GIT_CONFIG_PARAMETERS`) on the `exec.Cmd`.
- Ensure all git invocations in this flow (clone/fetch/checkout/show) receive the same non-argv credential injection.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. search missing Args validator ✓ Resolved 📘 Rule violation ≡ Correctness
Description
The new search Cobra command accepts positional arguments (args) but does not declare an Args
validator. This can allow invalid argument counts/shape to slip through without Cobra-level
validation.
Code

internal/cli/search.go[R46-76]

Evidence
Rule 782342 requires commands that accept positional arguments to declare an Args validator. The
search command's struct literal defines RunE: func(cmd *cobra.Command, args []string) and uses
args, but no Args: field is present in the command definition block.

Rule 782342: Cobra commands accepting positional arguments must declare an Args validator
internal/cli/search.go[46-76]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `search` command accepts positional args but does not declare an `Args` validator.

## Issue Context
Even when a command accepts a variable number of args, it should explicitly declare an appropriate validator (e.g., `cobra.ArbitraryArgs`) to make the contract explicit and consistent.

## Fix Focus Areas
- internal/cli/search.go[46-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Search requires git repo ✓ Resolved 🐞 Bug ≡ Correctness
Description
searchCmd.run unconditionally calls gitToplevel and errors when not in a git repo, even though
loadCatalog can fetch the catalog over git (remote/file://) or read from a local-path origin. This
blocks skillrig search from working in non-git directories with a global or env-configured origin
and contradicts the command’s own help text (“needs no git working tree”).
Code

internal/cli/search.go[R95-103]

Evidence
searchCmd.run currently bails out before loadCatalog, but loadCatalog has a remote-fetch
branch that does not require a git repo; the unconditional gitToplevel call is therefore an
unnecessary functional restriction.

internal/cli/search.go[80-112]
internal/cli/search.go[114-144]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`skillrig search` fails outside a git repository because it always calls `gitToplevel` before attempting to load the catalog, even though catalog acquisition supports remote/file origins that do not require a local repo.

## Issue Context
`loadCatalog` only needs `repoRoot` to optionally read a colocated local checkout (`<repo-root>/OWNER/REPO`). For remote-fetch and local-path origins, the catalog can be acquired without a repo root.

## Fix Focus Areas
- internal/cli/search.go[80-144]
- internal/cli/search.go[146-176]

## Implementation notes
- Change `run()` to not hard-fail when `gitToplevel` fails.
- If `gitToplevel` fails:
 - still allow LOCAL path origins (read `<path>/index.json`), and
 - still allow remote/file origins by calling `skillcore.FetchCatalog`.
- Only use the repo root when it’s available to detect/use a local checkout; otherwise skip the local-checkout optimization.
- Update the not-a-git-repo error path accordingly (it should trigger only when a local-checkout is required, not for all searches).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

10. TestQuickstart_SearchRemoteFromNonGitDir lacks shape asserts 📘 Rule violation ▣ Testability ⭐ New
Description
The new quickstart test only checks that output contains a couple substrings, without asserting
output structure (e.g., expected line count / header+footer shape). This can allow regressions that
still include the substrings but break the CLI output contract.
Code

test/searchindex_quickstart_test.go[R1538-1545]

Evidence
PR Compliance ID 783440 requires output tests to validate structure, not only substrings. The added
test currently asserts only strings.Contains checks against res.stdout, with no line-count or
parsed-structure assertions.

Rule 783440: Tests must validate output shape, not just substring matches
test/searchindex_quickstart_test.go[1538-1545]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TestQuickstart_SearchRemoteFromNonGitDir` validates human output using only substring checks. Per compliance, tests must also validate the output *shape* (bounded/exact line count or equivalent structural constraints) so formatting regressions can’t slip through.

## Issue Context
This test exercises `skillrig search` in human mode; the renderer produces a compact, bounded set of lines (entries + footer hint). The test should assert the expected structure (e.g., split into lines, assert exact/expected count, and validate the footer line separately) in addition to any substring checks.

## Fix Focus Areas
- test/searchindex_quickstart_test.go[1538-1545]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. JSON decode crash path 🐞 Bug ☼ Reliability ⭐ New
Description
_request unconditionally runs json.loads(raw) on any non-empty response body, so a
non-JSON/malformed response will raise JSONDecodeError and crash with a traceback. This bypasses
the script’s otherwise user-friendly sys.exit("ERROR: ...") error handling.
Code

.agents/skills/qodo-manage-rules/scripts/qodo_rules.py[R72-94]

Evidence
The function catches HTTPError/URLError but returns json.loads(raw) without guarding for JSON
parsing errors, which will throw and exit ungracefully.

.agents/skills/qodo-manage-rules/scripts/qodo_rules.py[72-95]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`_request` can crash on malformed/non-JSON responses because it does not catch `json.JSONDecodeError` around `json.loads(raw)`.

### Issue Context
The script already provides controlled error messages for HTTP/network failures; JSON parsing failures should follow the same pattern.

### Fix Focus Areas
- .agents/skills/qodo-manage-rules/scripts/qodo_rules.py[72-95]

### Suggested fix
Wrap `json.loads(raw)` in `try/except json.JSONDecodeError` and `sys.exit` with a concise message that includes method/path and a truncated body snippet (similar to the HTTPError handler).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. Search description truncation not 80 ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Human-mode search output truncates descriptions to 60 characters and uses a single-character
ellipsis, not the required 80 characters with newline replacement and .... This violates the
standardized human output truncation contract.
Code

internal/cli/output.go[R126-181]

Evidence
Rule 783450 requires truncating descriptions to 80 characters and replacing newlines with spaces.
The new code sets searchDescWidth = 60 and truncates using a single-character ellipsis (),
which does not meet the specified 80-character and ... requirements.

Rule 783450: Human output must truncate descriptions to 80 characters and replace newlines with spaces
internal/cli/output.go[126-181]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Human output truncation for search descriptions does not follow the required 80-character + `...` convention.

## Issue Context
The compliance rule requires: (1) replace newlines with spaces, (2) truncate to 80 characters, (3) append `...` if truncated.

## Fix Focus Areas
- internal/cli/output.go[126-181]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit c3e95c7

Results up to commit c1a915a


🐞 Bugs (1) 📘 Rule violations (4) 📎 Requirement gaps (0)


Action required
1. Unapproved gopkg.in/yaml.v3 dependency 📘 Rule violation § Compliance
Description
go.mod adds gopkg.in/yaml.v3, which is outside the approved dependency allowlist. This can
introduce supply-chain and audit risk by expanding the transitive dependency surface.
Code

go.mod[8]

Evidence
Rule 831401 restricts new Go module dependencies to a small approved set. The diff shows a new
require entry for gopkg.in/yaml.v3, which violates that allowlist.

Rule 831401: Disallow new Go module dependencies beyond approved set
go.mod[5-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`go.mod` introduces a new module dependency (`gopkg.in/yaml.v3`) that is not in the approved allowlist.

## Issue Context
Compliance rule 831401 allows new dependencies only for `github.com/spf13/cobra` and `github.com/pelletier/go-toml/v2`.

## Fix Focus Areas
- go.mod[5-9]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. FetchSkill uses HTTPS clone 📘 Rule violation ⌂ Architecture
Description
The new fetch path derives https://github.com/... clone URLs and runs git clone, which performs
runtime network access. This violates the requirement that application code must not attempt any
network calls under any condition.
Code

pkg/skillcore/fetch.go[R123-136]

Evidence
Rule 782313 prohibits runtime network access. FetchRequest.cloneURL() constructs an
https://github.com/... URL, and gitClient.Clone() runs git clone against that URL, which will
initiate outbound network access when executed.

Rule 782313: Disallow runtime network access in application code
pkg/skillcore/fetch.go[123-136]
pkg/skillcore/git.go[108-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Application code introduced in this PR performs runtime network access by cloning over HTTPS.

## Issue Context
Compliance rule 782313 disallows any runtime network access in application code (TCP/UDP/HTTP/DNS), regardless of destination.

## Fix Focus Areas
- pkg/skillcore/fetch.go[90-136]
- pkg/skillcore/git.go[108-136]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Integration test lacks build tag 📘 Rule violation ⌂ Architecture
Description
test/searchindex_quickstart_test.go adds integration-style tests (execing the real binary) without
the required //go:build integration tag. This causes integration tests to run in default unit-test
runs and violates the integration tagging requirement.
Code

test/searchindex_quickstart_test.go[R1-35]

Evidence
Rule 782685 requires integration test files to start with //go:build integration. The new
test/searchindex_quickstart_test.go file begins with a regular comment and package quickstart
without the required build tag.

Rule 782685: Integration tests must use //go:build integration build tag
test/searchindex_quickstart_test.go[1-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new integration test file was added without the required `//go:build integration` build tag.

## Issue Context
These `TestQuickstart_*` tests execute the real built binary and use git substrate setup, which meets the definition of integration tests.

## Fix Focus Areas
- test/searchindex_quickstart_test.go[1-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (5)
4. Ignored c.run error return 📘 Rule violation ≡ Correctness
Description
fetchSparseInto discards the error from c.run(...) when running git fetch, which can hide
failures and lead to incorrect downstream behavior. Error-returning calls must be checked or
explicitly suppressed with a justified //nolint:errcheck.
Code

pkg/skillcore/git.go[R211-217]

Evidence
Rule 782713 requires checking all error returns or explicitly discarding them with
//nolint:errcheck and justification. The diff shows _, _ = c.run(...) with no check and no
//nolint:errcheck comment.

Rule 782713: All error returns must be checked
pkg/skillcore/git.go[211-223]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A call that returns an error is ignored via `_, _ = ...` without a justified suppression.

## Issue Context
The code comment says the fetch failure is "classified with the clone phase", but the implementation currently discards the error entirely.

## Fix Focus Areas
- pkg/skillcore/git.go[211-223]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Catalog fetch ignores @ref 🐞 Bug ≡ Correctness
Description
pkg/skillcore fetches index.json via git show <ref>:index.json without first fetching <ref>,
so origins configured as OWNER/REPO@branch can fail even when reachable. This breaks search and
remote add convention-gating because FetchCatalog forwards Origin.Ref into FetchFile.
Code

pkg/skillcore/git.go[R286-294]

Evidence
The code path explicitly allows origins with @REF and forwards that ref to catalog fetching, but
FetchFile never fetches the ref before trying to read a blob from it, so any ref not already
present locally can fail.

pkg/skillcore/git.go[250-297]
pkg/skillcore/catalog.go[97-114]
internal/config/origin.go[111-150]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FetchFile` clones and immediately runs `git show <ref>:<file>`; when `ref` is a non-default branch (e.g. origin configured as `OWNER/REPO@develop`), that ref commonly does not exist locally after clone, so the show fails.

## Issue Context
`FetchCatalog` passes the configured origin ref (or HEAD) to `FetchFile`, and origin parsing explicitly supports `OWNER/REPO[@REF]`.

## Fix Focus Areas
- pkg/skillcore/git.go[250-297]
- pkg/skillcore/catalog.go[97-114]
- internal/config/origin.go[111-150]

## Implementation notes
- In `FetchFile`, after `Clone(...)`, run an explicit `git fetch --depth 1 origin <ref>` (or equivalent) before `git show`.
- Prefer showing from a fetched, unambiguous revision (e.g. `FETCH_HEAD:<file>` after fetch) to avoid relying on local branch creation.
- Keep error phase classification consistent (`stepClone` vs `stepCheckout`) so callers still get correct typed errors.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Token passed via argv ✓ Resolved 🐞 Bug ⛨ Security
Description
GitHub tokens are embedded into git command-line arguments via `-c http.extraHeader=Authorization:
Basic <base64(token)>`, which exposes the token to local process inspection while git runs. This is
a credential leak risk on shared machines/CI runners.
Code

pkg/skillcore/git.go[R90-106]

Evidence
The code constructs an argv element containing the Authorization header derived from the token, and
then executes git using that argv; this directly exposes the token in the running process command
line.

pkg/skillcore/git.go[29-56]
pkg/skillcore/git.go[90-106]
pkg/skillcore/git.go[108-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`authConfigArgs` injects the token using `git -c http.extraHeader=...`, putting a base64-encoded token into process argv. On many systems, other processes/users can read argv (and base64 is reversible), leaking the credential.

## Issue Context
`gitClient.run` executes `git` with the provided args via `exec.CommandContext`, so anything in `args` is visible in the running process command line.

## Fix Focus Areas
- pkg/skillcore/git.go[29-57]
- pkg/skillcore/git.go[90-136]

## Implementation notes
- Stop passing the token via argv.
- Prefer a mechanism that does not place secrets in the command line, e.g. configure the header via environment-based git config (`GIT_CONFIG_COUNT`/`GIT_CONFIG_KEY_0`/`GIT_CONFIG_VALUE_0` or `GIT_CONFIG_PARAMETERS`) on the `exec.Cmd`.
- Ensure all git invocations in this flow (clone/fetch/checkout/show) receive the same non-argv credential injection.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. search missing Args validator ✓ Resolved 📘 Rule violation ≡ Correctness
Description
The new search Cobra command accepts positional arguments (args) but does not declare an Args
validator. This can allow invalid argument counts/shape to slip through without Cobra-level
validation.
Code

internal/cli/search.go[R46-76]

Evidence
Rule 782342 requires commands that accept positional arguments to declare an Args validator. The
search command's struct literal defines RunE: func(cmd *cobra.Command, args []string) and uses
args, but no Args: field is present in the command definition block.

Rule 782342: Cobra commands accepting positional arguments must declare an Args validator
internal/cli/search.go[46-76]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `search` command accepts positional args but does not declare an `Args` validator.

## Issue Context
Even when a command accepts a variable number of args, it should explicitly declare an appropriate validator (e.g., `cobra.ArbitraryArgs`) to make the contract explicit and consistent.

## Fix Focus Areas
- internal/cli/search.go[46-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Search requires git repo ✓ Resolved 🐞 Bug ≡ Correctness
Description
searchCmd.run unconditionally calls gitToplevel and errors when not in a git repo, even though
loadCatalog can fetch the catalog over git (remote/file://) or read from a local-path origin. This
blocks skillrig search from working in non-git directories with a global or env-configured origin
and contradicts the command’s own help text (“needs no git working tree”).
Code

internal/cli/search.go[R95-103]

Evidence
searchCmd.run currently bails out before loadCatalog, but loadCatalog has a remote-fetch
branch that does not require a git repo; the unconditional gitToplevel call is therefore an
unnecessary functional restriction.

internal/cli/search.go[80-112]
internal/cli/search.go[114-144]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`skillrig search` fails outside a git repository because it always calls `gitToplevel` before attempting to load the catalog, even though catalog acquisition supports remote/file origins that do not require a local repo.

## Issue Context
`loadCatalog` only needs `repoRoot` to optionally read a colocated local checkout (`<repo-root>/OWNER/REPO`). For remote-fetch and local-path origins, the catalog can be acquired without a repo root.

## Fix Focus Areas
- internal/cli/search.go[80-144]
- internal/cli/search.go[146-176]

## Implementation notes
- Change `run()` to not hard-fail when `gitToplevel` fails.
- If `gitToplevel` fails:
 - still allow LOCAL path origins (read `<path>/index.json`), and
 - still allow remote/file origins by calling `skillcore.FetchCatalog`.
- Only use the repo root when it’s available to detect/use a local checkout; otherwise skip the local-checkout optimization.
- Update the not-a-git-repo error path accordingly (it should trigger only when a local-checkout is required, not for all searches).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
9. Search description truncation not 80 ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Human-mode search output truncates descriptions to 60 characters and uses a single-character
ellipsis, not the required 80 characters with newline replacement and .... This violates the
standardized human output truncation contract.
Code

internal/cli/output.go[R126-181]

Evidence
Rule 783450 requires truncating descriptions to 80 characters and replacing newlines with spaces.
The new code sets searchDescWidth = 60 and truncates using a single-character ellipsis (),
which does not meet the specified 80-character and ... requirements.

Rule 783450: Human output must truncate descriptions to 80 characters and replace newlines with spaces
internal/cli/output.go[126-181]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Human output truncation for search descriptions does not follow the required 80-character + `...` convention.

## Issue Context
The compliance rule requires: (1) replace newlines with spaces, (2) truncate to 80 characters, (3) append `...` if truncated.

## Fix Focus Areas
- internal/cli/output.go[126-181]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment thread go.mod
require (
github.com/pelletier/go-toml/v2 v2.3.1
github.com/spf13/cobra v1.10.2
gopkg.in/yaml.v3 v3.0.1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Unapproved gopkg.in/yaml.v3 dependency 📘 Rule violation § Compliance

go.mod adds gopkg.in/yaml.v3, which is outside the approved dependency allowlist. This can
introduce supply-chain and audit risk by expanding the transitive dependency surface.
Agent Prompt
## Issue description
`go.mod` introduces a new module dependency (`gopkg.in/yaml.v3`) that is not in the approved allowlist.

## Issue Context
Compliance rule 831401 allows new dependencies only for `github.com/spf13/cobra` and `github.com/pelletier/go-toml/v2`.

## Fix Focus Areas
- go.mod[5-9]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread pkg/skillcore/fetch.go
Comment on lines +123 to +136
func (r FetchRequest) cloneURL() string {
if r.RepoURL != "" {
return r.RepoURL
}

return "https://" + defaultGitHubHost + "/" + r.Owner + "/" + r.Repo + ".git"
}

// classifyFetchError turns a raw fetch failure into the renderable typed error
// the CLI branches on. It runs the shared ClassifyGitError mapping
// (Auth/Unreachable/NotFound), then applies the fetch-specific refinements
// ClassifyGitError cannot know on its own, all anchored on WHICH git phase failed
// (FIX-3 — the *fetchStepError tag):
//
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. fetchskill uses https clone 📘 Rule violation ⌂ Architecture

The new fetch path derives https://github.com/... clone URLs and runs git clone, which performs
runtime network access. This violates the requirement that application code must not attempt any
network calls under any condition.
Agent Prompt
## Issue description
Application code introduced in this PR performs runtime network access by cloning over HTTPS.

## Issue Context
Compliance rule 782313 disallows any runtime network access in application code (TCP/UDP/HTTP/DNS), regardless of destination.

## Fix Focus Areas
- pkg/skillcore/fetch.go[90-136]
- pkg/skillcore/git.go[108-136]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1 to +35
// This file holds the TestQuickstart_* integration suite for feature
// 003-search-remote, the scenarios that are exercisable end-to-end against the
// real binary today: the discover (search, US1) and catalog-generation (index,
// US5) groups, plus the add --help shape (US2 SC-008). Each maps 1:1 to a
// scenario in specledger/003-search-remote/quickstart.md.
//
// Like the 001/002 suites it builds the binary once (TestMain in
// quickstart_test.go) and execs it via run(). It reuses the 002 fixture
// helpers (git, copyTree, sampleOriginDir, pinnedGitEnv, originRepo,
// decodeJSON, requireKeys, countExampleLines) and the RAW-git oracle
// discipline: every fixture is bootstrapped and every expected value computed
// with raw git, NEVER through skillcore (Constitution III / research D11).
//
// SUBSTRATE NOTE (S4 / D6). The remote-acquisition group (US2 remote add, US3
// --pin, US4 auth/unreachable failures) runs against a real file:// bare repo
// for the CLI's origin (FIX-1 gave config.ParseOrigin a local/file:// form and
// pkg/skillcore.cloneURL a file:// seam, so `add` with no local checkout clones
// a t.TempDir bare repo over a real git transport — offline, no github.com).
// newRemoteOrigin git-inits a working tree (committed + a v-tag), clones it
// --bare, and binds SKILLRIG_ORIGIN=file://<bare>; the RAW-git oracle reads the
// expected treeSha straight from that bare repo (never skillcore, D11).
//
// Injected git failures (US4 auth/unreachable/private-not-found) are produced
// at the integration tier by a fake `git` on the binary's PATH (fakeGitBin) that
// passes every command through to the real git EXCEPT `clone`, which it fails
// with a crafted (exit 128, stderr) — the integration analog of the
// pkg/skillcore commandContext stub seam (which, being an unexported field, is
// only reachable from a pkg/skillcore unit test). The clone-phase failure trips
// the catalog gate before any subtree is fetched, so the CLI renders the
// auth/unreachable/not-found class distinctly. The typed-class assertions for
// those classes live as unit tests in pkg/skillcore (TestClassifyFetchError),
// per the quickstart's own "unit-level via the stub seam" note.
package quickstart

import (
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Integration test lacks build tag 📘 Rule violation ⌂ Architecture

test/searchindex_quickstart_test.go adds integration-style tests (execing the real binary) without
the required //go:build integration tag. This causes integration tests to run in default unit-test
runs and violates the integration tagging requirement.
Agent Prompt
## Issue description
A new integration test file was added without the required `//go:build integration` build tag.

## Issue Context
These `TestQuickstart_*` tests execute the real built binary and use git substrate setup, which meets the definition of integration tests.

## Fix Focus Areas
- test/searchindex_quickstart_test.go[1-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread pkg/skillcore/git.go Outdated
Comment on lines +211 to +217
// Materialize an off-tip ref (an arbitrary commit SHA, FIX-6). If ref is
// already a fetched tip (branch/tag), this fetch fails harmlessly; only the
// checkout below is authoritative for ref existence, so a fetch failure is
// classified with the clone phase, never as a missing version.
fetchArgs := append([]string{}, auth...)
fetchArgs = append(fetchArgs, "-C", dir, "fetch", "--depth", "1", "origin", ref)
_, _ = c.run(ctx, fetchArgs...)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Ignored c.run error return 📘 Rule violation ≡ Correctness

fetchSparseInto discards the error from c.run(...) when running git fetch, which can hide
failures and lead to incorrect downstream behavior. Error-returning calls must be checked or
explicitly suppressed with a justified //nolint:errcheck.
Agent Prompt
## Issue description
A call that returns an error is ignored via `_, _ = ...` without a justified suppression.

## Issue Context
The code comment says the fetch failure is "classified with the clone phase", but the implementation currently discards the error entirely.

## Fix Focus Areas
- pkg/skillcore/git.go[211-223]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread internal/cli/search.go
Comment thread pkg/skillcore/git.go Outdated
Comment on lines +286 to +294
auth := authConfigArgs(token)

showArgs := append([]string{}, auth...)
showArgs = append(showArgs, "-C", tmpDir, "show", ref+":"+file)

out, err := c.run(ctx, showArgs...)
if err != nil {
return nil, &fetchStepError{step: stepCheckout, err: err}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

6. Catalog fetch ignores @ref 🐞 Bug ≡ Correctness

pkg/skillcore fetches index.json via git show <ref>:index.json without first fetching <ref>,
so origins configured as OWNER/REPO@branch can fail even when reachable. This breaks search and
remote add convention-gating because FetchCatalog forwards Origin.Ref into FetchFile.
Agent Prompt
## Issue description
`FetchFile` clones and immediately runs `git show <ref>:<file>`; when `ref` is a non-default branch (e.g. origin configured as `OWNER/REPO@develop`), that ref commonly does not exist locally after clone, so the show fails.

## Issue Context
`FetchCatalog` passes the configured origin ref (or HEAD) to `FetchFile`, and origin parsing explicitly supports `OWNER/REPO[@REF]`.

## Fix Focus Areas
- pkg/skillcore/git.go[250-297]
- pkg/skillcore/catalog.go[97-114]
- internal/config/origin.go[111-150]

## Implementation notes
- In `FetchFile`, after `Clone(...)`, run an explicit `git fetch --depth 1 origin <ref>` (or equivalent) before `git show`.
- Prefer showing from a fetched, unambiguous revision (e.g. `FETCH_HEAD:<file>` after fetch) to avoid relying on local branch creation.
- Keep error phase classification consistent (`stepClone` vs `stepCheckout`) so callers still get correct typed errors.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread internal/cli/search.go
Comment thread pkg/skillcore/git.go Outdated
…FIG env

Qodo code review (3 bugs + 6 rule violations). Fixed the 4 real/actionable;
declined 4 (documented decisions / false positive) — see PR reply.

- #8 (security): token no longer passed via argv. authConfigArgs (-c
  http.extraHeader=…) → authConfigEnv injecting GIT_CONFIG_COUNT/KEY_0/VALUE_0
  (git >=2.31) via cmd.Env, so the base64 credential is in the process environ,
  not ps-visible argv. Matches gh-cli's "token out of argv" posture (gh uses a
  credential helper; we use GIT_CONFIG env since we resolve the token ourselves).
  runEnv() added; Clone/fetchSparseInto/FetchFile use it. F2 tests rewritten:
  TestAuthConfigEnv + TestClone_TokenInjectionViaEnv (assert no token in argv,
  credential in GIT_CONFIG_VALUE_0 env).
- #7: `search` no longer requires a git repo — repoRoot is optional; a non-git
  cwd / checkout-less remote falls through to FetchCatalog. New
  TestQuickstart_SearchRemoteFromNonGitDir (file:// origin from a plain tempdir).
- #5: search declares Args: cobra.ArbitraryArgs (rule 782342).
- #9: human description width 60 → 80 (rule 783450).
- #4: investigated — no genuine ignored error (errcheck clean); no change.

Gate: make check 0 lint; go test -count=1 all pass; new tests run+pass; only the
two git-on-PATH t.Skip guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@so0k
Copy link
Copy Markdown
Contributor Author

so0k commented May 31, 2026

Qodo review triage — fixed d836344

Thanks Qodo. Disposition of the 9 findings:

✅ Fixed (d836344)

❌ Declined (with rationale)

  • Add Apache 2.0 license #1 gopkg.in/yaml.v3 not in allowlist (rule 831401) — deliberate, recorded decision: the skill manifest moved to agentskills.io SKILL.md YAML frontmatter (S1), so a YAML parser is required; it's the same parser gh uses. Documented in plan.md Complexity Tracking, spec.md A7, and CLAUDE.md. Please add gopkg.in/yaml.v3 to the rule-831401 allowlist.
  • chore: sync SpecLedger templates to constitution v2.1.0 #2 FetchSkill does network (rule 782313) — by design: remote add/search must fetch from the GitHub origin — that is the feature (003+004). Network is confined to the fetch layer; the verify integrity gate stays fully offline. Rule 782313 needs a carve-out for the fetch layer.
  • feat(001): skillrig init + single origin resolver #3 integration test lacks //go:build integration (rule 782685) — project convention separates integration tests by the ./test/ directory (the Makefile runs go test ./test/...), not a build tag — consistent with 001/002. (Qodo declined this same rule on PR feat(002): vendor & verify skills — skillcore SDK + add/verify #5.)
  • Feature: Flag if origin is not pointing at default branch #6 "catalog fetch ignores @ref" — false positive: search.go passes Ref: origin.Ref and FetchCatalog honors it (defaults to HEAD when empty). Only the operator-controlled local-checkout fast-path reads the checkout as-is, by design.

make check green (golangci-lint 0 issues); go test -count=1 ./... passes; the 11 remote acceptance scenarios run+pass, 0 skipped.

…loses #7)

Resolves issue #7 (Deprecated Terminology review). Terminology patch, no
principle changes (Sync Impact note added; version 2.1.0 → 2.1.1):
- §III ground-truth: "skills/*/skill.toml walk" → "skills/*/SKILL.md frontmatter
  walk (skillrig index)"; mise [[requires]] → metadata.x-skillrig.requires
  (manifest moved to SKILL.md frontmatter in 003/S1).
- §III testing tiers: GitHub "httptest + go-vcr" Unit boundary → the
  pkg/skillcore git exec-stub seam (skillrig shells git; the boundary is the git
  exec, not an HTTP API), with the file:// remote substrate — matching 003.
- §IX: eval tooling path corrected to .agents/skills/skill-creator/scripts/run_eval.py.

Completes the doc-scrub started in 18aebf2 (ARCHITECTURE/ROADMAP/CLAUDE.md). Also
deactivated Qodo rule 782685 (integration build-tag; project uses ./test/ convention)
and narrowed 782313 (network; carved out the consume-only fetch layer).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@so0k
Copy link
Copy Markdown
Contributor Author

so0k commented May 31, 2026

Closing without merging (branch 003-search-remote is preserved; this PR can be reopened).

State at close: the feature (search + remote add + --pin + index, manifest→SKILL.md frontmatter) is verified working — make check green (0 lint), 11 remote acceptance scenarios run+pass (0 skipped), cold adversarial re-review cleared it, Qodo triaged (4 fixed, 4 declined). Full trail under specledger/003-search-remote/.

Why closing rather than merging now: the planned "seed the origin with more skills" step (plan.md step 6) was omitted from the implementation, so the fixture origin still has a single skill — search/--topic/ordering are exercised end-to-end against one skill (the filter/order logic is covered via a synthetic in-memory catalog, but not over the real fetch path with multiple skills). Tracked in #9.

Reopen / supersede once #9 (multi-skill fixture + end-to-end search-filter coverage) lands.

@so0k so0k closed this May 31, 2026
@so0k so0k reopened this May 31, 2026
@so0k
Copy link
Copy Markdown
Contributor Author

so0k commented May 31, 2026

(The earlier close was a misclick — merging now. Fixture multi-skill seeding tracked in #9 as a follow-up.)

@so0k so0k merged commit 48afc69 into main May 31, 2026
@so0k so0k deleted the 003-search-remote branch May 31, 2026 08:38
@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 31, 2026

Code review by qodo was updated up to the latest commit c3e95c7

Comment on lines +140 to +150
page, total = 1, 0
while True:
d = _request("GET", f"/rules?page={page}")
for r in d.get("rules", []):
blob = (r.get("name", "") + " " + (r.get("content") or "")).lower()
if needle in blob:
ids.add(_rid(r))
total = d.get("totalCount", 0)
if page * 50 >= total or not d.get("rules"):
break
page += 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Hardcoded page size stop 🐞 Bug ≡ Correctness

cmd_find terminates pagination using page * 50 >= total, assuming the API returns exactly 50
rules per page; if the page size differs, find can stop early and silently miss matching rules.
This makes find produce incomplete results while list paginates based on observed counts.
Agent Prompt
### Issue description
`cmd_find` uses a hardcoded `50` to decide when to stop paging the `/rules` catalog, which can prematurely stop scanning and miss matches.

### Issue Context
This script is intended to reliably resolve rule IDs from partial text; missing pages defeats that goal.

### Fix Focus Areas
- .agents/skills/qodo-manage-rules/scripts/qodo_rules.py[127-153]

### Suggested fix
Mirror `cmd_list`’s approach: keep a running count of rules seen (or use `len(rules_accumulated)`), and stop when `seen >= totalCount` or when the returned `rules` array is empty—do not assume a fixed page size.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

so0k added a commit that referenced this pull request May 31, 2026
Status flip 🚧→✅; 003 (search + remote add + index) shipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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