Every SKILL.md, every harness.
A fast, pluggable TUI for inspecting SKILL.md files across every agentic-CLI
harness on your machine β Claude Code, Codex CLI, Cursor, OpenCode, Antigravity β
broken down by scope (user / project / project-local) and harness, with copy /
move / delete in 1β2 keystrokes.
β 1 Matrix β 2 Tree 3 Diff
Harnesses: β claude-code β codex β cursor β opencode β antigravity
skill user project local
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
git-helper β β β Β· Β·
multi-scope-skill β β Β·
local-skill Β· Β· β
β¦
β present β shadowed (higher scope wins) Β· absent ! parse error
[/] search [f] filter [p] preview [c] copy [m] move [d] delete [?] help
Recommended β curl-pipe installer (Linux + macOS, no Go required):
curl -sSL https://heidihowilson.github.io/skillscope/install.sh | shThe installer picks the first directory on your PATH it can write to (preferring /opt/homebrew/bin, /usr/local/bin, ~/.local/bin, ~/bin in that order). If none are on PATH, it falls back to ~/.local/bin and prints the exact shell-rc snippet you need to paste to make skillscope reachable.
Pin a version with SKILLSCOPE_VERSION=v0.1.0 β¦. Override the install dir entirely with SKILLSCOPE_INSTALL_DIR=β¦. Refuses to run as root unless SKILLSCOPE_ACCEPT_ROOT=1. sha256 is verified against the release's checksums.txt.
Homebrew (macOS + Linux):
brew install heidihowilson/tap/skillscopeScoop (Windows):
scoop bucket add heidihowilson https://github.com/heidihowilson/scoop-bucket
scoop install skillscopeWinGet (Windows): manifests are hand-curated in winget/ pending submission to microsoft/winget-pkgs. Once accepted upstream, winget install heidihowilson.skillscope will work.
Via go install:
go install github.com/heidihowilson/skillscope/cmd/skillscope@latestFrom source:
git clone https://github.com/heidihowilson/skillscope
cd skillscope
go install ./cmd/skillscopeRuns on Linux, macOS, and Windows. Go 1.22+. Single static binary, no CGO.
Run it from anywhere:
skillscopeIt scans your home dir + the current git repo (if any) and shows every skill across every harness. From inside this repo:
make demoboots the TUI pointed at testdata/.
| Key | Action |
|---|---|
q / Ctrl+C |
quit |
? |
help overlay |
/ |
fuzzy search |
Esc |
close preview / clear filter |
1β9 |
jump to view by index |
v / V |
cycle views forward / back |
f |
cycle harness filter |
F |
clear harness filter |
s |
cycle scope-kind filter |
g |
toggle "shadowed only" |
Tab |
move focus between panels |
R |
re-scan filesystem |
| Key | Action |
|---|---|
p |
preview pane: off β raw β rendered |
e |
open in $EDITOR |
c |
copy to scope (numbered picker, then 1β9) |
m |
move to scope (same picker) |
d |
delete (confirm with y) |
y |
yank skill path |
Picker shortcut: e.g. c 3 = "copy to scope 3."
| Flag | Meaning |
|---|---|
--version |
print version and exit |
--json |
dump all skills as JSON to stdout and exit |
--demo-home <dir> |
use <dir> as the simulated home dir |
--demo-repo <dir> |
use <dir> as the simulated repo root |
- Matrix β rows = skills, columns = scope (user / project / local /
plugin). Each cell shows one colored dot per harness present.
βwinning,βshadowed by a higher-precedence scope in the same harness,!parse error,Β·absent. - Tree β collapsible Harness β Scope β Skill.
- Diff β side-by-side frontmatter + body for skills in multiple scopes within one harness.
Drop a single file at internal/harness/<id>/harness.go. It self-registers
in init(); no edits to the core.
package myharness
import (
"path/filepath"
"github.com/charmbracelet/lipgloss"
"github.com/heidihowilson/skillscope/internal/harness"
)
type h struct{}
func (h) ID() string { return "myharness" }
func (h) Name() string { return "My Harness" }
func (h) Color() lipgloss.Color { return lipgloss.Color("#FF66CC") }
func (h) Scopes(ctx harness.Context) []harness.Scope {
scopes := []harness.Scope{{
Harness: "myharness", Kind: harness.User,
Path: filepath.Join(ctx.HomeDir, ".myharness", "skills"),
}}
if ctx.RepoRoot != "" {
scopes = append(scopes, harness.Scope{
Harness: "myharness", Kind: harness.Project,
Path: filepath.Join(ctx.RepoRoot, ".myharness", "skills"),
})
}
return scopes
}
func init() { harness.Register(h{}) }Then add a blank-import in cmd/skillscope/main.go:
_ "github.com/heidihowilson/skillscope/internal/harness/myharness"Drop a single file at internal/view/<id>/view.go. Same init()-registration
pattern.
package myview
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/heidihowilson/skillscope/internal/app"
)
type v struct{}
func (v) ID() string { return "myview" }
func (v) Name() string { return "My View" }
func (v) KeyHint() string { return "7" }
func (v) Init(m *app.Model) tea.Cmd { return nil }
func (vv v) Update(m *app.Model, msg tea.Msg) (app.View, tea.Cmd) {
return vv, nil
}
func (vv v) Render(m *app.Model, width, height int) string {
skills := m.FilteredSkills()
out := fmt.Sprintf("My View β %d skills\n\n", len(skills))
for i, sk := range skills {
marker := " "
if i == m.Cursor {
marker = "βΆ "
}
out += fmt.Sprintf("%s%s (%s)\n", marker, sk.Name, sk.Scope.Harness)
if i > height-4 {
break
}
}
_ = width
return out
}
func init() { app.RegisterView(v{}) }Blank-import it in cmd/skillscope/main.go and it'll appear in the tab bar.
- Editing skills inside the TUI (use
$EDITORwithe). - Creating skills from scratch.
- Syncing skills to a remote.
- Supporting non-skill rules files (
CLAUDE.md,AGENTS.md,.cursorrules).
MIT.