skillroute 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. skillroute-0.2.0/.github/dependabot.yml +21 -0
  2. skillroute-0.2.0/.github/workflows/ci.yml +172 -0
  3. skillroute-0.2.0/.github/workflows/release.yml +144 -0
  4. skillroute-0.2.0/.gitignore +25 -0
  5. skillroute-0.2.0/CHANGELOG.md +146 -0
  6. skillroute-0.2.0/CONTRIBUTING.md +55 -0
  7. skillroute-0.2.0/LICENSE +21 -0
  8. skillroute-0.2.0/ONBOARDING.md +127 -0
  9. skillroute-0.2.0/PKG-INFO +220 -0
  10. skillroute-0.2.0/README.md +190 -0
  11. skillroute-0.2.0/SECURITY.md +18 -0
  12. skillroute-0.2.0/docs/agent-setup.md +227 -0
  13. skillroute-0.2.0/docs/assets/screenshot-route.svg +21 -0
  14. skillroute-0.2.0/docs/assets/screenshot-skill-atlas.png +0 -0
  15. skillroute-0.2.0/docs/assets/screenshot-traces.svg +27 -0
  16. skillroute-0.2.0/docs/astra-backend.md +65 -0
  17. skillroute-0.2.0/docs/evals.md +83 -0
  18. skillroute-0.2.0/docs/getting-started.md +106 -0
  19. skillroute-0.2.0/docs/harnesses.md +218 -0
  20. skillroute-0.2.0/docs/mcp-server.md +89 -0
  21. skillroute-0.2.0/docs/metadata-overlays.md +51 -0
  22. skillroute-0.2.0/docs/roadmap.md +99 -0
  23. skillroute-0.2.0/docs/route-observability.md +51 -0
  24. skillroute-0.2.0/docs/skill-atlas.md +79 -0
  25. skillroute-0.2.0/examples/evals/dogfood_routes.json +21 -0
  26. skillroute-0.2.0/examples/evals/golden_routes.json +21 -0
  27. skillroute-0.2.0/examples/skills/astra-vector-backend/SKILL.md +18 -0
  28. skillroute-0.2.0/examples/skills/mcp-server-patterns/SKILL.md +20 -0
  29. skillroute-0.2.0/examples/skills/mcp-server-patterns/templates/tool-template.md +5 -0
  30. skillroute-0.2.0/examples/skills/python-patterns/SKILL.md +18 -0
  31. skillroute-0.2.0/examples/skills/python-testing/SKILL.md +18 -0
  32. skillroute-0.2.0/harnesses/amp.toml +17 -0
  33. skillroute-0.2.0/harnesses/claude-code.toml +51 -0
  34. skillroute-0.2.0/harnesses/claude-desktop.toml +22 -0
  35. skillroute-0.2.0/harnesses/codex.toml +43 -0
  36. skillroute-0.2.0/harnesses/cursor.toml +19 -0
  37. skillroute-0.2.0/harnesses/gemini-cli.toml +22 -0
  38. skillroute-0.2.0/harnesses/goose.toml +29 -0
  39. skillroute-0.2.0/harnesses/hermes.toml +50 -0
  40. skillroute-0.2.0/harnesses/ibm-bob.toml +22 -0
  41. skillroute-0.2.0/harnesses/opencode.toml +33 -0
  42. skillroute-0.2.0/harnesses/pi.toml +41 -0
  43. skillroute-0.2.0/harnesses/vscode.toml +19 -0
  44. skillroute-0.2.0/harnesses/windsurf.toml +18 -0
  45. skillroute-0.2.0/harnesses/zed.toml +29 -0
  46. skillroute-0.2.0/hatch_build.py +52 -0
  47. skillroute-0.2.0/mcp/LICENSE +21 -0
  48. skillroute-0.2.0/mcp/README.md +23 -0
  49. skillroute-0.2.0/mcp/package-lock.json +1573 -0
  50. skillroute-0.2.0/mcp/package.json +51 -0
  51. skillroute-0.2.0/mcp/src/bridge.ts +154 -0
  52. skillroute-0.2.0/mcp/src/index.ts +96 -0
  53. skillroute-0.2.0/mcp/tests/bridge-command.test.mjs +75 -0
  54. skillroute-0.2.0/mcp/tests/mcp-smoke.mjs +83 -0
  55. skillroute-0.2.0/mcp/tsconfig.json +16 -0
  56. skillroute-0.2.0/pyproject.toml +77 -0
  57. skillroute-0.2.0/scripts/bootstrap.sh +56 -0
  58. skillroute-0.2.0/scripts/install.sh +339 -0
  59. skillroute-0.2.0/src/skillroute/__init__.py +15 -0
  60. skillroute-0.2.0/src/skillroute/__main__.py +5 -0
  61. skillroute-0.2.0/src/skillroute/atlas.py +263 -0
  62. skillroute-0.2.0/src/skillroute/attribution.py +82 -0
  63. skillroute-0.2.0/src/skillroute/backends.py +566 -0
  64. skillroute-0.2.0/src/skillroute/catalog.py +750 -0
  65. skillroute-0.2.0/src/skillroute/cli.py +988 -0
  66. skillroute-0.2.0/src/skillroute/client_setup.py +70 -0
  67. skillroute-0.2.0/src/skillroute/context.py +92 -0
  68. skillroute-0.2.0/src/skillroute/dogfood.py +78 -0
  69. skillroute-0.2.0/src/skillroute/evals.py +70 -0
  70. skillroute-0.2.0/src/skillroute/harness_doctor.py +438 -0
  71. skillroute-0.2.0/src/skillroute/harness_render.py +494 -0
  72. skillroute-0.2.0/src/skillroute/harness_setup.py +339 -0
  73. skillroute-0.2.0/src/skillroute/harnesses.py +354 -0
  74. skillroute-0.2.0/src/skillroute/mcp_setup.py +91 -0
  75. skillroute-0.2.0/src/skillroute/metadata.py +152 -0
  76. skillroute-0.2.0/src/skillroute/migrations.py +327 -0
  77. skillroute-0.2.0/src/skillroute/models.py +104 -0
  78. skillroute-0.2.0/src/skillroute/overlays.py +44 -0
  79. skillroute-0.2.0/src/skillroute/parser.py +370 -0
  80. skillroute-0.2.0/src/skillroute/py.typed +0 -0
  81. skillroute-0.2.0/src/skillroute/rerankers.py +68 -0
  82. skillroute-0.2.0/src/skillroute/routing.py +368 -0
  83. skillroute-0.2.0/src/skillroute/text.py +79 -0
  84. skillroute-0.2.0/src/skillroute/tuning.py +200 -0
  85. skillroute-0.2.0/src/skillroute/ui_server.py +199 -0
  86. skillroute-0.2.0/tests/conftest.py +20 -0
  87. skillroute-0.2.0/tests/fixtures/golden_routes.json +26 -0
  88. skillroute-0.2.0/tests/fixtures/schema_v1.sql +66 -0
  89. skillroute-0.2.0/tests/fixtures/skills/astra-vector-backend/SKILL.md +11 -0
  90. skillroute-0.2.0/tests/fixtures/skills/mcp-server-patterns/SKILL.md +20 -0
  91. skillroute-0.2.0/tests/fixtures/skills/mcp-server-patterns/templates/tool.md +4 -0
  92. skillroute-0.2.0/tests/fixtures/skills/python-testing/SKILL.md +12 -0
  93. skillroute-0.2.0/tests/test_atlas.py +126 -0
  94. skillroute-0.2.0/tests/test_attribution.py +136 -0
  95. skillroute-0.2.0/tests/test_backends.py +476 -0
  96. skillroute-0.2.0/tests/test_catalog.py +227 -0
  97. skillroute-0.2.0/tests/test_cli.py +927 -0
  98. skillroute-0.2.0/tests/test_client_setup.py +318 -0
  99. skillroute-0.2.0/tests/test_context.py +88 -0
  100. skillroute-0.2.0/tests/test_dogfood.py +106 -0
  101. skillroute-0.2.0/tests/test_evals.py +17 -0
  102. skillroute-0.2.0/tests/test_harness_doctor.py +290 -0
  103. skillroute-0.2.0/tests/test_harnesses.py +533 -0
  104. skillroute-0.2.0/tests/test_metadata.py +127 -0
  105. skillroute-0.2.0/tests/test_migrations.py +279 -0
  106. skillroute-0.2.0/tests/test_parser.py +74 -0
  107. skillroute-0.2.0/tests/test_rerankers.py +90 -0
  108. skillroute-0.2.0/tests/test_routing.py +113 -0
  109. skillroute-0.2.0/tests/test_scripts.py +26 -0
  110. skillroute-0.2.0/tests/test_tuning.py +229 -0
  111. skillroute-0.2.0/tests/test_ui_server.py +162 -0
  112. skillroute-0.2.0/uv.lock +814 -0
  113. skillroute-0.2.0/web/dist/assets/index-I0Sgrz_R.css +1 -0
  114. skillroute-0.2.0/web/dist/assets/index-ylXOtl-c.js +15 -0
  115. skillroute-0.2.0/web/dist/index.html +13 -0
  116. skillroute-0.2.0/web/eslint.config.js +40 -0
  117. skillroute-0.2.0/web/index.html +12 -0
  118. skillroute-0.2.0/web/package-lock.json +3689 -0
  119. skillroute-0.2.0/web/package.json +32 -0
  120. skillroute-0.2.0/web/src/App.tsx +248 -0
  121. skillroute-0.2.0/web/src/api.ts +28 -0
  122. skillroute-0.2.0/web/src/components/graph-nodes.tsx +42 -0
  123. skillroute-0.2.0/web/src/components/inspector.tsx +277 -0
  124. skillroute-0.2.0/web/src/components/panels.tsx +238 -0
  125. skillroute-0.2.0/web/src/components/primitives.tsx +80 -0
  126. skillroute-0.2.0/web/src/components/route-preview.tsx +77 -0
  127. skillroute-0.2.0/web/src/graph.test.ts +123 -0
  128. skillroute-0.2.0/web/src/graph.ts +188 -0
  129. skillroute-0.2.0/web/src/main.tsx +11 -0
  130. skillroute-0.2.0/web/src/styles.css +1186 -0
  131. skillroute-0.2.0/web/src/types.ts +132 -0
  132. skillroute-0.2.0/web/src/ui.ts +2 -0
  133. skillroute-0.2.0/web/src/util.ts +22 -0
  134. skillroute-0.2.0/web/src/vite-env.d.ts +1 -0
  135. skillroute-0.2.0/web/tsconfig.json +21 -0
  136. skillroute-0.2.0/web/vite.config.ts +13 -0
@@ -0,0 +1,21 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+
8
+ - package-ecosystem: npm
9
+ directory: "/mcp"
10
+ schedule:
11
+ interval: weekly
12
+
13
+ - package-ecosystem: npm
14
+ directory: "/web"
15
+ schedule:
16
+ interval: weekly
17
+
18
+ - package-ecosystem: uv
19
+ directory: "/"
20
+ schedule:
21
+ interval: weekly
@@ -0,0 +1,172 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ python:
13
+ name: Python ${{ matrix.python-version }}
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.11", "3.13"]
19
+ steps:
20
+ - name: Check out repository
21
+ uses: actions/checkout@v7
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v9.0.0
25
+ with:
26
+ cache-suffix: python-${{ matrix.python-version }}
27
+
28
+ - name: Set up Python
29
+ uses: actions/setup-python@v7
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+
33
+ - name: Verify lockfile is up to date
34
+ run: uv lock --check
35
+
36
+ - name: Run tests with coverage
37
+ run: uv run --frozen --extra dev pytest --cov=skillroute --cov-report=term-missing --cov-fail-under=80
38
+
39
+ - name: Run lint
40
+ run: uv run --frozen --extra dev ruff check .
41
+
42
+ - name: Run type check
43
+ run: uv run --frozen --extra dev mypy
44
+
45
+ - name: Run example golden routes
46
+ run: uv run --frozen --extra dev skillroute eval run --fresh --index-root examples/skills --cases examples/evals/golden_routes.json
47
+
48
+ - name: Audit Python dependencies
49
+ run: |
50
+ uv export --frozen --no-emit-project --no-hashes --format requirements-txt -o requirements-audit.txt
51
+ uvx pip-audit --no-deps -r requirements-audit.txt
52
+
53
+ web:
54
+ name: Web
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - name: Check out repository
58
+ uses: actions/checkout@v7
59
+
60
+ - name: Set up Node
61
+ uses: actions/setup-node@v7
62
+ with:
63
+ node-version: "22"
64
+ cache: npm
65
+ cache-dependency-path: web/package-lock.json
66
+
67
+ - name: Install web dependencies
68
+ working-directory: web
69
+ run: npm ci
70
+
71
+ - name: Typecheck web
72
+ working-directory: web
73
+ run: npm run typecheck
74
+
75
+ - name: Lint web
76
+ working-directory: web
77
+ run: npm run lint
78
+
79
+ - name: Test web
80
+ working-directory: web
81
+ run: npm run test
82
+
83
+ - name: Build web
84
+ working-directory: web
85
+ run: npm run build
86
+
87
+ - name: Audit web dependencies
88
+ working-directory: web
89
+ run: npm audit --audit-level=high
90
+
91
+ mcp:
92
+ name: MCP
93
+ runs-on: ubuntu-latest
94
+ steps:
95
+ - name: Check out repository
96
+ uses: actions/checkout@v7
97
+
98
+ - name: Install uv
99
+ uses: astral-sh/setup-uv@v9.0.0
100
+ with:
101
+ cache-suffix: mcp
102
+
103
+ - name: Set up Python
104
+ uses: actions/setup-python@v7
105
+ with:
106
+ python-version: "3.13"
107
+
108
+ - name: Set up Node
109
+ uses: actions/setup-node@v7
110
+ with:
111
+ node-version: "22"
112
+ cache: npm
113
+ cache-dependency-path: mcp/package-lock.json
114
+
115
+ - name: Install MCP dependencies
116
+ working-directory: mcp
117
+ run: npm ci
118
+
119
+ - name: Build MCP server
120
+ working-directory: mcp
121
+ run: npm run build
122
+
123
+ - name: Typecheck MCP server
124
+ working-directory: mcp
125
+ run: npm run typecheck
126
+
127
+ - name: Test MCP server
128
+ working-directory: mcp
129
+ run: npm test
130
+
131
+ - name: Verify MCP package contents
132
+ working-directory: mcp
133
+ run: npm pack --dry-run
134
+
135
+ - name: Audit MCP dependencies
136
+ working-directory: mcp
137
+ run: npm audit --audit-level=high
138
+
139
+ - name: Smoke test MCP tools
140
+ working-directory: mcp
141
+ run: npm run smoke
142
+
143
+ package:
144
+ name: Package
145
+ runs-on: ubuntu-latest
146
+ steps:
147
+ - name: Check out repository
148
+ uses: actions/checkout@v7
149
+
150
+ - name: Install uv
151
+ uses: astral-sh/setup-uv@v9.0.0
152
+ with:
153
+ cache-suffix: package
154
+
155
+ - name: Set up Python
156
+ uses: actions/setup-python@v7
157
+ with:
158
+ python-version: "3.13"
159
+
160
+ - name: Set up Node
161
+ uses: actions/setup-node@v7
162
+ with:
163
+ node-version: "22"
164
+
165
+ - name: Build sdist and wheel
166
+ run: uv build
167
+
168
+ - name: Check distribution metadata
169
+ run: uvx twine check dist/*
170
+
171
+ - name: Verify wheel bundles the web UI
172
+ run: unzip -l dist/*.whl | grep -q "skillroute/_web/index.html"
@@ -0,0 +1,144 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ name: Build artifacts
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Check out repository
16
+ uses: actions/checkout@v7
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v9.0.0
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v7
23
+ with:
24
+ python-version: "3.13"
25
+
26
+ - name: Set up Node
27
+ uses: actions/setup-node@v7
28
+ with:
29
+ node-version: "22"
30
+
31
+ # The tag is the only thing a human types here, and the version published
32
+ # comes from package metadata, not from the tag. Without this check,
33
+ # tagging v0.2.0 while pyproject.toml still says 0.1.0 publishes 0.1.0 to
34
+ # PyPI under a release titled v0.2.0 -- and a PyPI version can never be
35
+ # reused, so there is no clean recovery.
36
+ - name: Verify the tag matches both package versions
37
+ run: |
38
+ tag="${GITHUB_REF_NAME#v}"
39
+ py=$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
40
+ npm_version=$(node -p "require('./mcp/package.json').version")
41
+ echo "tag=$tag pyproject=$py package.json=$npm_version"
42
+ if [ "$tag" != "$py" ] || [ "$tag" != "$npm_version" ]; then
43
+ echo "::error::Tag $GITHUB_REF_NAME disagrees with pyproject.toml ($py) and/or mcp/package.json ($npm_version)."
44
+ exit 1
45
+ fi
46
+
47
+ - name: Build sdist and wheel (bundles the web UI)
48
+ run: uv build
49
+
50
+ - name: Check distribution metadata
51
+ run: uvx twine check dist/*
52
+
53
+ - name: Verify wheel bundles the web UI
54
+ run: unzip -l dist/*.whl | grep -q "skillroute/_web/index.html"
55
+
56
+ - name: Pack MCP server tarball
57
+ working-directory: mcp
58
+ run: |
59
+ npm ci
60
+ npm pack --pack-destination ../dist
61
+
62
+ - name: Upload artifacts
63
+ uses: actions/upload-artifact@v6
64
+ with:
65
+ name: release-artifacts
66
+ path: dist/*
67
+
68
+ github-release:
69
+ name: Create GitHub release
70
+ needs: build
71
+ runs-on: ubuntu-latest
72
+ permissions:
73
+ contents: write
74
+ steps:
75
+ - name: Check out repository
76
+ uses: actions/checkout@v7
77
+
78
+ - name: Download artifacts
79
+ uses: actions/download-artifact@v7
80
+ with:
81
+ name: release-artifacts
82
+ path: dist
83
+
84
+ - name: Create release with artifacts
85
+ env:
86
+ GH_TOKEN: ${{ github.token }}
87
+ run: |
88
+ gh release create "$GITHUB_REF_NAME" dist/* \
89
+ --title "$GITHUB_REF_NAME" \
90
+ --generate-notes
91
+
92
+ pypi:
93
+ name: Publish to PyPI
94
+ if: vars.PYPI_PUBLISH == 'true'
95
+ needs: build
96
+ runs-on: ubuntu-latest
97
+ environment: pypi
98
+ permissions:
99
+ id-token: write
100
+ steps:
101
+ - name: Download artifacts
102
+ uses: actions/download-artifact@v7
103
+ with:
104
+ name: release-artifacts
105
+ path: dist
106
+
107
+ - name: Remove non-PyPI artifacts
108
+ run: rm -f dist/*.tgz
109
+
110
+ - name: Publish via trusted publishing
111
+ uses: pypa/gh-action-pypi-publish@release/v1
112
+
113
+ npm:
114
+ name: Publish MCP server to npm
115
+ if: vars.NPM_PUBLISH == 'true'
116
+ needs: build
117
+ runs-on: ubuntu-latest
118
+ permissions:
119
+ # npm trusted publishing is OIDC: this replaces NPM_TOKEN entirely, so
120
+ # there is no long-lived credential in repo secrets to leak or rotate.
121
+ id-token: write
122
+ steps:
123
+ - name: Check out repository
124
+ uses: actions/checkout@v7
125
+
126
+ # Trusted publishing needs npm >= 11.5.1. Node 22 bundles npm 10.x even at
127
+ # its latest patch, so it cannot be used here; Node 24 bundles 11.17+,
128
+ # which clears the floor without installing anything.
129
+ #
130
+ # Do not "fix" this by adding `npm install -g npm@latest` on Node 22: that
131
+ # is what v0.2.0's first release attempt did, and it failed with
132
+ # EBADENGINE because npm 12 requires Node ^22.22.2 || ^24.15.0 while
133
+ # setup-node had pinned 22.14.0.
134
+ - name: Set up Node
135
+ uses: actions/setup-node@v7
136
+ with:
137
+ node-version: "24"
138
+ registry-url: "https://registry.npmjs.org"
139
+
140
+ - name: Publish
141
+ working-directory: mcp
142
+ run: |
143
+ npm ci
144
+ npm publish
@@ -0,0 +1,25 @@
1
+ .coverage
2
+ .pytest_cache/
3
+ .ruff_cache/
4
+ .skillroute/
5
+ .venv/
6
+ __pycache__/
7
+ *.egg-info/
8
+ *.pyc
9
+
10
+ .env
11
+ .env.*
12
+ !.env.example
13
+
14
+ requirements-audit.txt
15
+
16
+ mcp/build/
17
+ mcp/node_modules/
18
+ web/dist/
19
+ web/node_modules/
20
+ node_modules/
21
+
22
+ dist/
23
+ .mypy_cache/
24
+ htmlcov/
25
+ coverage.xml
@@ -0,0 +1,146 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-08-13
11
+
12
+ ### Added
13
+
14
+ - **Harness packs.** Every agent tool SkillRoute supports is now one declarative
15
+ manifest in `harnesses/*.toml` describing detection, per-platform config paths,
16
+ and which install modes it offers. v0.1 encoded this as a hardcoded if/elif
17
+ chain plus a per-client detection function, so adding a tool meant editing
18
+ around seven places across two modules and three docs; adding one that fits an
19
+ existing config shape is now a data change with no Python. Six of the fourteen
20
+ shipped harnesses reuse the same shape unchanged. `tests/test_harnesses.py` is
21
+ parametrized over whatever is in `harnesses/`, so a new manifest is covered
22
+ automatically.
23
+ - Seven new harnesses: `pi`, `hermes`, `opencode`, `goose`, `gemini-cli`, `zed`,
24
+ and `amp` — joining the seven from v0.1, all migrated to manifests with
25
+ byte-identical generated output.
26
+ - Install modes beyond MCP: `acp`, `skills` (native skills-directory discovery
27
+ and projection), `hook`, `extension`, and `router_skill`. Where a harness lets
28
+ you register an extra skills directory (Hermes `external_dirs`, Pi's settings),
29
+ SkillRoute registers rather than copying — no duplication, no sync drift.
30
+ - Cross-platform config paths. Manifests declare `macos`/`linux`/`windows`
31
+ variants and the most specific match wins; `skillroute harness show --platform`
32
+ renders for a platform you are not on. v0.1 detection was macOS-only.
33
+ - `skillroute harness list | detect | show | install | doctor`, plus
34
+ [docs/harnesses.md](docs/harnesses.md) covering how to add a harness.
35
+ - `skillroute harness doctor` verifies a pack still matches reality: the manifest
36
+ declares a path for the current platform, every mode still renders, and the
37
+ config on disk names our server. It then runs the exact server command the
38
+ config points at and confirms it answers an MCP `initialize` handshake — the
39
+ one check that inspection cannot fake. Config paths for fourteen tools rot
40
+ silently, because `harness install` keeps reporting success while writing to a
41
+ file the tool no longer reads. An absent or unconfigured harness warns rather
42
+ than fails, so a non-zero exit means real breakage and the command works as a
43
+ CI gate (`--json`, `--no-probe`).
44
+ - `--server-source {local,npx}` on `harness show` and `harness install` chooses
45
+ whether a generated config starts the MCP server from a built checkout or from
46
+ the published `@skillroute/mcp-server` via `npx -y`. v0.1 hardcoded the
47
+ checkout path, which is why nothing outside a git clone could run SkillRoute.
48
+ The default stays `local` until the package is actually on npm, so this adds
49
+ the capability without emitting configs that resolve to nothing.
50
+ - Catalog schema v2 with real migration machinery. `skillroute.migrations`
51
+ defines ordered, named migrations; `Catalog.initialize()` detects the on-disk
52
+ version, takes a write lock (`BEGIN IMMEDIATE`) so a concurrent index and UI
53
+ server cannot both migrate, backs the file up before altering it, and refuses
54
+ a catalog written by a newer SkillRoute instead of corrupting it. Existing v1
55
+ catalogs upgrade in place; their traces are unpacked into the new columns
56
+ rather than discarded.
57
+ - Route traces now record who asked and what happened: `harness_id`,
58
+ `harness_version`, `surface`, `request_text`, `top_confidence`,
59
+ `second_confidence`, `catalog_fingerprint`, and the routing weights in effect.
60
+ A new `route_trace_candidates` table denormalizes every ranked candidate and
61
+ its score breakdown so analytics can use SQL instead of parsing response
62
+ blobs. `skillroute route --harness <id>` and `SKILLROUTE_HARNESS` set the
63
+ attribution; an unknown caller stays unknown rather than erroring.
64
+ - `Catalog.record_outcome()` and a `route_outcomes` table, so an agent can
65
+ report which skill it actually used. The rank it was offered at is resolved
66
+ from the recorded candidates rather than trusted from the caller.
67
+ - `route_trace_daily` aggregates every route on the day it happens. Raw traces
68
+ are still capped, but the rollup is not, so route counts, clarification rates,
69
+ and confidence distributions survive pruning and remain answerable over time.
70
+ - SQLite FTS5 retrieval backend (`--backend fts5`, alias `sqlite-fts5`):
71
+ local BM25 ranking with term-frequency and document-length normalization on
72
+ top of the existing token-overlap lexical score. Query input is escaped so
73
+ FTS5 syntax in requests is treated as literal terms. Available in the CLI,
74
+ bridge, and MCP server backend choices.
75
+ - Routing weights are now explicit and tunable: `RouteWeights` replaces the
76
+ hardcoded blend constants, `SKILLROUTE_WEIGHTS` overrides them per process,
77
+ and `skillroute eval tune` grid-searches weights against golden route cases
78
+ so changes are backed by eval evidence. Defaults are unchanged.
79
+
80
+ ### Changed
81
+
82
+ - The npm release job publishes via npm trusted publishing (OIDC) instead of a
83
+ long-lived `NPM_TOKEN` secret, so there is no static credential in repo
84
+ secrets to leak or rotate, and provenance attestations are generated
85
+ automatically. Requires `id-token: write` and npm ≥ 11.5.1, which Node 22 does
86
+ not bundle — the job upgrades npm explicitly.
87
+ - The release workflow now fails if the pushed tag disagrees with the version in
88
+ `pyproject.toml` or `mcp/package.json`. The published version comes from
89
+ package metadata rather than the tag, so tagging `v0.2.0` against a `0.1.0`
90
+ pyproject would have published `0.1.0` under a release titled `v0.2.0` — and
91
+ a PyPI version can never be reused, so there is no clean recovery.
92
+ - Skill discovery is derived from the harness manifests instead of a hardcoded
93
+ three-entry tuple, growing from 3 roots to 10 — including `~/.claude/skills`,
94
+ which v0.1 never scanned.
95
+ - Raw route-trace retention raised from 1,000 to 20,000, configurable via
96
+ `SKILLROUTE_MAX_TRACES` (`0` disables pruning). 1,000 rows was a few days of
97
+ one active harness — too short a horizon for any question about change over
98
+ time. Pruning is now amortized across inserts rather than run on every one, so
99
+ the table may sit slightly above the cap between prunes.
100
+
101
+ ### Deprecated
102
+
103
+ - `skillroute mcp config --client <id>` in favour of `skillroute harness show`
104
+ and `skillroute harness install`. Output is unchanged and the deprecation
105
+ notice goes to stderr, so `--json` stdout stays machine-parseable. The
106
+ `skillroute.client_setup` and `skillroute.mcp_setup` modules are now shims
107
+ re-exporting `skillroute.harness_setup` and `skillroute.harness_render`. All
108
+ are removed in 0.3.
109
+
110
+ ### Security
111
+
112
+ - The Skill Atlas `POST /api/route-preview` endpoint no longer accepts an
113
+ arbitrary `repo` filesystem path. Any caller who could reach the local UI
114
+ server could use it to probe the disk: the response reports whether a
115
+ directory exists, its resolved absolute path, which marker files it holds,
116
+ and how many files it contains. A `repo` is now honored only when
117
+ `SKILLROUTE_REPO_ROOT` names a base directory, and only for paths that
118
+ resolve inside it (CodeQL `py/path-injection`). The bundled UI never sent
119
+ `repo`, and the CLI's `--repo` is unaffected.
120
+
121
+ [Unreleased]: https://github.com/erichare/skill-route/compare/v0.2.0...HEAD
122
+ [0.2.0]: https://github.com/erichare/skill-route/compare/v0.1.0...v0.2.0
123
+
124
+ ## [0.1.0] - 2026-08-10
125
+
126
+ First release.
127
+
128
+ ### Added
129
+
130
+ - SKILL.md bundle indexing into a local SQLite catalog (`skillroute index`)
131
+ - Semantic routing with ranked skills, confidence, evidence snippets, suggested
132
+ order, and clarification questions (`skillroute route`)
133
+ - Hybrid search over indexed skills (`skillroute search`) and per-skill
134
+ inspection (`skillroute inspect`)
135
+ - Pluggable retrieval backends: local token backend and Astra Data API backend,
136
+ plus a LangChain retriever adapter
137
+ - Metadata overlays for curating tags, domains, and languages without editing
138
+ skill sources
139
+ - Route observability: persisted route traces (`skillroute traces list`)
140
+ - Golden route evals (`skillroute eval run`)
141
+ - Skill Atlas web UI (`skillroute ui`), bundled into the Python wheel
142
+ - MCP stdio server (`@skillroute/mcp-server`) exposing `skillroute.route`,
143
+ `skillroute.search`, and `skillroute.inspect_skill`, with client setup via
144
+ `skillroute mcp config --client <client>`
145
+
146
+ [0.1.0]: https://github.com/erichare/skill-route/releases/tag/v0.1.0
@@ -0,0 +1,55 @@
1
+ # Contributing
2
+
3
+ Thanks for your interest in SkillRoute! This page covers local development and
4
+ the release process.
5
+
6
+ ## Development setup
7
+
8
+ Requirements: [uv](https://docs.astral.sh/uv/), Node 20+.
9
+
10
+ ```bash
11
+ # Python package (src/skillroute) + tests
12
+ uv sync --extra dev
13
+ uv run --extra dev pytest --cov=skillroute --cov-fail-under=80
14
+ uv run --extra dev ruff check .
15
+ uv run --extra dev mypy
16
+
17
+ # Skill Atlas web UI
18
+ npm --prefix web ci
19
+ npm --prefix web run typecheck && npm --prefix web run lint && npm --prefix web run test
20
+
21
+ # MCP server
22
+ npm --prefix mcp ci
23
+ npm --prefix mcp run build && npm --prefix mcp test && npm --prefix mcp run smoke
24
+ ```
25
+
26
+ CI mirrors these commands plus dependency audits and a packaging check; see
27
+ [.github/workflows/ci.yml](.github/workflows/ci.yml).
28
+
29
+ ## Guidelines
30
+
31
+ - Conventional commit messages (`feat:`, `fix:`, `chore:`, ...)
32
+ - Add or update tests with behavior changes; overall coverage must stay >= 80%
33
+ - `ruff` and `mypy` must pass
34
+
35
+ ## Releasing
36
+
37
+ 1. Bump the version in `pyproject.toml`, `mcp/package.json` (and
38
+ `web/package.json` for consistency). Python code and the MCP server read
39
+ their versions from package metadata — do not hardcode versions elsewhere.
40
+ 2. Add a section to `CHANGELOG.md` and update its compare/tag links.
41
+ 3. Land those changes on `main`, then tag and push:
42
+
43
+ ```bash
44
+ git tag vX.Y.Z && git push origin vX.Y.Z
45
+ ```
46
+
47
+ 4. The [release workflow](.github/workflows/release.yml) builds the sdist,
48
+ wheel, and npm tarball, then creates a GitHub release with the artifacts
49
+ attached.
50
+ - PyPI publishing runs only when the `PYPI_PUBLISH` repository variable is
51
+ `true` and a [PyPI trusted publisher](https://docs.pypi.org/trusted-publishers/)
52
+ is configured for this repository.
53
+ - npm publishing runs only when the `NPM_PUBLISH` repository variable is
54
+ `true` and an `NPM_TOKEN` secret with publish rights to the
55
+ `@skillroute` scope is configured.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eric Hare
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.