Add namespaced --category filter to skern skill list (#96)#98
Open
devrimcavusoglu wants to merge 1 commit into
Open
Add namespaced --category filter to skern skill list (#96)#98devrimcavusoglu wants to merge 1 commit into
--category filter to skern skill list (#96)#98devrimcavusoglu wants to merge 1 commit into
Conversation
Adds a repeatable, domain-agnostic `--category category:value` flag to `skern skill list` for narrowing a skill set by structured tag dimensions (e.g. `lang:python`, `topic:testing`) without skern knowing what any category means. The existing flat `--tag` filter is unchanged; the two compose with AND. Semantics (the two design questions the issue left open): - Untagged / category-absent handling: strict by default — a skill with no tag in a requested category is excluded. `--include-untagged` opts into "absent = applies to all". A category the skill *does* declare must still match a requested value even with the flag. - Combination: OR within a category, AND across categories. Values can be supplied as repeated flags (`--category lang:python --category lang:go`) or a comma list (`--category lang:python,go`); the two forms are equivalent. The matcher (`matchesCategories`) sits beside `hasTag` in skill_helpers.go; `parseCategoryFilters` validates flag input and returns a ValidationError (exit code 2) for a missing colon, empty category, or empty value. Matching is case-insensitive, consistent with `hasTag`. Flat tags (no colon) are never categorical and remain `--tag` territory. Tests cover the parser, the matcher (OR/AND, strict vs include-untagged, zero-tag and flat-tag edge cases, case-insensitivity), and the end-to-end `--json` contract including --tag/--category composition and the exit-code-2 path. Docs updated in reference/commands.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #96.
Summary
Adds a repeatable, domain-agnostic
--category category:valueflag toskern skill listfor narrowing a skill set by structured tag dimensions (e.g.lang:python,topic:testing) without skern knowing what any category means. The namespace is whatever precedes the first:; skern never enumerates or special-cases known categories. The existing flat--tagfilter is unchanged, and the two compose with AND.Design decisions
The issue left two semantics questions open. Resolved as follows (these were confirmed with the maintainer before implementation):
1. Untagged / category-absent handling — strict by default, wildcard opt-in.
A skill with no tag in a requested category is excluded.
--include-untaggedopts into "absent = applies to all". A category the skill does declare must still match a requested value even with the flag —--include-untaggedonly relaxes the absent case, never the present-but-mismatched case.2. Combination — OR within a category, AND across categories.
--category lang:python,go --category topic:testingmatches skills tagged (lang:pythonorlang:go) andtopic:testing. Values can be supplied as repeated flags or a comma list;--category lang:python --category lang:go≡--category lang:python,go.Implementation
parseCategoryFilters(inskill_helpers.go) parses the repeated flag into anamespace -> []valuemap, lowercasing for case-insensitive matching (consistent withhasTag). Malformed input — missing colon, empty category, empty value — returns aValidationError(exit code 2).matchesCategoriessits besidehasTagand applies OR-within / AND-across with the untagged rule. Flat tags (no colon) are not categorical and are ignored by it — they remain--tagterritory.skill_list.goparses filters once up front (so validation errors surface immediately) and ANDs the matcher with the existing--tagcheck in the discovery loop.Edge cases handled (per acceptance criteria)
--category--include-untagged)Test plan
go test ./...— all packages passgofmtclean;golangci-lint run ./internal/cli/...→ 0 issuesparseCategoryFilters(9 cases incl. all malformed inputs) andmatchesCategories(13 cases: OR/AND, strict vs include-untagged, zero-tag, flat-tag, case-insensitivity)--jsoncontract test end-to-end (TestSkillList_FilterByCategory): single value, OR-within, AND-across, strict default,--include-untagged--tag+--categorycomposition (TestSkillList_TagAndCategory) and the exit-code-2 path (TestSkillList_FilterByCategory_Invalid)Manual-test gate: the acceptance criteria name the agent-driven manual-test gate, which is an interactive release-time process (build binary + drive scenarios with an agent in
/tmp). This change doesn't alter any existing scenario; the--jsoncontract is covered by the automated tests above. The maintainer runs the full manual gate before release as usual.Docs
docs/reference/commands.md: added--category/--include-untaggedto theskill listflag table plus a "Categorical-tag filtering" section documenting repeatability, the OR/AND model, the strict-vs---include-untaggedrule, and the exit-code-2 behavior.🤖 Generated with Claude Code