portawhip 0.1.0
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.
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/SECURITY.md +15 -0
- package/VISION.md +281 -0
- package/adapters/hooks/hook-stub.mjs +21 -0
- package/adapters/hooks/hook-stub.test.mjs +43 -0
- package/adapters/hooks/universal-hook.mjs +348 -0
- package/adapters/hooks/universal-hook.test.mjs +294 -0
- package/adapters/instructions/generate.mjs +114 -0
- package/core/fixtures/bad-recipe.yaml +5 -0
- package/core/fixtures/capability-graph.json +10 -0
- package/core/fixtures/skill-with-metadata/SKILL.md +15 -0
- package/core/registry/capability-docs.mjs +145 -0
- package/core/registry/capability-graph-compiler.mjs +90 -0
- package/core/registry/capability-graph.mjs +53 -0
- package/core/registry/capability-kind.mjs +9 -0
- package/core/registry/cli-enrich.mjs +316 -0
- package/core/registry/cli-enrich.test.mjs +119 -0
- package/core/registry/discover.mjs +379 -0
- package/core/registry/enrich.mjs +213 -0
- package/core/registry/enrich.test.mjs +53 -0
- package/core/registry/eval-harvest.mjs +93 -0
- package/core/registry/eval-harvest.test.mjs +64 -0
- package/core/registry/registry.mjs +197 -0
- package/core/router/concept-vector.mjs +91 -0
- package/core/router/concept-vector.test.mjs +36 -0
- package/core/router/curated-trigger.test.mjs +28 -0
- package/core/router/dense-embedder.mjs +242 -0
- package/core/router/fusion.mjs +18 -0
- package/core/router/hybrid-router.mjs +375 -0
- package/core/router/intent-evidence.mjs +60 -0
- package/core/router/prompt-hygiene.mjs +31 -0
- package/core/router/route-entry.mjs +74 -0
- package/core/router/router-cli.mjs +218 -0
- package/core/router/router-cli.test.mjs +25 -0
- package/core/router/router-eval.mjs +166 -0
- package/core/router/router-live.test.mjs +89 -0
- package/core/router/router.test.mjs +838 -0
- package/core/router/scorer.mjs +72 -0
- package/core/router/sparse-retriever.mjs +79 -0
- package/core/router/tokenize.mjs +42 -0
- package/core/state/bundle-state.mjs +124 -0
- package/core/state/bundle-state.test.mjs +175 -0
- package/core/state/config.mjs +115 -0
- package/core/state/feedback.mjs +129 -0
- package/core/state/feedback.test.mjs +181 -0
- package/core/state/runtime-root.test.mjs +22 -0
- package/core/state/stack-detect.mjs +102 -0
- package/core/state/stack-detect.test.mjs +64 -0
- package/core/surface/config-sync-backends.mjs +224 -0
- package/core/surface/connector-targets.mjs +205 -0
- package/core/surface/discover-hooks.mjs +151 -0
- package/core/surface/discover-hooks.test.mjs +63 -0
- package/core/surface/discover-surface.test.mjs +49 -0
- package/core/surface/extra-hosts.mjs +48 -0
- package/core/surface/extra-hosts.test.mjs +24 -0
- package/core/surface/hook-targets.mjs +102 -0
- package/core/surface/surface-copy-targets.mjs +37 -0
- package/core/surface/surface-inventory.mjs +106 -0
- package/core/surface/surface-matrix.mjs +133 -0
- package/core/surface/surface-matrix.test.mjs +90 -0
- package/docs/router-eval-set.jsonl +38 -0
- package/hooks.manifest.yaml +16 -0
- package/package.json +101 -0
- package/recipe.yaml +247 -0
- package/recipes/foundry.yaml +27 -0
- package/recipes/manifest.yaml +18 -0
- package/recipes/roles/backend-data.yaml +26 -0
- package/recipes/roles/coding.yaml +26 -0
- package/recipes/roles/frontend.yaml +14 -0
- package/recipes/roles/research.yaml +31 -0
- package/recipes/roles/secure.yaml +27 -0
- package/router.config.yaml +120 -0
- package/scripts/bundles.mjs +131 -0
- package/scripts/doctor.mjs +117 -0
- package/scripts/embedded-hooks.mjs +27 -0
- package/scripts/hosts.mjs +60 -0
- package/scripts/link/link-connectors.mjs +190 -0
- package/scripts/link/link-connectors.test.mjs +111 -0
- package/scripts/link/link-hooks.mjs +259 -0
- package/scripts/link/link-hooks.test.mjs +112 -0
- package/scripts/link/link-surfaces.mjs +188 -0
- package/scripts/link/link-surfaces.test.mjs +76 -0
- package/scripts/load.mjs +143 -0
- package/scripts/package-contract.test.mjs +26 -0
- package/scripts/surface-inventory.mjs +6 -0
- package/scripts/sync/agents-surface.mjs +55 -0
- package/scripts/sync/agents-surface.test.mjs +18 -0
- package/scripts/sync/auto-sync.mjs +135 -0
- package/scripts/sync/auto-sync.test.mjs +41 -0
- package/scripts/sync/import-surfaces.mjs +331 -0
- package/scripts/sync/import-surfaces.test.mjs +106 -0
- package/scripts/sync/sync-config.mjs +230 -0
- package/scripts/sync/sync-config.test.mjs +141 -0
- package/scripts/sync/sync-surfaces.mjs +229 -0
- package/scripts/sync/sync-surfaces.test.mjs +66 -0
- package/scripts/tui-actions.mjs +59 -0
- package/scripts/tui-actions.test.mjs +53 -0
- package/scripts/tui.mjs +782 -0
- package/scripts/uninstall-all.mjs +39 -0
- package/server/mcp-server.mjs +129 -0
- package/server/mcp-server.test.mjs +175 -0
- package/skills/portawhip/SKILL.md +80 -0
- package/surface-matrix.yaml +93 -0
package/package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "portawhip",
|
|
3
|
+
"private": false,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "Tools collector + context-cheap router for AI agent hosts: dispatches capability install to add-mcp/mise/asm, then routes the right one at the right moment instead of loading everything into context.",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/VVeb1250/portawhip#readme",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/VVeb1250/portawhip/issues"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/VVeb1250/portawhip.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai-agents",
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"agent-tools",
|
|
21
|
+
"tool-router",
|
|
22
|
+
"claude-code",
|
|
23
|
+
"codex",
|
|
24
|
+
"gemini-cli",
|
|
25
|
+
"developer-tools"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"bin": {
|
|
31
|
+
"portawhip": "scripts/tui.mjs",
|
|
32
|
+
"portawhip-router": "core/router/router-cli.mjs",
|
|
33
|
+
"harness-router": "server/mcp-server.mjs"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"adapters/",
|
|
37
|
+
"core/",
|
|
38
|
+
"docs/router-eval-set.jsonl",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"SECURITY.md",
|
|
41
|
+
"recipes/",
|
|
42
|
+
"scripts/",
|
|
43
|
+
"server/",
|
|
44
|
+
"skills/",
|
|
45
|
+
"hooks.manifest.yaml",
|
|
46
|
+
"recipe.yaml",
|
|
47
|
+
"router.config.yaml",
|
|
48
|
+
"surface-matrix.yaml",
|
|
49
|
+
"VISION.md"
|
|
50
|
+
],
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"load": "node scripts/load.mjs",
|
|
56
|
+
"doctor": "node scripts/doctor.mjs",
|
|
57
|
+
"connectors": "node scripts/link/link-connectors.mjs status",
|
|
58
|
+
"connectors:link": "node scripts/link/link-connectors.mjs install",
|
|
59
|
+
"hooks": "node scripts/link/link-hooks.mjs status",
|
|
60
|
+
"hooks:link": "node scripts/link/link-hooks.mjs install",
|
|
61
|
+
"sync-config": "node scripts/sync/sync-config.mjs status",
|
|
62
|
+
"sync-config:preview": "node scripts/sync/sync-config.mjs preview",
|
|
63
|
+
"agents": "node scripts/sync/agents-surface.mjs",
|
|
64
|
+
"agents:connect": "node scripts/sync/agents-surface.mjs connect",
|
|
65
|
+
"agents:mcp": "node scripts/sync/agents-surface.mjs mcp",
|
|
66
|
+
"surface": "node scripts/surface-inventory.mjs",
|
|
67
|
+
"import": "node scripts/sync/import-surfaces.mjs status",
|
|
68
|
+
"import:preview": "node scripts/sync/import-surfaces.mjs preview",
|
|
69
|
+
"hooks:embedded": "node scripts/embedded-hooks.mjs",
|
|
70
|
+
"surface:sync": "node scripts/sync/sync-surfaces.mjs sync",
|
|
71
|
+
"surface:sync:check": "node scripts/sync/sync-surfaces.mjs check",
|
|
72
|
+
"surface:watch": "node scripts/sync/sync-surfaces.mjs watch",
|
|
73
|
+
"tui": "node scripts/tui.mjs",
|
|
74
|
+
"bundles": "node scripts/bundles.mjs list",
|
|
75
|
+
"bundles:status": "node scripts/bundles.mjs status",
|
|
76
|
+
"bundles:select": "node scripts/bundles.mjs select",
|
|
77
|
+
"test": "node --test",
|
|
78
|
+
"route": "node core/router/router-cli.mjs route",
|
|
79
|
+
"route:list": "node core/router/router-cli.mjs list",
|
|
80
|
+
"route:eval": "node core/router/router-cli.mjs eval --engine hybrid",
|
|
81
|
+
"route:compare": "node core/router/router-cli.mjs compare",
|
|
82
|
+
"route:graph": "node core/router/router-cli.mjs graph-compile --out .hp-state/capability-graph.json",
|
|
83
|
+
"route:enrich": "node core/router/router-cli.mjs enrich"
|
|
84
|
+
},
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"@huggingface/transformers": "^4.2.0",
|
|
87
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
88
|
+
"add-mcp": "^1.13.0",
|
|
89
|
+
"agent-skill-manager": "^2.7.0",
|
|
90
|
+
"ansi-escapes": "^7.3.0",
|
|
91
|
+
"cross-spawn": "^7.0.6",
|
|
92
|
+
"ink": "^5.2.1",
|
|
93
|
+
"js-yaml": "^4.1.0",
|
|
94
|
+
"minisearch": "^7.2.0",
|
|
95
|
+
"react": "^18.3.1"
|
|
96
|
+
},
|
|
97
|
+
"devDependencies": {
|
|
98
|
+
"@agents-dev/cli": "^0.8.9",
|
|
99
|
+
"ai-config-sync-manager": "0.1.5"
|
|
100
|
+
}
|
|
101
|
+
}
|
package/recipe.yaml
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Step 1 proof-of-concept recipe.
|
|
2
|
+
# Each entry declares WHAT capability to load, not HOW — the dispatcher
|
|
3
|
+
# picks the backend per `type` and shells out to a tool that already
|
|
4
|
+
# solves that backend well (add-mcp / mise / asm). No install logic
|
|
5
|
+
# lives in this repo.
|
|
6
|
+
- id: context7
|
|
7
|
+
type: mcp
|
|
8
|
+
source: https://mcp.context7.com/mcp
|
|
9
|
+
route:
|
|
10
|
+
triggers: ["library docs", "api docs", "documentation", "how to use", "sdk usage", "package docs"]
|
|
11
|
+
description: "Fetch current docs/examples for a library, framework, or API"
|
|
12
|
+
when: [user_prompt]
|
|
13
|
+
inject: hint
|
|
14
|
+
|
|
15
|
+
- id: ripgrep
|
|
16
|
+
type: cli
|
|
17
|
+
source: ripgrep
|
|
18
|
+
route:
|
|
19
|
+
triggers: ["search codebase", "grep", "find text in files", "regex search"]
|
|
20
|
+
description: "Fast regex search across files"
|
|
21
|
+
when: [user_prompt]
|
|
22
|
+
inject: hint
|
|
23
|
+
binary: rg
|
|
24
|
+
|
|
25
|
+
- id: pdf
|
|
26
|
+
# id matches the skill's real installed name (not "anthropic-skills") on
|
|
27
|
+
# purpose: registry.mjs dedupes curated vs. auto-discovered entries by id,
|
|
28
|
+
# and this skill also gets auto-discovered once installed (asm reports it
|
|
29
|
+
# as "pdf" in every host's skill dir). Matching ids lets the curated,
|
|
30
|
+
# deliberately-authored route win outright instead of competing on score
|
|
31
|
+
# against a separately-discovered duplicate of the same capability.
|
|
32
|
+
type: skill
|
|
33
|
+
source: github:anthropics/skills
|
|
34
|
+
path: skills/pdf
|
|
35
|
+
route:
|
|
36
|
+
triggers: ["pdf", "merge pages", "ocr", "extract table"]
|
|
37
|
+
description: "Read/merge/split/OCR PDF files"
|
|
38
|
+
when: [user_prompt]
|
|
39
|
+
inject: hint
|
|
40
|
+
|
|
41
|
+
- id: codegraph
|
|
42
|
+
# Same curated-override-wins pattern as pdf above: codegraph is already
|
|
43
|
+
# auto-discovered (installed globally as an MCP server), but it also
|
|
44
|
+
# needs a per-project .codegraph/ index before it's actually usable here.
|
|
45
|
+
# Observed live: the router suggested codegraph in THIS repo, which has
|
|
46
|
+
# no .codegraph/ — readyMarker/readyHint let the suggestion say so
|
|
47
|
+
# instead of silently implying it just works.
|
|
48
|
+
type: mcp
|
|
49
|
+
source: codegraph
|
|
50
|
+
route:
|
|
51
|
+
triggers: ["codegraph", "code graph", "call graph", "blast radius", "symbol graph"]
|
|
52
|
+
description: "MCP server: codebase knowledge graph (symbols, edges, call paths)"
|
|
53
|
+
when: [user_prompt]
|
|
54
|
+
inject: hint
|
|
55
|
+
readyMarker: ".codegraph"
|
|
56
|
+
readyHint: "codegraph init"
|
|
57
|
+
|
|
58
|
+
- id: harness-router
|
|
59
|
+
type: mcp
|
|
60
|
+
source: node
|
|
61
|
+
path: "."
|
|
62
|
+
args: ["server/mcp-server.mjs"]
|
|
63
|
+
name: harness-router
|
|
64
|
+
scope: project
|
|
65
|
+
route:
|
|
66
|
+
triggers:
|
|
67
|
+
[
|
|
68
|
+
"harness-router",
|
|
69
|
+
"portawhip",
|
|
70
|
+
"hybrid-router.mjs",
|
|
71
|
+
"sparse-retriever.mjs",
|
|
72
|
+
"router-cli.mjs",
|
|
73
|
+
"fix the router",
|
|
74
|
+
"improve the router",
|
|
75
|
+
]
|
|
76
|
+
description: "Inspect or improve this repo's harness-router/portawhip routing source"
|
|
77
|
+
when: [user_prompt]
|
|
78
|
+
inject: hint
|
|
79
|
+
action: inspect_code
|
|
80
|
+
|
|
81
|
+
- id: portawhip
|
|
82
|
+
# This repo's own management skill (skills/portawhip/SKILL.md). Curated so
|
|
83
|
+
# the router surfaces it when the user talks about importing/syncing tools
|
|
84
|
+
# across hosts. install:false — it lives in-repo and is read via the pointer,
|
|
85
|
+
# like the other instruction-backed skills below.
|
|
86
|
+
type: skill
|
|
87
|
+
source: portawhip
|
|
88
|
+
path: skills/portawhip
|
|
89
|
+
install: false
|
|
90
|
+
route:
|
|
91
|
+
triggers:
|
|
92
|
+
[
|
|
93
|
+
"import capability",
|
|
94
|
+
"import tool",
|
|
95
|
+
"sync tools across hosts",
|
|
96
|
+
"share skill across hosts",
|
|
97
|
+
"fan out to all hosts",
|
|
98
|
+
"manage portawhip",
|
|
99
|
+
"surface coverage matrix",
|
|
100
|
+
"what capabilities are synced",
|
|
101
|
+
"import newly installed",
|
|
102
|
+
]
|
|
103
|
+
description: "Manage portawhip cross-host capability sync: import, enrich, check coverage, fan out to all hosts"
|
|
104
|
+
when: [user_prompt]
|
|
105
|
+
inject: hint
|
|
106
|
+
action: read_skill
|
|
107
|
+
|
|
108
|
+
- id: workspace-surface-audit
|
|
109
|
+
type: skill
|
|
110
|
+
source: workspace-surface-audit
|
|
111
|
+
install: false
|
|
112
|
+
route:
|
|
113
|
+
triggers:
|
|
114
|
+
[
|
|
115
|
+
"ecc:harness-audit",
|
|
116
|
+
"harness audit",
|
|
117
|
+
"audit connector",
|
|
118
|
+
"audit hook",
|
|
119
|
+
"connector audit",
|
|
120
|
+
"hook audit",
|
|
121
|
+
"mcp audit",
|
|
122
|
+
"workspace surface audit",
|
|
123
|
+
"harness surface",
|
|
124
|
+
]
|
|
125
|
+
description: "Audit the active repo, MCP servers, connectors, hooks, plugins, and ECC harness surface"
|
|
126
|
+
when: [user_prompt]
|
|
127
|
+
inject: hint
|
|
128
|
+
action: read_skill
|
|
129
|
+
|
|
130
|
+
- id: ai-config-sync-manager
|
|
131
|
+
type: config-sync
|
|
132
|
+
source: ai-config-sync
|
|
133
|
+
install: false
|
|
134
|
+
route:
|
|
135
|
+
triggers:
|
|
136
|
+
[
|
|
137
|
+
"sync claude codex config",
|
|
138
|
+
"sync config",
|
|
139
|
+
"config drift",
|
|
140
|
+
"copy skills to codex",
|
|
141
|
+
"copy skills to claude",
|
|
142
|
+
"sync mcp config",
|
|
143
|
+
"sync hooks permissions",
|
|
144
|
+
"claude codex drift",
|
|
145
|
+
]
|
|
146
|
+
description: "Bidirectional Claude Code/Codex config sync via ai-config-sync-manager"
|
|
147
|
+
when: [user_prompt]
|
|
148
|
+
inject: hint
|
|
149
|
+
action: run_sync_config
|
|
150
|
+
|
|
151
|
+
- id: agent-skill-manager-sync-probe
|
|
152
|
+
type: config-sync
|
|
153
|
+
source: agent-skill-manager
|
|
154
|
+
install: false
|
|
155
|
+
route:
|
|
156
|
+
triggers:
|
|
157
|
+
[
|
|
158
|
+
"agent-skill-manager",
|
|
159
|
+
"asm providers",
|
|
160
|
+
"skill providers",
|
|
161
|
+
"skills installed across hosts",
|
|
162
|
+
"sync skills",
|
|
163
|
+
]
|
|
164
|
+
description: "Probe agent-skill-manager provider state used by the skill install backend"
|
|
165
|
+
when: [user_prompt]
|
|
166
|
+
inject: hint
|
|
167
|
+
action: run_sync_config_status
|
|
168
|
+
|
|
169
|
+
- id: agents-dotdir-sync
|
|
170
|
+
type: config-sync
|
|
171
|
+
source: agents
|
|
172
|
+
install: false
|
|
173
|
+
route:
|
|
174
|
+
triggers:
|
|
175
|
+
[
|
|
176
|
+
".agents",
|
|
177
|
+
"agents sync",
|
|
178
|
+
"agents status",
|
|
179
|
+
"single source of truth",
|
|
180
|
+
"sync all hosts",
|
|
181
|
+
"sync codex claude gemini cursor",
|
|
182
|
+
]
|
|
183
|
+
description: "Probe or run @agents-dev/cli .agents source-of-truth sync across many hosts"
|
|
184
|
+
when: [user_prompt]
|
|
185
|
+
inject: hint
|
|
186
|
+
action: run_sync_config
|
|
187
|
+
|
|
188
|
+
- id: configure-ecc
|
|
189
|
+
type: skill
|
|
190
|
+
source: configure-ecc
|
|
191
|
+
install: false
|
|
192
|
+
route:
|
|
193
|
+
triggers:
|
|
194
|
+
[
|
|
195
|
+
"update-config",
|
|
196
|
+
"update config",
|
|
197
|
+
"settings.json hook",
|
|
198
|
+
"claude code settings",
|
|
199
|
+
"codex config",
|
|
200
|
+
"mcp config",
|
|
201
|
+
"configure ecc",
|
|
202
|
+
"hook troubleshooting",
|
|
203
|
+
"fix config",
|
|
204
|
+
]
|
|
205
|
+
description: "Configure or repair ECC/Codex/Claude harness config, hooks, settings, and MCP wiring"
|
|
206
|
+
when: [user_prompt]
|
|
207
|
+
inject: hint
|
|
208
|
+
action: read_skill
|
|
209
|
+
|
|
210
|
+
- id: verification-loop
|
|
211
|
+
type: skill
|
|
212
|
+
source: verification-loop
|
|
213
|
+
install: false
|
|
214
|
+
route:
|
|
215
|
+
triggers:
|
|
216
|
+
[
|
|
217
|
+
"verify",
|
|
218
|
+
"verification",
|
|
219
|
+
"run tests",
|
|
220
|
+
"test before commit",
|
|
221
|
+
"pre commit verification",
|
|
222
|
+
"quality gate",
|
|
223
|
+
"fix bug and run tests",
|
|
224
|
+
]
|
|
225
|
+
description: "Run build/test/lint/security verification after code changes and before commits"
|
|
226
|
+
when: [user_prompt]
|
|
227
|
+
inject: hint
|
|
228
|
+
action: read_skill
|
|
229
|
+
|
|
230
|
+
- id: code-review
|
|
231
|
+
type: skill
|
|
232
|
+
source: code-review
|
|
233
|
+
install: false
|
|
234
|
+
route:
|
|
235
|
+
triggers:
|
|
236
|
+
[
|
|
237
|
+
"code-review",
|
|
238
|
+
"code review",
|
|
239
|
+
"review changed code",
|
|
240
|
+
"review before commit",
|
|
241
|
+
"bug fix review",
|
|
242
|
+
"pull request review",
|
|
243
|
+
]
|
|
244
|
+
description: "Review changed code for bugs, regressions, missing tests, and maintainability before commit"
|
|
245
|
+
when: [user_prompt]
|
|
246
|
+
inject: hint
|
|
247
|
+
action: review_code
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Foundry - whipforaweeb's recommended core bundle. Recommended, not forced:
|
|
2
|
+
# `node scripts/bundles.mjs select --foundry` opts in, `select --none` opts
|
|
3
|
+
# out at any time.
|
|
4
|
+
#
|
|
5
|
+
# Every entry here MUST carry a route: block. This is the rule that keeps
|
|
6
|
+
# this bundle from repeating the predecessor project's own gripe: a set of
|
|
7
|
+
# curated tools that installed cleanly but was never wired into behavior
|
|
8
|
+
# ("bundle harness = bench harness, not production harness" -
|
|
9
|
+
# E:\portable-harness\docs\BUNDLE.md section 7). Selecting a bundle here
|
|
10
|
+
# writes the SAME recipe-file list that both scripts/load.mjs (install) and
|
|
11
|
+
# the router/hooks (routing) read - so nothing in this file can end up
|
|
12
|
+
# installed-then-silent.
|
|
13
|
+
#
|
|
14
|
+
# ast-grep is carried over from the predecessor project's already
|
|
15
|
+
# bench-proven 0-tax core (docs/BUNDLE.md: "+69% precision/+76-97% codemod"
|
|
16
|
+
# vs plain grep/sed on structural edits) and its mise registry name was
|
|
17
|
+
# re-verified live in this repo on 2026-07-05 (`mise registry` lists
|
|
18
|
+
# `ast-grep -> aqua:ast-grep/ast-grep`).
|
|
19
|
+
- id: ast-grep
|
|
20
|
+
type: cli
|
|
21
|
+
source: ast-grep
|
|
22
|
+
route:
|
|
23
|
+
triggers: ["structural search", "ast-grep", "codemod", "rewrite code pattern", "syntax-aware search"]
|
|
24
|
+
description: "Structural, syntax-aware code search and rewrite (AST-based, not plain text)"
|
|
25
|
+
when: [user_prompt]
|
|
26
|
+
inject: hint
|
|
27
|
+
binary: ast-grep
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Bundle catalog metadata (data only, no logic) — read by
|
|
2
|
+
# `scripts/bundles.mjs list`/`status`. Every bundle here is opt-in; foundry
|
|
3
|
+
# is only "recommended", never auto-installed or auto-selected (agreed
|
|
4
|
+
# 2026-07-05: bundles recommend, they never force).
|
|
5
|
+
foundry:
|
|
6
|
+
description: "whipforaweeb's recommended core - small, cross-OS, 0-MCP. Opt-out anytime with `bundles select --none`."
|
|
7
|
+
recommended: true
|
|
8
|
+
roles:
|
|
9
|
+
secure:
|
|
10
|
+
description: "Deterministic supply-chain/secret checks (0-MCP). Pick this if your role touches dependencies, CI, or handles credentials."
|
|
11
|
+
coding:
|
|
12
|
+
description: "Code-size orientation and perf verification (0-MCP). Pick this if you write/refactor code day to day."
|
|
13
|
+
research:
|
|
14
|
+
description: "Document format conversion (0-MCP). Pick this if you work with docs, papers, or notes across formats."
|
|
15
|
+
frontend:
|
|
16
|
+
description: "JS/TS/JSON lint and format (0-MCP). Pick this if your role touches frontend or Node code."
|
|
17
|
+
backend-data:
|
|
18
|
+
description: "Query CSV/Parquet/SQLite/JSON without loading them into context (0-MCP). Pick this if your role touches data files or APIs returning JSON."
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Role: backend-data - opt-in via
|
|
2
|
+
# `node scripts/bundles.mjs select --role backend-data`.
|
|
3
|
+
# duckdb + jq are carried over from the predecessor project's already
|
|
4
|
+
# bench-proven data-query set (docs/BUNDLE.md: "+99.96% vs Read" for bulk
|
|
5
|
+
# CSV/Parquet/SQLite/JSON queries, 0 MCP). Both mise registry names
|
|
6
|
+
# re-verified live in this repo on 2026-07-05 (`mise registry`: duckdb ->
|
|
7
|
+
# aqua:duckdb/duckdb, jq -> aqua:jqlang/jq).
|
|
8
|
+
- id: duckdb
|
|
9
|
+
type: cli
|
|
10
|
+
source: duckdb
|
|
11
|
+
route:
|
|
12
|
+
triggers: ["query csv", "duckdb", "query parquet", "sql on files", "analyze large dataset"]
|
|
13
|
+
description: "Run SQL directly over CSV/Parquet/SQLite/JSON files without loading them into context"
|
|
14
|
+
when: [user_prompt]
|
|
15
|
+
inject: hint
|
|
16
|
+
binary: duckdb
|
|
17
|
+
|
|
18
|
+
- id: jq
|
|
19
|
+
type: cli
|
|
20
|
+
source: jq
|
|
21
|
+
route:
|
|
22
|
+
triggers: ["parse json", "jq", "filter json", "transform json", "query json file"]
|
|
23
|
+
description: "Slice, filter, and transform JSON from the command line"
|
|
24
|
+
when: [user_prompt]
|
|
25
|
+
inject: hint
|
|
26
|
+
binary: jq
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Role: coding - opt-in via `node scripts/bundles.mjs select --role coding`.
|
|
2
|
+
# ast-grep (structural search/rewrite) already lives in foundry, so this
|
|
3
|
+
# role covers what foundry doesn't: perf verification while coding.
|
|
4
|
+
#
|
|
5
|
+
# tokei (LOC counter) was tried and dropped live on 2026-07-05: mise's
|
|
6
|
+
# registry only offers it via a cargo build (`cargo:tokei`) or an aqua entry
|
|
7
|
+
# that itself refuses non-binary cargo packages ("package type cargo is not
|
|
8
|
+
# supported in the aqua backend") - no prebuilt binary path on this
|
|
9
|
+
# platform. That's compile-tax, the same class of problem that got
|
|
10
|
+
# `headroom-ai` rejected from the predecessor project's bundle (see
|
|
11
|
+
# E:\portable-harness\docs\BUNDLE.md: "= compile-tax ทุก host ... ขัด North
|
|
12
|
+
# Star portable"). Not forcing a Rust toolchain install for one bundle tool.
|
|
13
|
+
# No prebuilt-binary LOC-counter alternative (scc, cloc) was found in mise's
|
|
14
|
+
# registry either - open gap, not silently worked around.
|
|
15
|
+
#
|
|
16
|
+
# hyperfine's mise registry name re-verified live on 2026-07-05
|
|
17
|
+
# (`mise registry`: hyperfine -> aqua:sharkdp/hyperfine cargo:hyperfine).
|
|
18
|
+
- id: hyperfine
|
|
19
|
+
type: cli
|
|
20
|
+
source: hyperfine
|
|
21
|
+
route:
|
|
22
|
+
triggers: ["benchmark command", "hyperfine", "compare performance", "measure runtime", "how fast is this"]
|
|
23
|
+
description: "Command-line benchmarking with statistically sound comparisons"
|
|
24
|
+
when: [user_prompt]
|
|
25
|
+
inject: hint
|
|
26
|
+
binary: hyperfine
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Role: frontend - opt-in via `node scripts/bundles.mjs select --role frontend`.
|
|
2
|
+
# biome is a single-binary linter+formatter for JS/TS/JSON (fast, no Node
|
|
3
|
+
# toolchain dependency at the binary level). mise registry name re-verified
|
|
4
|
+
# live in this repo on 2026-07-05 (`mise registry`: biome ->
|
|
5
|
+
# aqua:biomejs/biome npm:@biomejs/biome).
|
|
6
|
+
- id: biome
|
|
7
|
+
type: cli
|
|
8
|
+
source: biome
|
|
9
|
+
route:
|
|
10
|
+
triggers: ["lint javascript", "biome", "format typescript", "lint frontend code", "js formatter"]
|
|
11
|
+
description: "Lint and format JS/TS/JSON (fast, single binary)"
|
|
12
|
+
when: [user_prompt]
|
|
13
|
+
inject: hint
|
|
14
|
+
binary: biome
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Role: research - opt-in via `node scripts/bundles.mjs select --role research`.
|
|
2
|
+
# pandoc handles the common research friction of converting between document
|
|
3
|
+
# formats (docs/papers/notes) without a heavyweight app. mise registry name
|
|
4
|
+
# re-verified live in this repo on 2026-07-05 (`mise registry`: pandoc ->
|
|
5
|
+
# github:jgm/pandoc).
|
|
6
|
+
- id: pandoc
|
|
7
|
+
type: cli
|
|
8
|
+
source: pandoc
|
|
9
|
+
route:
|
|
10
|
+
triggers: ["convert document", "pandoc", "markdown to pdf", "docx to markdown", "document format conversion"]
|
|
11
|
+
description: "Convert between document formats (markdown, docx, pdf, html, and more)"
|
|
12
|
+
when: [user_prompt]
|
|
13
|
+
inject: hint
|
|
14
|
+
binary: pandoc
|
|
15
|
+
|
|
16
|
+
# markitdown converts binary office/PDF documents to LLM-friendly markdown -
|
|
17
|
+
# the common research-material-ingestion step pandoc doesn't cover well
|
|
18
|
+
# (pandoc is markup<->markup; markitdown targets docx/pptx/xlsx/pdf/images
|
|
19
|
+
# specifically). Installed live via mise's pipx backend on 2026-07-05
|
|
20
|
+
# (`source: pipx:markitdown` - no short-name alias in mise's own registry,
|
|
21
|
+
# but the pipx-qualified name resolves and installs cleanly: pure Python
|
|
22
|
+
# wheels, no compiler needed, ~25MB, a few seconds).
|
|
23
|
+
- id: markitdown
|
|
24
|
+
type: cli
|
|
25
|
+
source: pipx:markitdown
|
|
26
|
+
route:
|
|
27
|
+
triggers: ["convert to markdown", "markitdown", "extract text from pdf", "docx to text", "read office document"]
|
|
28
|
+
description: "Convert docx/pptx/xlsx/pdf/images to markdown for LLM-friendly reading"
|
|
29
|
+
when: [user_prompt]
|
|
30
|
+
inject: hint
|
|
31
|
+
binary: markitdown
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Role: secure - opt-in via `node scripts/bundles.mjs select --role secure`
|
|
2
|
+
# (combine with other roles: --role secure,coding).
|
|
3
|
+
#
|
|
4
|
+
# gitleaks + osv-scanner are carried over from the predecessor project's
|
|
5
|
+
# already bench-proven secure-agent set (docs/BUNDLE.md: "tested PASS",
|
|
6
|
+
# 0 MCP, deterministic). Both mise registry names were re-verified live in
|
|
7
|
+
# this repo on 2026-07-05 (`mise registry`: gitleaks -> aqua:gitleaks/gitleaks,
|
|
8
|
+
# osv-scanner -> aqua:google/osv-scanner).
|
|
9
|
+
- id: gitleaks
|
|
10
|
+
type: cli
|
|
11
|
+
source: gitleaks
|
|
12
|
+
route:
|
|
13
|
+
triggers: ["secret scan", "gitleaks", "leaked credentials", "hardcoded secret", "api key in code"]
|
|
14
|
+
description: "Scan for hardcoded secrets/credentials before they get committed"
|
|
15
|
+
when: [user_prompt]
|
|
16
|
+
inject: hint
|
|
17
|
+
binary: gitleaks
|
|
18
|
+
|
|
19
|
+
- id: osv-scanner
|
|
20
|
+
type: cli
|
|
21
|
+
source: osv-scanner
|
|
22
|
+
route:
|
|
23
|
+
triggers: ["vulnerability scan", "osv-scanner", "dependency vulnerabilities", "cve check", "supply chain"]
|
|
24
|
+
description: "Scan dependencies for known vulnerabilities (OSV database)"
|
|
25
|
+
when: [user_prompt]
|
|
26
|
+
inject: hint
|
|
27
|
+
binary: osv-scanner
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Tunable router defaults. This is data the scorer reads at runtime —
|
|
2
|
+
# not decision logic. Missing file / missing keys fall back to the same
|
|
3
|
+
# defaults shown here (core/state/config.mjs), so this file is optional.
|
|
4
|
+
#
|
|
5
|
+
# Two thresholds, not one — curated (recipe.yaml) triggers are deliberately
|
|
6
|
+
# authored, so a single hit is trustworthy (recipeThreshold=1). Auto-
|
|
7
|
+
# discovered triggers (core/registry/discover.mjs) are inferred from free-text
|
|
8
|
+
# descriptions across 300+ installed skills and produce real single-word
|
|
9
|
+
# noise (e.g. "write" fired on "write a poem about the ocean" against
|
|
10
|
+
# writing-related skills) — verified requiring 2 distinct hits removes that
|
|
11
|
+
# false positive without losing true matches (grep/pdf/docs still route).
|
|
12
|
+
engine: hybrid
|
|
13
|
+
threshold: 2
|
|
14
|
+
recipeThreshold: 1
|
|
15
|
+
# Hybrid retrieval uses minisearch (core/router/sparse-retriever.mjs) — score scale
|
|
16
|
+
# is in the hundreds/thousands, not the small BM25-ish numbers the old
|
|
17
|
+
# hand-rolled engine produced. Two thresholds here too, for the same reason
|
|
18
|
+
# as recipeThreshold above: curated entries (recipe.yaml) need a much lower
|
|
19
|
+
# bar than auto-discovered ones. Verified empirically (docs/archive/phase2.5-verify.md):
|
|
20
|
+
# generic domain vocabulary shared across hundreds of skill docs ("architecture",
|
|
21
|
+
# "patterns") can outscore a genuine curated match (ripgrep/context7), so one
|
|
22
|
+
# global threshold can't separate "real auto match" from "noise" AND "real
|
|
23
|
+
# curated match" at the same time. Calibrated against docs/router-eval-set.jsonl:
|
|
24
|
+
# 350 clears all 18 negatives (0 false positives, including both hard prompts
|
|
25
|
+
# that regress-test the old noisy hook) while keeping all 5 original Phase-2
|
|
26
|
+
# positives; costs 4 of 7 newer p25 positives (accepted: silence > wrong guess).
|
|
27
|
+
hybridThreshold: 350
|
|
28
|
+
hybridRecipeThreshold: 130
|
|
29
|
+
# Auto-discovered MCP/CLI tools are a third bucket, not "skills with a lower
|
|
30
|
+
# bar": add-mcp/mise give no description, so their documents are just a bare
|
|
31
|
+
# name with almost nothing for generic vocabulary to falsely match against.
|
|
32
|
+
# Verified: 0 false positives from any mcp/cli-type entry across the full
|
|
33
|
+
# negative eval set, so this can sit far below hybridThreshold without risk
|
|
34
|
+
# — recovers real "use <tool>" matches (exa/github/playwright) that
|
|
35
|
+
# hybridThreshold=350 was silently dropping.
|
|
36
|
+
hybridToolThreshold: 80
|
|
37
|
+
# Optional Phase-2.5 graph. If the file is absent, graph expansion is a no-op.
|
|
38
|
+
# Schema: {"edges":[{"from":"capability-id","to":"neighbor-id","type":"related_skill","weight":1}]}
|
|
39
|
+
graphPath: .hp-state/capability-graph.json
|
|
40
|
+
graphBoost: 0.25
|
|
41
|
+
k: 5
|
|
42
|
+
# A lane (skill or tool) where the top match barely beats the runner-up is
|
|
43
|
+
# diffuse-vocabulary noise, not a genuine pick - verified against the last
|
|
44
|
+
# remaining false positive in docs/router-eval-set.jsonl: "what context
|
|
45
|
+
# signals should a router observe before injecting a skill" scores
|
|
46
|
+
# example-skill and skill-development within 0.3% of each other (both lit up
|
|
47
|
+
# by the same generic "router"/"skill"/"injecting" words shared across
|
|
48
|
+
# hundreds of skill docs), while every genuine match in the eval set has a
|
|
49
|
+
# clear top pick with no close runner-up. Swept 1.05/1.08/1.12 against the
|
|
50
|
+
# full eval set - all three give the same result (a plateau, not a knife's
|
|
51
|
+
# edge), so 1.05 is not a fragile fit to one prompt. Confirmed this doesn't
|
|
52
|
+
# fix everything: it's a geometry-of-scores fix, so it can't separate a
|
|
53
|
+
# genuinely peaked-but-wrong match (a doc that's confidently, unambiguously
|
|
54
|
+
# the top hit yet still the wrong one) - that needs a semantic signal
|
|
55
|
+
# (planned: PLAN.md Phase 4's local embedding model), not a sharper number.
|
|
56
|
+
peakednessRatio: 1.05
|
|
57
|
+
# Phase 4 semantic layer (PLAN.md): dense retrieval via BAAI/bge-m3
|
|
58
|
+
# (core/router/dense-embedder.mjs) - a second, meaning-based channel additive to the
|
|
59
|
+
# lexical one above, on by default so every user gets it with zero manual
|
|
60
|
+
# setup (no install script, no model management - transformers.js downloads
|
|
61
|
+
# and caches the model itself on first use, MIT-licensed, ~543MB quantized,
|
|
62
|
+
# 100+ languages including Thai). Exists to close the one gap threshold/
|
|
63
|
+
# margin tuning on lexical scores alone provably cannot: a genuine paraphrase
|
|
64
|
+
# with little/no shared vocabulary (docs/router-eval-set.jsonl's e2e-testing
|
|
65
|
+
# miss - "use Playwright to test login flow" vs the skill's own wording).
|
|
66
|
+
# Fails soft to a no-op whenever the model isn't reachable, so this is safe
|
|
67
|
+
# to leave on - every caller sees identical output to before whenever dense
|
|
68
|
+
# doesn't contribute. denseThreshold is on cosine similarity's own 0..1
|
|
69
|
+
# scale, never comparable to hybridThreshold's hundreds/thousands scale.
|
|
70
|
+
# The push hook (adapters/hooks/universal-hook.mjs) explicitly disables this
|
|
71
|
+
# per-call: it's a fresh subprocess per prompt, so it can't amortize a
|
|
72
|
+
# 500MB+ model load the way the long-lived MCP server/CLI can.
|
|
73
|
+
denseEnabled: true
|
|
74
|
+
# 0.6, not the more intuitive-looking 0.55 - verified live against
|
|
75
|
+
# docs/router-eval-set.jsonl with the real BGE-M3 model (not simulated): 0.55
|
|
76
|
+
# let a genuinely irrelevant agent/skill pair through on "audit why route
|
|
77
|
+
# suggestions are noisy and injected at the wrong time" (network-config-
|
|
78
|
+
# reviewer/caveman-review, both boosted over the line by
|
|
79
|
+
# actionAlignmentFactor's "review" match stacked on top of raw cosine
|
|
80
|
+
# ~0.48-0.50 - BGE-M3's ambient similarity floor for unrelated short text,
|
|
81
|
+
# not a genuine match). Swept 0.55/0.56/0.58/0.60 against the full eval set:
|
|
82
|
+
# 0.55-0.56 fail, 0.58-0.60 both clean (falsePositiveCount 0, precisionAt1/
|
|
83
|
+
# recallAt3 still 1, including the e2e-testing paraphrase this channel exists
|
|
84
|
+
# to rescue) - a real plateau, not one lucky number. Picked 0.60 for extra
|
|
85
|
+
# margin over the 0.58 edge.
|
|
86
|
+
denseThreshold: 0.6
|
|
87
|
+
# WS-A mode differentiation: the push hook sees a raw prompt without the
|
|
88
|
+
# agent's reasoned intent summary. Characterization proved lexical/dense
|
|
89
|
+
# signals cannot reliably separate meta-discussion from an actionable request,
|
|
90
|
+
# so unsolicited push is silent by default. Set PORTAWHIP_PUSH_MODE=legacy as
|
|
91
|
+
# a temporary rollback switch; pull route() remains enabled and recall-generous.
|
|
92
|
+
pushMode: silent
|
|
93
|
+
# Phase 3 push-mode hook: hard char budget per injected suggestion block
|
|
94
|
+
# (proxy for tokens — no tokenizer dependency for this). Lines are added
|
|
95
|
+
# until the next one would exceed this, so it degrades to fewer/shorter
|
|
96
|
+
# lines rather than truncating mid-line.
|
|
97
|
+
#
|
|
98
|
+
# Bumped 320 -> 640 (2026-07-06): adding actionDirective() (invocation
|
|
99
|
+
# syntax per kind, so suggestions actually get acted on) made a first-time
|
|
100
|
+
# mcp line ~265 chars on its own (the ToolSearch-fallback clause is the
|
|
101
|
+
# biggest chunk) - 320 only fit one such line even when lane-reserved
|
|
102
|
+
# results (core/router/hybrid-router.mjs) legitimately surface 2-3 relevant
|
|
103
|
+
# capabilities across skill/agent/tool lanes at once. Repeat mentions
|
|
104
|
+
# within the same session already render tersely (universal-hook.mjs's
|
|
105
|
+
# sessionSuggestedIds), so this cost is paid at most once per id per
|
|
106
|
+
# session, not every turn - 640 fits ~2 full mcp lines or a full
|
|
107
|
+
# skill+agent+tool combo comfortably.
|
|
108
|
+
pushBudgetChars: 640
|
|
109
|
+
# Push/pull asymmetry (2026-07-09 audit): push is an unsolicited interruption,
|
|
110
|
+
# pull (MCP route()) is a solicited lookup. Advisory-systems literature calls
|
|
111
|
+
# the push failure mode alert fatigue - CDSS systems with 90%+ override rates
|
|
112
|
+
# get tuned out entirely, and this repo's own feedback log was at 22/26
|
|
113
|
+
# suggestions ignored. Push therefore drops any hit below this calibrated
|
|
114
|
+
# confidence unless it's required-tier (curated recipe.yaml entries); pull
|
|
115
|
+
# keeps generous recall untouched.
|
|
116
|
+
pushMinConfidence: 0.75
|
|
117
|
+
# Interrupt budget per capability per session: full line once, terse reminder
|
|
118
|
+
# once, then silent. (Repeat-terse already existed via sessionSuggestedIds;
|
|
119
|
+
# this adds the "then shut up" cap.)
|
|
120
|
+
pushMaxMentionsPerSession: 2
|