sfp-hive 0.0.0-stage → 3.19.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/LICENSE +21 -0
- package/README.md +630 -2
- package/bin/sfp.js +577 -0
- package/package.json +52 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 siddu1004
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,631 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/banner-dark.svg">
|
|
4
|
+
<img src="assets/banner-light.svg" alt="SFP: Skills for Productivity" width="100%">
|
|
5
|
+
</picture>
|
|
6
|
+
</h1>
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
<p align="center">
|
|
9
|
+
<b>Give your AI coding agent the right skills for the job, not all of them.</b><br>
|
|
10
|
+
1065 skills, sorted by what you build. A hive picks the few each task needs, for the project in front of it, and learns from your feedback.
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<img src="https://img.shields.io/badge/version-3.19.0-0f766e?style=flat-square&labelColor=3b4350" alt="Version 3.19.0">
|
|
15
|
+
<img src="https://img.shields.io/badge/skills-1065-0f766e?style=flat-square&labelColor=3b4350" alt="1065 skills">
|
|
16
|
+
<img src="https://img.shields.io/badge/installs_into-16_IDEs-0f766e?style=flat-square&labelColor=3b4350" alt="Installs into 16 IDEs and CLIs">
|
|
17
|
+
<img src="https://img.shields.io/badge/tested_end_to_end-Claude_Code-0f766e?style=flat-square&labelColor=3b4350" alt="Tested end to end in Claude Code">
|
|
18
|
+
<img src="https://img.shields.io/badge/needs-Python_3-0f766e?style=flat-square&labelColor=3b4350" alt="Needs Python 3">
|
|
19
|
+
<img src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square&labelColor=3b4350" alt="MIT license">
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<blockquote align="center">
|
|
23
|
+
<b>SFP 3.19.0 Results at a Glance:</b><br>
|
|
24
|
+
• <b>61.9% held-out retrieval accuracy</b> (+37.2% over plain keyword search 24.7%, +14.5% over words-only 47.4%) with local <code>bge-m3</code> vectors + fast local reranking.<br>
|
|
25
|
+
• <b>92.5% format match on held-out tasks</b> (up from 57.5% cold start) tailored to user taste (animation, text, code, video) with zero hard-coded skill names.<br>
|
|
26
|
+
• <b>96.1% context token reduction</b> vs loading all skill descriptions (99.8% vs loading full library text).<br>
|
|
27
|
+
• <b>100% private, local-first intelligence</b> with personalized learning taste profiles and zero prompt telemetry leaving your workstation.<br>
|
|
28
|
+
<i>Read the complete benchmark report, 95% Wilson intervals, and disclosures in <a href="bench/RESULTS.md">bench/RESULTS.md</a>.</i>
|
|
29
|
+
</blockquote>
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<picture>
|
|
33
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/results-numbers-dark.svg">
|
|
34
|
+
<img src="assets/results-numbers-light.svg" alt="86% right skill on unseen tasks (plain search 9%); 5 of 6 pages shipped with SFP against 4 of 6 without skills; 1065 skills" width="100%">
|
|
35
|
+
</picture>
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
<p align="center">
|
|
39
|
+
<a href="#try-it-in-60-seconds"><b>Try in 60s</b></a> ·
|
|
40
|
+
<a href="#the-problem"><b>Why We Built It</b></a> ·
|
|
41
|
+
<a href="#what-sfp-does"><b>What It Does</b></a> ·
|
|
42
|
+
<a href="#see-it-choose"><b>Live Selection</b></a> ·
|
|
43
|
+
<a href="#platform-capabilities"><b>Platform Capabilities</b></a> ·
|
|
44
|
+
<a href="#why-choose-sfp"><b>Benchmark Results</b></a> ·
|
|
45
|
+
<a href="#the-proof"><b>The Proof</b></a> ·
|
|
46
|
+
<a href="#install"><b>Install</b></a>
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
## Try It in 60 Seconds
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# macOS and Linux:
|
|
53
|
+
curl -fsSL https://raw.githubusercontent.com/siddu1004/SFP/main/get.sh | sh
|
|
54
|
+
|
|
55
|
+
# Windows (PowerShell):
|
|
56
|
+
irm https://raw.githubusercontent.com/siddu1004/SFP/main/get.ps1 | iex
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Needs Python 3.8+ and Git. Installs the starter preset into every IDE found on your machine; [Install](#install) walks through every step. Restart your IDE, then prompt your agent:
|
|
60
|
+
|
|
61
|
+
> Use sfp-hive for this task: add tests for the checkout form.
|
|
62
|
+
|
|
63
|
+
The agent selects the exact skills matching your stack, explains why, and executes in sequence. When finished, feedback (`helped`, `unhelpful`) teaches the hive to choose better next time.
|
|
64
|
+
|
|
65
|
+
Uninstall cleanly anytime: `~/.sfp/SFP/install.sh uninstall` (or `.\install.ps1 uninstall` on Windows).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## The Problem
|
|
70
|
+
|
|
71
|
+
High-quality agent skills exist, but using them today forces a painful tradeoff:
|
|
72
|
+
|
|
73
|
+
- **The 58,000-Token Tax**: Agents read every installed skill description at session start. For 1065 skills, that consumes **81,931 tokens** (41% of a 200k context window) before you type a single prompt.
|
|
74
|
+
- **Dumb Search Fails Across Stacks**: Asking for "write tests" requires completely different skills in Next.js (`react-testing`), Django (`django-tdd`), or Rust (`rust-testing`). Keyword search cannot see your project structure.
|
|
75
|
+
- **Fragmented Ecosystem**: 52 upstream repositories use different file layouts, paths, and metadata formats across 16 IDEs.
|
|
76
|
+
- **Static Guesswork**: Without feedback and reinforcement learning, agent tooling repeats the same bad selections indefinitely.
|
|
77
|
+
|
|
78
|
+
<p align="center">
|
|
79
|
+
<picture>
|
|
80
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/hive-lifecycle-dark.svg">
|
|
81
|
+
<img src="assets/hive-lifecycle-light.svg" alt="Why Choose SFP Hive: Architecture Advantage" width="100%">
|
|
82
|
+
</picture>
|
|
83
|
+
</p>
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## What SFP Does
|
|
88
|
+
|
|
89
|
+
SFP brings biological collective intelligence to agent skill orchestration:
|
|
90
|
+
|
|
91
|
+
| Capability | Mechanism | Impact |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| **Curate & Unify** | 91 repositories merged into 24 categories, organized by role presets | Complete coverage across frontend, backend, security, DevOps, and AI |
|
|
94
|
+
| **Dynamic Hive Selection** | 5 scout signals (task words, project files, work phase, category, history) reach quorum | **266 tokens** carried instead of 81,931: **308x reduction** |
|
|
95
|
+
| **LinUCB Bandit & RL** | Contextual bandit exploration plus implicit reward harvesting from test runs and git commits | **91% of reported mistakes fixed** on retry |
|
|
96
|
+
| **Universal Delivery** | Native folder injection for 16 IDEs + zero-install MCP server + VS Code / Antigravity extension | Install once, run anywhere |
|
|
97
|
+
| **Unlimited Multi-Bundle Stacking** | Stack multiple workflow recipes concurrently (e.g. testing + frontend + security) with auto-deduplication | Zero limits on active bundle depth |
|
|
98
|
+
|
|
99
|
+
<p align="center">
|
|
100
|
+
<picture>
|
|
101
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/hive-architecture-dark.svg">
|
|
102
|
+
<img src="assets/hive-architecture-light.svg" alt="SFP Hive Decision Engine Architecture" width="100%">
|
|
103
|
+
</picture>
|
|
104
|
+
</p>
|
|
105
|
+
|
|
106
|
+
### How the Hive Operates
|
|
107
|
+
|
|
108
|
+
1. **Scouts (Five Signals)**: Candidate skills are scored by prompt intent, project manifests (`package.json`, `Cargo.toml`, etc.), current phase (plan, build, test, ship), category alignment, and Markov sequence history.
|
|
109
|
+
2. **Quorum Consensus**: A skill only enters the stack if backed by multiple signals or high task confidence, with strict filtering against foreign technologies.
|
|
110
|
+
3. **Cross-Inhibition (Stop Signals)**: Once a testing or design skill is chosen, overlapping alternatives are suppressed to prevent duplicate guidance.
|
|
111
|
+
4. **Division of Labor**: Roles (base, check, finish) are filled according to task needs.
|
|
112
|
+
5. **Continuous Learning**: A regularized model updates from explicit verdicts and automatic rewards (+1.0 for passing test suites, +0.5 for git commits, -0.6 for test failures).
|
|
113
|
+
6. **Meaning, Not Just Words (local models)**: With an embedding model running in LM Studio or Ollama, every skill is also a vector, and a task finds skills close to what it *means*. Meaning rescues a weak word match but never overrules one that names its skill. Nothing leaves your machine.
|
|
114
|
+
7. **Your Role**: The project's files tell the hive who you are (backend, frontend, mobile, data and ML, DevOps, embedded and hardware, web3, agent builder), and the skills of your role get a small push.
|
|
115
|
+
8. **Gaps Filled by Research**: When no skill fits, or your stack is one the library barely covers (Simulink, KiCad, Verilog...), the hive says so and offers `research_skill`: a local model searches OpenAlex, arXiv and Semantic Scholar, ranks papers by meaning, citations and recency, and writes a cited skill as a draft for you to approve. `sfp_research.py refresh <skill>` brings an existing skill up to date with newer papers, and `sfp_research.py watch` drafts skills from new research on the topics you follow, or the ones the mentor sees you leaning towards.
|
|
116
|
+
|
|
117
|
+
| Measured with nomic-embed-text v1.5 (hit / right first) | Words only | With meaning |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| Benchmark tasks (91) | 0.89 / 0.77 | 0.91 / 0.79 |
|
|
120
|
+
| The same tasks reworded by a local model, held out (35) | 0.34 / 0.23 | 0.40 / 0.26 |
|
|
121
|
+
| Project tasks (24) | 0.79 / 0.63 | 0.79 / 0.67 |
|
|
122
|
+
| Held-out project tasks (22) | 0.86 / 0.68 | 0.86 / 0.68 |
|
|
123
|
+
|
|
124
|
+
Meaning helps most when a task is said in other words, and costs about 70 ms a task. It is still far from solving rewording (0.40), and a stronger embedding model would help. Rewriting every task with a local chat model first (`SFP_REWRITE=1`) found about one more right skill per 35 tasks for 0.5 to 40 seconds a task, so it is off by default.
|
|
125
|
+
|
|
126
|
+
### Dynamic Multi-Bundle Stacking (No Limits)
|
|
127
|
+
|
|
128
|
+
Combine any number of bundles for complex, full-lifecycle workflows. Hive seamlessly stacks and deduplicates skills into clear agent execution phases:
|
|
129
|
+
|
|
130
|
+
<p align="center">
|
|
131
|
+
<picture>
|
|
132
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/hive-multibundle-dark.svg">
|
|
133
|
+
<img src="assets/hive-multibundle-light.svg" alt="Dynamic Multi-Bundle Stacking Engine" width="100%">
|
|
134
|
+
</picture>
|
|
135
|
+
</p>
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## See It Choose
|
|
140
|
+
|
|
141
|
+
The exact same prompt — *"write tests for the orders"* — executed in five distinct projects. Output is generated live by the hive:
|
|
142
|
+
|
|
143
|
+
| Your project | The hive chooses |
|
|
144
|
+
|---|---|
|
|
145
|
+
| Next.js | `react-testing`, `playwright-cli`, `application-security-testing` |
|
|
146
|
+
| Rust | `rust-testing` |
|
|
147
|
+
| .NET | `csharp-testing` |
|
|
148
|
+
| Flutter | `dart-flutter-patterns`, `flutter-dart-code-review` |
|
|
149
|
+
| Django | `django-celery`, `django-tdd` |
|
|
150
|
+
|
|
151
|
+
Notice that plain keyword search yields identical, generic results everywhere. The hive inspects project manifests so zero stacks receive tools for the wrong technology.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## How SFP Picks
|
|
158
|
+
|
|
159
|
+
The hive evaluates tasks through five progressive layers of understanding:
|
|
160
|
+
1. **Words & Fingerprints**: Fast lexical matching scored against the catalog, combined with project manifest detection (`package.json`, `Cargo.toml`, `go.mod`, etc.) so tools for foreign ecosystems are strictly discarded.
|
|
161
|
+
2. **Local Vector Meaning (`bge-m3`)**: A local embedding model converts task intents into high-dimensional vectors, rescuing vague or colloquial phrasing that doesn't share explicit keywords.
|
|
162
|
+
3. **Local Model Reranking (`lfm2-24b-a2b`)**: When words are ambiguous or weak (`SFP_RERANK=auto`), the local LLM evaluates candidate cards and selects the best fit, pushing plain-words accuracy to 50%.
|
|
163
|
+
4. **Skill Cards (`skill_cards.json`)**: Every one of the 1,065 skills has a structured card defining its output format (`code`, `text`, `animation`, `video`, `diagram`), interaction style, depth, and substitute equivalence group. Near-duplicate substitutes are never stacked together.
|
|
164
|
+
5. **Your Taste (`~/.sfp/taste.json`)**: SFP learns how you prefer to learn and build (code vs animation vs deep prose) from feedback, updating private weights with a 30-day half-life. An explicit format requested in your prompt (e.g. *"as a markdown summary"*) strictly overrides taste.
|
|
165
|
+
|
|
166
|
+
<p align="center">
|
|
167
|
+
<picture>
|
|
168
|
+
<source media="(prefers-color-scheme: dark)" srcset="bench/charts/headline-dark.svg">
|
|
169
|
+
<img src="bench/charts/headline-light.svg" alt="Held-Out Accuracy across Engines 1-6" width="100%">
|
|
170
|
+
</picture>
|
|
171
|
+
</p>
|
|
172
|
+
|
|
173
|
+
### Real Selection Examples from Benchmark 3.19.0
|
|
174
|
+
|
|
175
|
+
| What you ask | User Context / Taste | What SFP Picks | Why |
|
|
176
|
+
|---|---|---|---|
|
|
177
|
+
| *"make the api not die when flooded with requests"* | Any | `rate-limiting`, `resilience` | Plain-words colloquial request rescued by local reranker |
|
|
178
|
+
| *"check for sneaky memory leaks in go routine"* | Go project | `golang-patterns`, `golang-testing` | Lexical gap bridged by meaning & project fingerprint |
|
|
179
|
+
| *"explain how attention works in transformers"* | Visual Learner (`animation`) | `manim-video` | Learner prefers programmatic animated visual walkthroughs |
|
|
180
|
+
| *"explain how attention works in transformers"* | Reader (`text`) | `teach-me` | Reader prefers concise structured text walkthrough |
|
|
181
|
+
| *"just give me a text summary of attention mechanisms"* | Visual Learner | `teach-me` | **Explicit named form override:** User asked for text summary |
|
|
182
|
+
| *"simulate quantum teleportation with qiskit"* | Any | **Library Gap Detected** | SFP detects unmet need and suggests `sfp mentor grow` |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Choose Models
|
|
187
|
+
|
|
188
|
+
SFP is 100% local-first and works offline out of the box with LM Studio, Ollama, llama.cpp, Jan, and vLLM.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# View detected models and health
|
|
192
|
+
sfp models
|
|
193
|
+
|
|
194
|
+
# Probe active endpoints for latency and speed
|
|
195
|
+
sfp models probe
|
|
196
|
+
|
|
197
|
+
# Add an external or self-hosted API model safely
|
|
198
|
+
sfp models add deepseek-research https://api.deepseek.com/v1 deepseek-reasoner --key-env DEEPSEEK_API_KEY --research-only
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
> **Privacy Guarantee:** API keys are never stored on disk or committed to files; they are read at invocation strictly from the specified environment variable. Models marked `--research-only` are exclusively restricted to background paper reading and skill drafting - they never see your daily coding prompts.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Your Taste & The Mentor
|
|
206
|
+
|
|
207
|
+
### Inspecting and Tuning Taste
|
|
208
|
+
See your learned preference weights at any time:
|
|
209
|
+
```bash
|
|
210
|
+
# View active taste profile
|
|
211
|
+
sfp taste
|
|
212
|
+
|
|
213
|
+
# Reset learned weights back to neutral cold-start
|
|
214
|
+
sfp taste --reset
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### The Mentor Loop
|
|
218
|
+
```bash
|
|
219
|
+
# Inspect your profile, interests, and unmet library needs
|
|
220
|
+
sfp mentor
|
|
221
|
+
|
|
222
|
+
# Research and draft skills to fill identified gaps
|
|
223
|
+
sfp mentor grow
|
|
224
|
+
|
|
225
|
+
# Approve research drafts into your live skill library
|
|
226
|
+
sfp research drafts
|
|
227
|
+
sfp research approve <draft-id>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Platform Capabilities
|
|
233
|
+
|
|
234
|
+
SFP supports 16 IDEs and provides three flexible delivery modes:
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
### 1. The SFP Hive Extension (Antigravity & VS Code)
|
|
238
|
+
- **Automatic Skills**: Automatically syncs active skills to `.agents/rules/sfp-active-skills.md`. The agent consumes targeted instructions on every turn without copy-pasting.
|
|
239
|
+
- **Bundle Inspector**: Visualizes multi-skill recipes, match confidence percentages, and the exact task keyword chips driving the choice.
|
|
240
|
+
- **Local Model Router**: Manages local backends (Ollama, LM Studio, llama.cpp, vLLM) with automatic failover and zero telemetry.
|
|
241
|
+
|
|
242
|
+
### 2. Zero-Footprint MCP Server
|
|
243
|
+
- Serves all 1065 skills dynamically via standard JSON-RPC over stdio.
|
|
244
|
+
- Tools supported: `search_skills`, `get_skill`, `select_skills`, `give_feedback`, `predict_next`, and `find_api`.
|
|
245
|
+
- Zero context bloat: skills are loaded on demand only when invoked.
|
|
246
|
+
|
|
247
|
+
### 3. Native IDE Folder Sync
|
|
248
|
+
- One command installs targeted presets into native skill directories across 16 IDEs: Claude Code, Cursor, Codex, Gemini CLI, Antigravity, GitHub Copilot, Windsurf, Kiro, OpenCode, Trae, and more.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Who It Is For
|
|
253
|
+
|
|
254
|
+
| You are | Install | You get, for example | Try asking |
|
|
255
|
+
|---|---|---|---|
|
|
256
|
+
| A frontend developer | `frontend-dev` | `impeccable`, `design-taste-frontend`, `animate`, `accessibility-audit`, `break-ui` | "Critique this page and fix the hierarchy." |
|
|
257
|
+
| A backend developer | `backend-dev` | `postgres-patterns`, `database-migrations`, `api-design`, `docker-patterns`, `tdd-workflow` | "Plan a zero-downtime migration for this table." |
|
|
258
|
+
| A mobile developer | `mobile-dev` | `swiftui-patterns`, `dart-flutter-patterns`, `android-clean-architecture`, `compose-multiplatform-patterns` | "Review this Flutter screen for state-management problems." |
|
|
259
|
+
| Building agents, plugins or MCP servers | `agent-builder` | `skill-creator`, `hook-development`, `mcp-builder`, `agent-eval`, `mem-search` | "Help me design an MCP server for our ticket system." |
|
|
260
|
+
| Security-minded | `backend-dev` and `security` | `penetration-testing-with-strix`, `owasp-top-10-testing`, `find-security-vulnerabilities-in-code`, `security-review` | "Check this service against the OWASP top 10." |
|
|
261
|
+
| A founder or marketer | `business-ops` and `content-media` | `investor-materials`, `marketing-campaign`, `article-writing`, `persuasion-audit`, `price-framing` | "Draft this month's investor update." |
|
|
262
|
+
| Job hunting | `career` | `career-ops` | "Evaluate this job posting against my CV." |
|
|
263
|
+
| Using an IDE with no skills folder | the MCP server | every skill, through `search_skills` and `get_skill` | "Search SFP for a skill that fits this task." |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Why Choose SFP
|
|
268
|
+
|
|
269
|
+
Rigorous benchmarks against baselines and plain keyword search:
|
|
270
|
+
|
|
271
|
+
<picture>
|
|
272
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/results-rounds-dark.svg">
|
|
273
|
+
<img src="assets/results-rounds-light.svg" alt="Review rounds until a reviewer would ship the page: 2.8 with SFP, 3.7 with no skills" width="100%">
|
|
274
|
+
</picture>
|
|
275
|
+
|
|
276
|
+
<picture>
|
|
277
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/results-accuracy-dark.svg">
|
|
278
|
+
<img src="assets/results-accuracy-light.svg" alt="Right skill on held-out tasks: SFP hive 86%, earlier engine 64%, plain search 9%" width="100%">
|
|
279
|
+
</picture>
|
|
280
|
+
|
|
281
|
+
### Summary of Verified Results
|
|
282
|
+
|
|
283
|
+
1. **One Full Round Faster to Ship**: In blind multi-round design evaluations scored by an independent judge, agents guided by SFP shipped ready pages in **2.8 rounds** versus **3.7 rounds** unassisted.
|
|
284
|
+
2. **86% Selection Accuracy**: On 22 held-out tasks across 8 unseen projects, SFP Hive achieved **86% precision** compared to **9%** for plain keyword search.
|
|
285
|
+
3. **100% Success on Unfamiliar Tools**: When challenged with novel tools (FreeLLMAPI), unguided agents met 0 of 7 automated validation checks; with SFP skills, agents passed all 7 checks cleanly ([docs/EFFECT.md](docs/EFFECT.md)).
|
|
286
|
+
4. **Sub-6ms Speed**: Decisions execute locally in under 6 milliseconds, with zero network lag and total privacy.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## The Proof
|
|
291
|
+
|
|
292
|
+
Figures below are computed directly from this repository during the build. Reproduce with `python3 mcp/sfp_hive.py evaluate` and `python3 mcp/sfp_hive.py learning-curve`.
|
|
293
|
+
|
|
294
|
+
| Task set | Hive 3.19.0 | Earlier engine | Plain search |
|
|
295
|
+
|---|---:|---:|---:|
|
|
296
|
+
| 22 held-out tasks in 8 new projects, written first and scored once | **86%** | 64% | 9% |
|
|
297
|
+
| 24 tasks in 10 sample projects | 79% | 79% | 25% |
|
|
298
|
+
| 91 tasks with no project | 87% | 87% | 84% |
|
|
299
|
+
| Stacks with a skill for the wrong technology, all sets | 0 | 0 | 0 |
|
|
300
|
+
|
|
301
|
+
**What does it cost your agent?**
|
|
302
|
+
|
|
303
|
+
| What you install | Skills your agent can use | Skill descriptions it carries each session | Share of a 200k-token window |
|
|
304
|
+
|---|---:|---:|---:|
|
|
305
|
+
| `sfp` and `sfp-hive` only (the rest on demand) | 2 + all 1063 through them | about 266 tokens | 0.1% |
|
|
306
|
+
| `starter` preset | 174 | about 15,355 tokens | 7.7% |
|
|
307
|
+
| `frontend-dev` preset | 225 | about 16,541 tokens | 8.3% |
|
|
308
|
+
| `backend-dev` preset | 151 | about 13,382 tokens | 6.7% |
|
|
309
|
+
| `mobile-dev` preset | 84 | about 6,886 tokens | 3.4% |
|
|
310
|
+
| `agent-builder` preset | 309 | about 20,658 tokens | 10.3% |
|
|
311
|
+
| `everything` | 1065 | about 81,931 tokens | 41.0% |
|
|
312
|
+
|
|
313
|
+
**How fast is it?**
|
|
314
|
+
|
|
315
|
+
Decisions take about 6 ms inside the host process. Search takes about 0.1 ms. MCP queries execute in 3 to 5 ms once the project tree is indexed ([docs/HIVE.md](docs/HIVE.md#speed)).
|
|
316
|
+
|
|
317
|
+
> **What has not been measured.** Whether the chosen skills make your agent's finished work better across every domain. Learning is measured on a simulated user, not on real long-run use. Tasks and ground truths were written and validated by human evaluators. Token counts are estimated at 4 characters per token.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Install
|
|
322
|
+
|
|
323
|
+
This guide takes you from a bare machine to an agent that gets the right skills on its own. Every step ends with a **Check**, so you know it worked before you move on. Allow about fifteen minutes; steps 7 to 10 are optional.
|
|
324
|
+
|
|
325
|
+
| Step | What you get | Needed? |
|
|
326
|
+
|---|---|---|
|
|
327
|
+
| [1. Install the prerequisites](#1-install-the-prerequisites) | Python, Git, Node.js | Yes |
|
|
328
|
+
| [2. Get SFP](#2-get-sfp) | SFP on your machine, in `~/.sfp/SFP` | Yes |
|
|
329
|
+
| [3. Check the install](#3-check-the-install) | A health report | Yes |
|
|
330
|
+
| [4. Install skills into your tools](#4-install-skills-into-your-tools) | Skills your agent can use | Yes |
|
|
331
|
+
| [5. Add the standing instruction](#5-add-the-standing-instruction) | The agent asks the hive on every real task | Recommended |
|
|
332
|
+
| [6. Register the MCP server](#6-register-the-mcp-server) | All 1065 skills on demand, nothing copied | Recommended |
|
|
333
|
+
| [7. Install the SFP Hive extension](#7-install-the-sfp-hive-extension) | The sidebar in Antigravity or VS Code | Optional |
|
|
334
|
+
| [8. Use SFP in Antigravity](#8-use-sfp-in-antigravity) | Your first task with the hive | Use it |
|
|
335
|
+
| [9. Let the hive use local models](#9-optional-let-the-hive-use-local-models) | Meaning search, your role, skills from research | Optional |
|
|
336
|
+
| [9b. Set up the local model router](#9b-optional-set-up-the-local-model-router) | Local models first, free tiers next | Optional |
|
|
337
|
+
| [10. Extras](#10-optional-extras) | Companion apps, skills from any Git repo | Optional |
|
|
338
|
+
|
|
339
|
+
Also: [Claude Code plugin](#claude-code-plugin-instead-of-steps-2-6), [Keeping it current](#keeping-it-current), [When something is wrong](#when-something-is-wrong), [Removing everything](#removing-everything).
|
|
340
|
+
|
|
341
|
+
> **Windows:** type `python` wherever this guide says `python3`. Run the commands in PowerShell.
|
|
342
|
+
|
|
343
|
+
### 1. Install the prerequisites
|
|
344
|
+
|
|
345
|
+
| Program | Why SFP needs it | Get it | Check |
|
|
346
|
+
|---|---|---|---|
|
|
347
|
+
| Python 3.8 or newer | runs the hive, the MCP server, the router and the checks | [python.org/downloads](https://www.python.org/downloads/) (Windows: tick **Add python.exe to PATH**) | `python3 --version` |
|
|
348
|
+
| Git | downloads SFP and keeps it current | [git-scm.com/downloads](https://git-scm.com/downloads) | `git --version` |
|
|
349
|
+
| Node.js 18 or newer, with npm | only to build the SFP Hive extension (step 7) | [nodejs.org](https://nodejs.org/) | `node --version` |
|
|
350
|
+
| An agent tool | where the skills are used | Antigravity, Claude Code, Cursor, VS Code with Copilot, Windsurf, Codex, Gemini CLI, Kiro and more | |
|
|
351
|
+
| Optional: Ollama or LM Studio | local models for the router (step 9) | [ollama.com](https://ollama.com/), [lmstudio.ai](https://lmstudio.ai/) | |
|
|
352
|
+
|
|
353
|
+
**Check:** each command in the last column prints a version number. If one says "not found", install that program and open a new terminal.
|
|
354
|
+
|
|
355
|
+
### 2. Get SFP
|
|
356
|
+
|
|
357
|
+
Pick **one** of these.
|
|
358
|
+
|
|
359
|
+
**A. One line (recommended).** Downloads SFP into `~/.sfp/SFP` and installs the starter skills into every agent tool it finds, so it also does step 4 for you.
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
# macOS and Linux
|
|
363
|
+
curl -fsSL https://raw.githubusercontent.com/siddu1004/SFP/main/get.sh | sh
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
```powershell
|
|
367
|
+
# Windows PowerShell
|
|
368
|
+
irm https://raw.githubusercontent.com/siddu1004/SFP/main/get.ps1 | iex
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Running it again later updates SFP (`git pull`) and reinstalls. To use a different folder, set `SFP_DIR` first.
|
|
372
|
+
|
|
373
|
+
**B. Clone it yourself.** Use this if you want SFP somewhere else, or want to contribute.
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
git clone https://github.com/siddu1004/SFP.git
|
|
377
|
+
cd SFP
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**C. Rust.** If you have Cargo: `cargo install --git https://github.com/siddu1004/SFP.git`, then `sfp install`.
|
|
381
|
+
|
|
382
|
+
**D. NPM / NPX.** Install globally or run on demand via npm:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
npm install -g sfp-hive
|
|
386
|
+
sfp install
|
|
387
|
+
|
|
388
|
+
# Or run directly without installing:
|
|
389
|
+
npx sfp-hive install
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
When updates land on GitHub, npm users receive automatic update notifications, or can run `sfp update` (or `npx sfp-hive update`) to automatically pull updates and refresh skills. Set `SFP_AUTO_UPDATE=1` for seamless hands-free updates on every run.
|
|
393
|
+
|
|
394
|
+
**Check:** the folder exists and holds `catalog.json`:
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
ls ~/.sfp/SFP/catalog.json # A, or the folder you cloned into for B
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
All commands below are run **from the SFP folder**: `cd ~/.sfp/SFP` (or your clone).
|
|
401
|
+
|
|
402
|
+
### 3. Check the install
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
python3 mcp/sfp_hive.py doctor
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Check:** it reports Python, the catalog, the search index and the hive as working. Anything that is not names the command that fixes it.
|
|
409
|
+
|
|
410
|
+
### 4. Install skills into your tools
|
|
411
|
+
|
|
412
|
+
If you used 2A, this is done; read on only to change what is installed.
|
|
413
|
+
|
|
414
|
+
SFP has 1065 skills. Installing all of them fills a large part of your agent's context, so install a **profile** and let the hive pick the rest on demand.
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
python3 scripts/install.py list # all categories, profiles and the tools found on this machine
|
|
418
|
+
python3 scripts/install.py install # the starter profile into every tool found
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
| Profile | Categories |
|
|
422
|
+
|---|---|
|
|
423
|
+
| `starter` (default) | sfp, engineering, testing-quality, data-apis, agent-dev |
|
|
424
|
+
| `frontend-dev` | sfp, frontend, design-styles, testing-quality, engineering, data-apis |
|
|
425
|
+
| `backend-dev` | sfp, backend, languages, testing-quality, devops, security, engineering, data-apis |
|
|
426
|
+
| `mobile-dev`, `agent-builder` | see `install.py list` |
|
|
427
|
+
| `everything` | all categories (heavy) |
|
|
428
|
+
|
|
429
|
+
Useful variations:
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
python3 scripts/install.py install --profile frontend-dev --tools antigravity # one profile, one tool
|
|
433
|
+
python3 scripts/install.py install --categories frontend,security --tools cursor,codex
|
|
434
|
+
python3 scripts/install.py install --project . # into this project's tool folders instead of your home folder
|
|
435
|
+
python3 scripts/install.py install --link # symlinks, so `git pull` updates skills in place
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
`--tools` takes names such as `antigravity`, `claude`, `cursor`, `copilot`, `windsurf`, `codex`, `gemini`, `kiro`, `cline`, `roo`, `opencode`, `trae`, `qoder`; `auto` (the default) means every tool found. The installer only replaces or removes folders it created itself (they hold a `.sfp` marker); `--force` overrides that.
|
|
439
|
+
|
|
440
|
+
**Check:** restart your agent tool and ask it:
|
|
441
|
+
|
|
442
|
+
> Use sfp-hive for this task: add tests for the checkout form.
|
|
443
|
+
|
|
444
|
+
It names a few skills that fit your project, says why, and follows them in order.
|
|
445
|
+
|
|
446
|
+
### 5. Add the standing instruction
|
|
447
|
+
|
|
448
|
+
This tells the agent to consult the hive on every substantial task, without you asking each time.
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
python3 scripts/install.py rules # every tool found (Antigravity: ~/.gemini/GEMINI.md)
|
|
452
|
+
python3 scripts/install.py rules --project . # only this project (AGENTS.md)
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Check:** the file named in the output contains an SFP section. Undo with `--remove`.
|
|
456
|
+
|
|
457
|
+
### 6. Register the MCP server
|
|
458
|
+
|
|
459
|
+
The MCP server lets any MCP client search and read all 1065 skills on demand, with nothing copied into your tools.
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
python3 scripts/install.py mcp # every tool found
|
|
463
|
+
python3 scripts/install.py mcp --tools antigravity # Antigravity only: ~/.gemini/config/mcp_config.json
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
It registers a server called `sfp` that runs `mcp/sfp_mcp.py`. The agent gets tools such as `select_skills`, `search_skills`, `get_skill`, `use_skill`, `find_api`, `predict_next` and `give_feedback`.
|
|
467
|
+
|
|
468
|
+
**Check:** restart the tool; `sfp` is listed among its MCP servers, with its tools. Undo with `--remove`.
|
|
469
|
+
|
|
470
|
+
### 7. Install the SFP Hive extension
|
|
471
|
+
|
|
472
|
+
The sidebar for Antigravity and other VS Code-based editors: choose skills for a task, browse the library, see what the hive learned, and run the model router.
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
python3 extensions/antigravity-hive/install.py # build, test, package, install into every editor found
|
|
476
|
+
python3 extensions/antigravity-hive/install.py --editor antigravity # one editor only
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
It builds the `.vsix`, runs the extension's tests, and installs it with the editor's own `--install-extension` command. If no editor command is on your PATH, it prints the manual steps: in the editor, open **Extensions** → **...** → **Install from VSIX...** and pick the built file (a `.vsix` from a GitHub release works the same way).
|
|
480
|
+
|
|
481
|
+
Then reload the editor: `Ctrl+Shift+P` (macOS: `Cmd+Shift+P`) → **Developer: Reload Window**.
|
|
482
|
+
|
|
483
|
+
**Check:**
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
python3 extensions/antigravity-hive/verify.py --editor antigravity
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Every line says `PASS`. In the editor, the hexagon **SFP Hive** icon is in the activity bar; open it, go to **Insights** → **Check connection**, and every indicator is green.
|
|
490
|
+
|
|
491
|
+
### 8. Use SFP in Antigravity
|
|
492
|
+
|
|
493
|
+
Open the **SFP Hive** icon in the activity bar. It has three views: **SFP Hive** (the studio), **Skill Library** and **Models**. The studio has four tabs:
|
|
494
|
+
|
|
495
|
+
| Tab | What it is for |
|
|
496
|
+
|---|---|
|
|
497
|
+
| **Now** | Follows your work (saved files, test runs, commits) to tell which phase you are in, and shows the skills and bundle for it |
|
|
498
|
+
| **Choose** | Type a task; the hive picks a few skills and orders them. Click one to see why it was chosen, `+` to pin another, `x` to drop one |
|
|
499
|
+
| **Library** | Browse all 1065 skills by area, goal, bundle and cluster; open a skill, pin it or add it to a bundle |
|
|
500
|
+
| **Insights** | What the hive has learned from your feedback, and **Check connection** |
|
|
501
|
+
|
|
502
|
+

|
|
503
|
+
|
|
504
|
+
There are three ways to get the skills to the agent:
|
|
505
|
+
|
|
506
|
+
1. **Automatic (default).** Whenever you choose a task, or **Now** sees a new phase, the extension writes the skills to `.agents/rules/sfp-active-skills.md` in your workspace. The agent reads that rule on every turn, so there is nothing to paste. Turn it off with **SFP Hive: Turn automatic skills on or off**.
|
|
507
|
+
2. **Chat.** Mention `@hive` in the chat panel: `@hive write unit tests for payment processing`.
|
|
508
|
+
3. **MCP tools** (step 6). The agent calls `select_skills` itself.
|
|
509
|
+
|
|
510
|
+
After a task, tell the hive how it went: **This skill helped** / **This skill did not help** in the sidebar, or `give_feedback` through MCP. That is how it chooses better next time.
|
|
511
|
+
|
|
512
|
+
Useful commands (`Ctrl+Shift+P`, then type "SFP Hive"): **Choose skills for a task**, **Show current agent skills and phase**, **Search skills**, **Apply a bundle**, **Copy the agent prompt**, **Check connection**, **Add a skill from Git**.
|
|
513
|
+
|
|
514
|
+
### 9. Optional: let the hive use local models
|
|
515
|
+
|
|
516
|
+
Load an embedding model in LM Studio or Ollama (for example `nomic-embed-text`), then embed the library once:
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
python3 mcp/sfp_embed.py build # about a minute; later runs only embed what changed
|
|
520
|
+
python3 mcp/sfp_role.py . # your role, read from this project, and the stacks the library covers thinly
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
The hive then matches tasks by meaning as well as words, on its own. When it reports a gap, draft a skill from research (any loaded chat model writes it; only the search queries leave your machine):
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
python3 mcp/sfp_research.py draft "tune the PI controller of a buck converter" --role embedded-hardware
|
|
527
|
+
python3 mcp/sfp_research.py approve <name> --install antigravity # after you have read the draft
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
**Check:** `python3 mcp/sfp_hive.py doctor` shows **Meaning search** with every skill embedded. `SFP_SEMANTIC=0` turns all of this off.
|
|
531
|
+
|
|
532
|
+
### 9b. Optional: set up the local model router
|
|
533
|
+
|
|
534
|
+
An OpenAI-compatible router on `127.0.0.1:8787` that sends requests to your local models first, then free tiers, then paid ones, and moves to the next model when one is rate limited, out of quota or down.
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
python3 mcp/sfp_route.py discover # find models running here (Ollama, LM Studio, llama.cpp, Jan, vLLM)
|
|
538
|
+
python3 mcp/sfp_route.py setup --yes # write the routes from what was found and the API keys you have set
|
|
539
|
+
python3 mcp/sfp_route.py serve # run it; leave this terminal open
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Point any tool that takes a custom OpenAI endpoint at it: base URL `http://127.0.0.1:8787/v1`, any API key (for example `sfp`), model `auto` (or `sfp/light`, `sfp/normal`, `sfp/heavy`). The **Models** view in the sidebar can start, stop and set it up too.
|
|
543
|
+
|
|
544
|
+
**Check:** `python3 mcp/sfp_route.py status` lists your models as ready.
|
|
545
|
+
|
|
546
|
+
### 10. Optional: extras
|
|
547
|
+
|
|
548
|
+
**Programs some skills need** (OmniRoute, FreeLLMAPI, Strix):
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
python3 scripts/install.py apps list
|
|
552
|
+
python3 scripts/install.py apps install omniroute # shows the plan and changes nothing
|
|
553
|
+
python3 scripts/install.py apps install omniroute --yes # runs it
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Turn any Git repository into a skill:** in the Library tab press **+** and paste a URL, `owner/repo` or a folder; or
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
python3 scripts/repo_to_skill.py https://github.com/owner/repo --install antigravity
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
The skill is written to `~/.sfp/skills/<name>/` and copied into the tool you name.
|
|
563
|
+
|
|
564
|
+
### Claude Code plugin (instead of steps 2-6)
|
|
565
|
+
|
|
566
|
+
In Claude Code:
|
|
567
|
+
|
|
568
|
+
```text
|
|
569
|
+
/plugin marketplace add siddu1004/SFP
|
|
570
|
+
/plugin install sfp@sfp
|
|
571
|
+
/plugin install frontend@sfp
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
`sfp` is the router and hive; add the category plugins you want (`frontend`, `backend`, `testing-quality`, ...). **Check:** `/plugin` lists them as installed.
|
|
575
|
+
|
|
576
|
+
### Keeping it current
|
|
577
|
+
|
|
578
|
+
```bash
|
|
579
|
+
cd ~/.sfp/SFP
|
|
580
|
+
git pull
|
|
581
|
+
python3 scripts/install.py install # with the same options you used before
|
|
582
|
+
python3 extensions/antigravity-hive/install.py # if you use the extension
|
|
583
|
+
python3 mcp/sfp_hive.py doctor
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Re-running the one-line command from step 2A does the first three for you.
|
|
587
|
+
|
|
588
|
+
### When something is wrong
|
|
589
|
+
|
|
590
|
+
| You see | Do this |
|
|
591
|
+
|---|---|
|
|
592
|
+
| `python3` or `python`: not found | Install Python (step 1); on Windows, reinstall with **Add python.exe to PATH** ticked, then open a new terminal |
|
|
593
|
+
| `git is required` | Install Git (step 1) and open a new terminal |
|
|
594
|
+
| The agent does not mention any skills | Restart the tool after installing; run step 5 so it consults the hive on its own |
|
|
595
|
+
| "SFP checkout not found" in the sidebar | Set the `sfpHive.sfpPath` setting to your SFP folder, then reload the window |
|
|
596
|
+
| No SFP Hive icon after installing the extension | **Developer: Reload Window**; then `python3 extensions/antigravity-hive/verify.py` names what is missing |
|
|
597
|
+
| The Library tab stays on "Loading" | Update the extension to 0.3.0 or newer (step 7) and reload |
|
|
598
|
+
| The agent uses other skills than the sidebar shows | Choose the task again; check `.agents/rules/sfp-active-skills.md` exists in the workspace and automatic skills are on |
|
|
599
|
+
| Search index: stale | `python3 scripts/sync.py`, or `git pull` |
|
|
600
|
+
| `sfp` missing from the MCP servers | Run step 6 again for that tool and restart it |
|
|
601
|
+
| Router: not running | `python3 mcp/sfp_route.py serve` in a terminal you leave open |
|
|
602
|
+
| Local models: none found | Start Ollama (port 11434) or LM Studio's server (port 1234), then `sfp_route.py discover` |
|
|
603
|
+
| Anything else | `python3 mcp/sfp_hive.py doctor` names the failing part and the command that fixes it |
|
|
604
|
+
|
|
605
|
+
### Removing everything
|
|
606
|
+
|
|
607
|
+
```bash
|
|
608
|
+
cd ~/.sfp/SFP
|
|
609
|
+
python3 scripts/install.py uninstall # the skills SFP installed (and nothing else)
|
|
610
|
+
python3 scripts/install.py mcp --remove # the MCP server entries
|
|
611
|
+
python3 scripts/install.py rules --remove # the standing instruction
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
Uninstall **SFP Hive** from the editor's Extensions view. Your history, feedback and settings are in `~/.sfp`; delete that folder to remove them and SFP itself.
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## Supported IDEs
|
|
619
|
+
|
|
620
|
+
Claude Code, Codex, Cursor, Gemini CLI, Antigravity, GitHub Copilot, VS Code, Windsurf, Kiro, OpenCode, Pi, Grok Build, Qoder, Trae, Rovo Dev, Mistral Vibe, and Hermes.
|
|
621
|
+
|
|
622
|
+
Install into specific tools:
|
|
623
|
+
```bash
|
|
624
|
+
./install.sh --tools claude,cursor,antigravity,codex
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## Sources and Licenses
|
|
630
|
+
|
|
631
|
+
SFP's selection engine, installer, and MCP server are licensed under the [MIT License](LICENSE). Each skill preserves the license and copyright of its original upstream author. Detailed attributions are cataloged in [NOTICE.md](NOTICE.md) and [SKILLS.md](SKILLS.md).
|
package/bin/sfp.js
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SFP (Skills for Productivity) CLI & MCP Runner
|
|
5
|
+
* Cross-platform entry point for npx / global npm install.
|
|
6
|
+
* Includes automated update notifications and self-update capabilities.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { spawn, spawnSync } = require('child_process');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
const https = require('https');
|
|
14
|
+
|
|
15
|
+
const PKG_DIR = path.resolve(__dirname, '..');
|
|
16
|
+
const REPO_URL = 'https://github.com/siddu1004/SFP.git';
|
|
17
|
+
const GITHUB_API_TAGS = 'https://api.github.com/repos/siddu1004/SFP/tags';
|
|
18
|
+
const NPM_REGISTRY_LATEST = 'https://registry.npmjs.org/sfp-hive/latest';
|
|
19
|
+
const UPDATE_CHECK_INTERVAL_MS = 30 * 60 * 1000; // 30 minutes
|
|
20
|
+
|
|
21
|
+
function getLatestReleaseTag(rootDir) {
|
|
22
|
+
const res = spawnSync('git', ['-C', rootDir, 'tag', '-l', 'v*'], { encoding: 'utf-8' });
|
|
23
|
+
if (res.status === 0 && res.stdout) {
|
|
24
|
+
const lines = res.stdout.trim().split(/\r?\n/);
|
|
25
|
+
const tags = [];
|
|
26
|
+
for (const line of lines) {
|
|
27
|
+
const m = line.trim().match(/^v(\d+)\.(\d+)\.(\d+)$/);
|
|
28
|
+
if (m) {
|
|
29
|
+
tags.push({
|
|
30
|
+
raw: line.trim(),
|
|
31
|
+
sem: [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)]
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
tags.sort((a, b) => {
|
|
36
|
+
for (let i = 0; i < 3; i++) {
|
|
37
|
+
if (b.sem[i] !== a.sem[i]) return b.sem[i] - a.sem[i];
|
|
38
|
+
}
|
|
39
|
+
return 0;
|
|
40
|
+
});
|
|
41
|
+
if (tags.length > 0) return tags[0].raw;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Whether release tag vX.Y.Z is newer than the SFP checked out in rootDir: an update never moves back to an older
|
|
47
|
+
// release (the newest tag can lag behind main until the next release is tagged).
|
|
48
|
+
function isNewerRelease(tag, rootDir) {
|
|
49
|
+
const m = (tag || '').match(/^v(\d+)\.(\d+)\.(\d+)$/);
|
|
50
|
+
if (!m) return false;
|
|
51
|
+
let mine = null;
|
|
52
|
+
try {
|
|
53
|
+
const v = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8')).version || '';
|
|
54
|
+
const mm = v.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
55
|
+
if (mm) mine = [1, 2, 3].map((i) => parseInt(mm[i], 10));
|
|
56
|
+
} catch {}
|
|
57
|
+
if (!mine) return true;
|
|
58
|
+
for (let i = 0; i < 3; i++) {
|
|
59
|
+
const t = parseInt(m[i + 1], 10);
|
|
60
|
+
if (t !== mine[i]) return t > mine[i];
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function findPython() {
|
|
66
|
+
const candidates = process.platform === 'win32'
|
|
67
|
+
? ['python3', 'python', 'py -3', 'py']
|
|
68
|
+
: ['python3', 'python'];
|
|
69
|
+
|
|
70
|
+
for (const cmd of candidates) {
|
|
71
|
+
try {
|
|
72
|
+
const parts = cmd.split(' ');
|
|
73
|
+
const bin = parts[0];
|
|
74
|
+
const testArgs = parts.slice(1).concat(['-c', 'import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)']);
|
|
75
|
+
const res = spawnSync(bin, testArgs, { stdio: 'ignore' });
|
|
76
|
+
if (res.status === 0) {
|
|
77
|
+
return { bin, extraArgs: parts.slice(1) };
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
// Continue to next candidate
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function getUpdateCachePath() {
|
|
87
|
+
const dir = path.join(os.homedir(), '.sfp');
|
|
88
|
+
return path.join(dir, 'update_check.json');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function readUpdateCache() {
|
|
92
|
+
try {
|
|
93
|
+
const file = getUpdateCachePath();
|
|
94
|
+
if (fs.existsSync(file)) {
|
|
95
|
+
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
96
|
+
}
|
|
97
|
+
} catch {}
|
|
98
|
+
return { lastChecked: 0, hasUpdate: false };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function writeUpdateCache(data) {
|
|
102
|
+
try {
|
|
103
|
+
const file = getUpdateCachePath();
|
|
104
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
105
|
+
fs.writeFileSync(file, JSON.stringify(data, null, 2), 'utf-8');
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function fetchJson(url, headers = {}) {
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
111
|
+
const req = https.get(url, {
|
|
112
|
+
headers: {
|
|
113
|
+
'User-Agent': 'sfp-cli',
|
|
114
|
+
...headers
|
|
115
|
+
},
|
|
116
|
+
timeout: 4000
|
|
117
|
+
}, (res) => {
|
|
118
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
119
|
+
return resolve(fetchJson(res.headers.location, headers));
|
|
120
|
+
}
|
|
121
|
+
if (res.statusCode !== 200) {
|
|
122
|
+
return reject(new Error(`HTTP ${res.statusCode}`));
|
|
123
|
+
}
|
|
124
|
+
let raw = '';
|
|
125
|
+
res.on('data', chunk => { raw += chunk; });
|
|
126
|
+
res.on('end', () => {
|
|
127
|
+
try {
|
|
128
|
+
resolve(JSON.parse(raw));
|
|
129
|
+
} catch (e) {
|
|
130
|
+
reject(e);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
req.on('error', reject);
|
|
135
|
+
req.on('timeout', () => {
|
|
136
|
+
req.destroy();
|
|
137
|
+
reject(new Error('timeout'));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function isSemverNewer(remote, local) {
|
|
143
|
+
if (!remote || !local) return false;
|
|
144
|
+
const parse = v => (String(v).replace(/^v/, '').split('.').map(x => parseInt(x, 10) || 0));
|
|
145
|
+
const r = parse(remote);
|
|
146
|
+
const l = parse(local);
|
|
147
|
+
for (let i = 0; i < 3; i++) {
|
|
148
|
+
const rv = r[i] || 0;
|
|
149
|
+
const lv = l[i] || 0;
|
|
150
|
+
if (rv > lv) return true;
|
|
151
|
+
if (rv < lv) return false;
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function checkRemoteUpdate(rootDir) {
|
|
157
|
+
let remoteCommit = '';
|
|
158
|
+
let localCommit = '';
|
|
159
|
+
let remoteVersion = '';
|
|
160
|
+
let localVersion = '';
|
|
161
|
+
let hasUpdate = false;
|
|
162
|
+
|
|
163
|
+
// 1. Check local commit / version
|
|
164
|
+
try {
|
|
165
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PKG_DIR, 'package.json'), 'utf-8'));
|
|
166
|
+
localVersion = pkg.version || '';
|
|
167
|
+
} catch {}
|
|
168
|
+
|
|
169
|
+
if (fs.existsSync(path.join(rootDir, '.git'))) {
|
|
170
|
+
const rev = spawnSync('git', ['-C', rootDir, 'rev-parse', 'HEAD'], { encoding: 'utf-8' });
|
|
171
|
+
if (rev.status === 0 && rev.stdout) {
|
|
172
|
+
localCommit = rev.stdout.trim();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 2. Check GitHub remote commit
|
|
177
|
+
try {
|
|
178
|
+
const commitData = await fetchJson(GITHUB_API_COMMITS);
|
|
179
|
+
if (commitData && commitData.sha) {
|
|
180
|
+
remoteCommit = commitData.sha;
|
|
181
|
+
if (localCommit && !remoteCommit.startsWith(localCommit) && !localCommit.startsWith(remoteCommit)) {
|
|
182
|
+
hasUpdate = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} catch {}
|
|
186
|
+
|
|
187
|
+
// 3. Check npm registry version
|
|
188
|
+
try {
|
|
189
|
+
const npmData = await fetchJson(NPM_REGISTRY_LATEST);
|
|
190
|
+
if (npmData && npmData.version) {
|
|
191
|
+
remoteVersion = npmData.version;
|
|
192
|
+
if (localVersion && isSemverNewer(remoteVersion, localVersion)) {
|
|
193
|
+
hasUpdate = true;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch {}
|
|
197
|
+
|
|
198
|
+
const cache = {
|
|
199
|
+
lastChecked: Date.now(),
|
|
200
|
+
hasUpdate,
|
|
201
|
+
remoteCommit: remoteCommit.slice(0, 7),
|
|
202
|
+
localCommit: localCommit.slice(0, 7),
|
|
203
|
+
remoteVersion,
|
|
204
|
+
localVersion
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
writeUpdateCache(cache);
|
|
208
|
+
return cache;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function spawnBackgroundUpdateCheck(rootDir) {
|
|
212
|
+
try {
|
|
213
|
+
const child = spawn(process.execPath, [__filename, '__bg_check_update', rootDir], {
|
|
214
|
+
detached: true,
|
|
215
|
+
stdio: 'ignore'
|
|
216
|
+
});
|
|
217
|
+
child.unref();
|
|
218
|
+
} catch {}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function printUpdateNotice(info) {
|
|
222
|
+
const localRef = info.localVersion || (info.localCommit ? info.localCommit.slice(0, 7) : 'installed');
|
|
223
|
+
const remoteRef = info.remoteVersion || (info.remoteCommit ? info.remoteCommit.slice(0, 7) : 'latest');
|
|
224
|
+
const line1 = ` Update available! SFP repository has updates: ${localRef} -> ${remoteRef} `;
|
|
225
|
+
const line2 = ` Run 'sfp update' or 'npx sfp-hive update' to automatically update. `;
|
|
226
|
+
const len = Math.max(line1.length, line2.length);
|
|
227
|
+
const border = '─'.repeat(len);
|
|
228
|
+
const pad1 = ' '.repeat(len - line1.length);
|
|
229
|
+
const pad2 = ' '.repeat(len - line2.length);
|
|
230
|
+
|
|
231
|
+
console.error('\n\x1b[33m┌' + border + '┐\x1b[0m');
|
|
232
|
+
console.error('\x1b[33m│\x1b[0m\x1b[1m\x1b[32m' + line1 + pad1 + '\x1b[0m\x1b[33m│\x1b[0m');
|
|
233
|
+
console.error('\x1b[33m│\x1b[0m\x1b[36m' + line2 + pad2 + '\x1b[0m\x1b[33m│\x1b[0m');
|
|
234
|
+
console.error('\x1b[33m└' + border + '┘\x1b[0m\n');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function handleUpdate(rootDir, py, args) {
|
|
238
|
+
console.error('\x1b[1m\x1b[36m=== SFP Updater ===\x1b[0m\n');
|
|
239
|
+
const git = (...a) => spawnSync('git', ['-C', rootDir, '-c', 'core.longpaths=true', ...a], { encoding: 'utf-8' });
|
|
240
|
+
|
|
241
|
+
// 1. Pull latest repository changes
|
|
242
|
+
if (fs.existsSync(path.join(rootDir, '.git'))) {
|
|
243
|
+
console.error('\x1b[36m[1/3] Pulling latest repository updates from GitHub...\x1b[0m');
|
|
244
|
+
const status = git('status', '--porcelain').stdout.trim();
|
|
245
|
+
if (status) {
|
|
246
|
+
console.error('\x1b[33m Note: Working directory has local modifications; skipping git checkout to preserve local edits.\x1b[0m');
|
|
247
|
+
} else {
|
|
248
|
+
console.error(' Fetching release tags...');
|
|
249
|
+
git('fetch', '--tags', 'origin');
|
|
250
|
+
const latestTag = getLatestReleaseTag(rootDir);
|
|
251
|
+
if (latestTag) {
|
|
252
|
+
const curr = git('describe', '--tags', '--exact-match');
|
|
253
|
+
const currTag = (curr.stdout || '').trim();
|
|
254
|
+
if (currTag === latestTag) {
|
|
255
|
+
console.error(` \x1b[32m✔ Already on latest release tag ${latestTag}.\x1b[0m`);
|
|
256
|
+
} else if (!isNewerRelease(latestTag, rootDir)) {
|
|
257
|
+
console.error(` \x1b[32m✔ This copy is already newer than the latest release tag ${latestTag}; staying on it.\x1b[0m`);
|
|
258
|
+
} else {
|
|
259
|
+
console.error(` Checking out latest release tag ${latestTag}...`);
|
|
260
|
+
const co = git('checkout', latestTag);
|
|
261
|
+
if (co.status === 0) {
|
|
262
|
+
console.error(` \x1b[32m✔ Checked out latest release tag ${latestTag}.\x1b[0m`);
|
|
263
|
+
} else {
|
|
264
|
+
console.error(' \x1b[33mWarning: git checkout failed:\x1b[0m', (co.stderr || co.stdout).trim());
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
console.error(' No release tags found matching vX.Y.Z.');
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
console.error('\x1b[36m[1/3] SFP directory is not a git repository; skipping git pull.\x1b[0m');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// 2. Refresh installed skills in detected IDEs
|
|
276
|
+
console.error('\n\x1b[36m[2/3] Refreshing installed skills into detected IDEs and tools...\x1b[0m');
|
|
277
|
+
const installScript = path.join(rootDir, 'scripts', 'install.py');
|
|
278
|
+
const passArgs = args.filter(a => a !== 'update');
|
|
279
|
+
const installRes = spawnSync(py.bin, [...py.extraArgs, installScript, 'install', ...passArgs], {
|
|
280
|
+
cwd: rootDir,
|
|
281
|
+
stdio: 'inherit',
|
|
282
|
+
env: {
|
|
283
|
+
...process.env,
|
|
284
|
+
PYTHONIOENCODING: 'utf-8',
|
|
285
|
+
PYTHONUTF8: '1',
|
|
286
|
+
PYTHONPATH: [path.join(rootDir, 'mcp'), process.env.PYTHONPATH].filter(Boolean).join(path.delimiter)
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// 3. Check npm package status
|
|
291
|
+
console.error('\n\x1b[36m[3/3] Checking npm CLI package status...\x1b[0m');
|
|
292
|
+
try {
|
|
293
|
+
const npmOutdated = spawnSync('npm', ['outdated', '-g', 'sfp-hive', '--json'], { encoding: 'utf-8' });
|
|
294
|
+
if (npmOutdated.stdout && npmOutdated.stdout.includes('sfp-hive')) {
|
|
295
|
+
console.error('\x1b[33m Notice: A newer sfp-hive npm package is available!\x1b[0m');
|
|
296
|
+
console.error(' Run: \x1b[32mnpm install -g sfp-hive\x1b[0m to update the global binary.\n');
|
|
297
|
+
} else {
|
|
298
|
+
console.error(' \x1b[32m✔ npm CLI package is up to date.\x1b[0m');
|
|
299
|
+
}
|
|
300
|
+
} catch {}
|
|
301
|
+
|
|
302
|
+
// Reset update check cache
|
|
303
|
+
writeUpdateCache({
|
|
304
|
+
lastChecked: Date.now(),
|
|
305
|
+
hasUpdate: false,
|
|
306
|
+
remoteCommit: '',
|
|
307
|
+
localCommit: ''
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
console.error('\n\x1b[1m\x1b[32m✔ SFP is fully up to date!\x1b[0m\n');
|
|
311
|
+
process.exit(installRes.status ?? 0);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function resolveSfpRoot() {
|
|
315
|
+
// 1. If running inside a full SFP repository checkout, use it directly
|
|
316
|
+
if (fs.existsSync(path.join(PKG_DIR, 'catalog.json')) && fs.existsSync(path.join(PKG_DIR, 'mcp', 'sfp_hive.py'))) {
|
|
317
|
+
return PKG_DIR;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// 2. Check ~/.sfp/root pointer written by install.py
|
|
321
|
+
const rootPointer = path.join(os.homedir(), '.sfp', 'root');
|
|
322
|
+
if (fs.existsSync(rootPointer)) {
|
|
323
|
+
try {
|
|
324
|
+
const pointed = fs.readFileSync(rootPointer, 'utf-8').trim();
|
|
325
|
+
if (pointed && fs.existsSync(path.join(pointed, 'catalog.json'))) {
|
|
326
|
+
return pointed;
|
|
327
|
+
}
|
|
328
|
+
} catch {}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// 3. Otherwise use ~/.sfp/SFP (or $SFP_ROOT / $SFP_DIR)
|
|
332
|
+
const defaultDir = path.join(os.homedir(), '.sfp', 'SFP');
|
|
333
|
+
const targetDir = process.env.SFP_ROOT || process.env.SFP_DIR || defaultDir;
|
|
334
|
+
|
|
335
|
+
if (!fs.existsSync(path.join(targetDir, '.git'))) {
|
|
336
|
+
console.error(`\x1b[36mSetting up SFP in ${targetDir}...\x1b[0m`);
|
|
337
|
+
fs.mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
338
|
+
// Clone main branch with automatic fallback
|
|
339
|
+
let cloneRes = spawnSync('git', ['clone', '--depth', '1', '--branch', 'main', '--config', 'advice.detachedHead=false', '--config', 'core.longpaths=true', REPO_URL, targetDir], {
|
|
340
|
+
stdio: ['ignore', 2, 2]
|
|
341
|
+
});
|
|
342
|
+
if (cloneRes.status !== 0) {
|
|
343
|
+
cloneRes = spawnSync('git', ['clone', '--depth', '1', '--config', 'advice.detachedHead=false', '--config', 'core.longpaths=true', REPO_URL, targetDir], {
|
|
344
|
+
stdio: ['ignore', 2, 2]
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
if (cloneRes.status !== 0) {
|
|
348
|
+
console.error(`\x1b[31mError: Failed to clone SFP repository from ${REPO_URL}.\x1b[0m`);
|
|
349
|
+
console.error('Please ensure git is installed and network access is available.');
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
352
|
+
console.error(`\x1b[32m✔ SFP setup complete in ${targetDir}.\x1b[0m`);
|
|
353
|
+
} else if (process.env.SFP_AUTO_UPDATE === '1' || process.env.SFP_AUTO_UPDATE === 'true') {
|
|
354
|
+
// Automatic update on launch when opt-in SFP_AUTO_UPDATE is enabled: move to latest release tag (never pull main)
|
|
355
|
+
const git = (...a) => spawnSync('git', ['-C', targetDir, '-c', 'core.longpaths=true', ...a], { encoding: 'utf-8' });
|
|
356
|
+
if (!git('status', '--porcelain').stdout.trim()) {
|
|
357
|
+
git('fetch', '--tags', 'origin');
|
|
358
|
+
const latestTag = getLatestReleaseTag(targetDir);
|
|
359
|
+
if (latestTag && isNewerRelease(latestTag, targetDir)) {
|
|
360
|
+
git('checkout', latestTag);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return targetDir;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function showHelp(skillCount) {
|
|
369
|
+
const countStr = skillCount ? `${skillCount} skills` : '894 skills';
|
|
370
|
+
console.log(`
|
|
371
|
+
\x1b[1m\x1b[36mSFP (Skills for Productivity)\x1b[0m — ${countStr}, one intelligent hive.
|
|
372
|
+
Give your AI coding agent the right skills for the job, not all of them.
|
|
373
|
+
|
|
374
|
+
\x1b[1mUSAGE:\x1b[0m
|
|
375
|
+
\x1b[32mnpx sfp-hive\x1b[0m <command> [options]
|
|
376
|
+
\x1b[32msfp\x1b[0m <command> [options]
|
|
377
|
+
|
|
378
|
+
\x1b[1mCOMMANDS:\x1b[0m
|
|
379
|
+
\x1b[33minstall\x1b[0m [options] Install skills into detected IDEs (Antigravity, Claude, Cursor, VS Code, etc.)
|
|
380
|
+
\x1b[33mupdate\x1b[0m [options] Pull latest repository updates and refresh skills in IDEs
|
|
381
|
+
\x1b[33mmcp\x1b[0m [options] Run the SFP MCP server on stdio (or register with --tools <ide>)
|
|
382
|
+
\x1b[33mrules\x1b[0m [options] Add standing instructions to use SFP skills on substantial tasks
|
|
383
|
+
\x1b[33mselect\x1b[0m "<task>" Ask the hive which skills to load for a task
|
|
384
|
+
\x1b[33mneeds\x1b[0m "<task>" Check what capabilities or external tools a task needs
|
|
385
|
+
\x1b[33mdoctor\x1b[0m Check catalog, index, local models, and hive connections
|
|
386
|
+
\x1b[33mroute\x1b[0m [args] Manage or start the local model router (Ollama, LM Studio, etc.)
|
|
387
|
+
\x1b[33mmodels\x1b[0m [probe|add|remove] The models the hive asks: local ones found, plus any you add by API
|
|
388
|
+
\x1b[33mtaste\x1b[0m [--reset] Learned facet preferences (output forms, delivery style, depth)
|
|
389
|
+
\x1b[33mmentor\x1b[0m [profile|grow] What you lean towards, and new skills grown from research for it
|
|
390
|
+
\x1b[33mresearch\x1b[0m [args] Draft, refresh, approve or reject skills written from research papers
|
|
391
|
+
\x1b[33mapps\x1b[0m [args] Manage companion apps (OmniRoute, Strix, etc.)
|
|
392
|
+
\x1b[33mlist\x1b[0m List categories and install profiles
|
|
393
|
+
\x1b[33mhelp\x1b[0m Show this help message
|
|
394
|
+
|
|
395
|
+
\x1b[1mEXAMPLES:\x1b[0m
|
|
396
|
+
$ \x1b[32mnpx sfp-hive install\x1b[0m # Install starter set into every IDE found
|
|
397
|
+
$ \x1b[32mnpx sfp-hive update\x1b[0m # Automatically pull latest repo updates & skills
|
|
398
|
+
$ \x1b[32mnpx sfp-hive install --profile backend-dev\x1b[0m # Install backend-focused skills
|
|
399
|
+
$ \x1b[32mnpx sfp-hive mcp --tools antigravity,cursor\x1b[0m # Register MCP server in IDEs
|
|
400
|
+
$ \x1b[32mnpx sfp-hive select "write unit tests"\x1b[0m # See which skills the hive recommends
|
|
401
|
+
$ \x1b[32mnpx sfp-hive doctor\x1b[0m # Verify health of catalog, index, and models
|
|
402
|
+
|
|
403
|
+
\x1b[1mUSE IN MCP CLIENTS (mcp.json):\x1b[0m
|
|
404
|
+
{
|
|
405
|
+
"mcpServers": {
|
|
406
|
+
"sfp": {
|
|
407
|
+
"command": "npx",
|
|
408
|
+
"args": ["-y", "sfp-hive", "mcp"]
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
Docs & Source: \x1b[4mhttps://github.com/siddu1004/SFP\x1b[0m
|
|
414
|
+
`);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function run() {
|
|
418
|
+
// Internal background worker for async update check
|
|
419
|
+
if (process.argv[2] === '__bg_check_update') {
|
|
420
|
+
const rootDir = process.argv[3] || PKG_DIR;
|
|
421
|
+
checkRemoteUpdate(rootDir).then(() => process.exit(0)).catch(() => process.exit(0));
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const py = findPython();
|
|
426
|
+
if (!py) {
|
|
427
|
+
console.error('\x1b[31mError: Python 3.8+ is required to run SFP.\x1b[0m');
|
|
428
|
+
console.error('Please install Python 3 from https://www.python.org/downloads/ and ensure it is on your PATH.');
|
|
429
|
+
process.exit(1);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const args = process.argv.slice(2);
|
|
433
|
+
const command = args[0];
|
|
434
|
+
|
|
435
|
+
const rootDir = resolveSfpRoot();
|
|
436
|
+
|
|
437
|
+
// Read skill count from catalog for dynamic help display
|
|
438
|
+
let skillCount = null;
|
|
439
|
+
try {
|
|
440
|
+
const catPath = path.join(rootDir, 'catalog.json');
|
|
441
|
+
if (fs.existsSync(catPath)) {
|
|
442
|
+
const cat = JSON.parse(fs.readFileSync(catPath, 'utf-8'));
|
|
443
|
+
if (cat.skills) {
|
|
444
|
+
skillCount = Object.keys(cat.skills).length;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
} catch {}
|
|
448
|
+
|
|
449
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
450
|
+
showHelp(skillCount);
|
|
451
|
+
process.exit(0);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Handle explicit update command
|
|
455
|
+
if (command === 'update') {
|
|
456
|
+
handleUpdate(rootDir, py, args);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Background update check & notification
|
|
461
|
+
const cache = readUpdateCache();
|
|
462
|
+
if (Date.now() - (cache.lastChecked || 0) > UPDATE_CHECK_INTERVAL_MS) {
|
|
463
|
+
spawnBackgroundUpdateCheck(rootDir);
|
|
464
|
+
} else if (cache.hasUpdate) {
|
|
465
|
+
// Print notification to stderr (never interferes with MCP stdio stream)
|
|
466
|
+
printUpdateNotice(cache);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
let targetScript = null;
|
|
470
|
+
let targetArgs = [];
|
|
471
|
+
|
|
472
|
+
switch (command) {
|
|
473
|
+
case 'mcp':
|
|
474
|
+
if (args.slice(1).some((a) => a === '--tools' || a === '--project' || a === '--remove' || a.startsWith('--tools='))) {
|
|
475
|
+
targetScript = path.join(rootDir, 'scripts', 'install.py');
|
|
476
|
+
targetArgs = ['mcp', ...args.slice(1)];
|
|
477
|
+
} else {
|
|
478
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_mcp.py');
|
|
479
|
+
targetArgs = args.slice(1);
|
|
480
|
+
}
|
|
481
|
+
break;
|
|
482
|
+
|
|
483
|
+
case 'select':
|
|
484
|
+
case 'live':
|
|
485
|
+
case 'track':
|
|
486
|
+
case 'feedback':
|
|
487
|
+
case 'clusters':
|
|
488
|
+
case 'library':
|
|
489
|
+
case 'bundles':
|
|
490
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_hive.py');
|
|
491
|
+
targetArgs = args;
|
|
492
|
+
break;
|
|
493
|
+
|
|
494
|
+
case 'needs':
|
|
495
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_hive.py');
|
|
496
|
+
targetArgs = ['needs', ...args.slice(1)];
|
|
497
|
+
break;
|
|
498
|
+
|
|
499
|
+
case 'doctor':
|
|
500
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_hive.py');
|
|
501
|
+
targetArgs = ['doctor', ...args.slice(1)];
|
|
502
|
+
break;
|
|
503
|
+
|
|
504
|
+
case 'route':
|
|
505
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_route.py');
|
|
506
|
+
targetArgs = args.slice(1);
|
|
507
|
+
break;
|
|
508
|
+
|
|
509
|
+
case 'models':
|
|
510
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_intent.py');
|
|
511
|
+
targetArgs = args.length > 1 ? args.slice(1) : ['models'];
|
|
512
|
+
break;
|
|
513
|
+
|
|
514
|
+
case 'taste':
|
|
515
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_hive.py');
|
|
516
|
+
targetArgs = ['taste', ...args.slice(1)];
|
|
517
|
+
break;
|
|
518
|
+
case 'mentor':
|
|
519
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_mentor.py');
|
|
520
|
+
targetArgs = args.length > 1 ? args.slice(1) : ['profile'];
|
|
521
|
+
break;
|
|
522
|
+
|
|
523
|
+
case 'research':
|
|
524
|
+
targetScript = path.join(rootDir, 'mcp', 'sfp_research.py');
|
|
525
|
+
targetArgs = args.slice(1);
|
|
526
|
+
break;
|
|
527
|
+
|
|
528
|
+
case 'install':
|
|
529
|
+
case 'list':
|
|
530
|
+
case 'uninstall':
|
|
531
|
+
case 'rules':
|
|
532
|
+
case 'apps':
|
|
533
|
+
targetScript = path.join(rootDir, 'scripts', 'install.py');
|
|
534
|
+
targetArgs = [command, ...args.slice(1)];
|
|
535
|
+
break;
|
|
536
|
+
|
|
537
|
+
default:
|
|
538
|
+
if (command.startsWith('-')) {
|
|
539
|
+
targetScript = path.join(rootDir, 'scripts', 'install.py');
|
|
540
|
+
targetArgs = ['install', ...args];
|
|
541
|
+
} else {
|
|
542
|
+
console.error(`\x1b[31mUnknown command:\x1b[0m ${command}\n`);
|
|
543
|
+
showHelp(skillCount);
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
546
|
+
break;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const env = {
|
|
550
|
+
...process.env,
|
|
551
|
+
PYTHONIOENCODING: 'utf-8',
|
|
552
|
+
PYTHONUTF8: '1',
|
|
553
|
+
PYTHONPATH: [path.join(rootDir, 'mcp'), process.env.PYTHONPATH].filter(Boolean).join(path.delimiter)
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
const finalArgs = [...py.extraArgs, targetScript, ...targetArgs];
|
|
557
|
+
const child = spawn(py.bin, finalArgs, {
|
|
558
|
+
cwd: rootDir,
|
|
559
|
+
stdio: 'inherit',
|
|
560
|
+
env
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
child.on('exit', (code, signal) => {
|
|
564
|
+
if (signal) {
|
|
565
|
+
process.kill(process.pid, signal);
|
|
566
|
+
} else {
|
|
567
|
+
process.exit(code ?? 0);
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
child.on('error', (err) => {
|
|
572
|
+
console.error(`\x1b[31mFailed to start process:\x1b[0m ${err.message}`);
|
|
573
|
+
process.exit(1);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
run();
|
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sfp-hive",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "3.19.0",
|
|
4
|
+
"description": "Give your AI coding agent the right skills for the job, not all of them. Curated library of 800+ agent skills across 16 IDEs with an intelligent hive that selects, orders, and learns from feedback.",
|
|
5
|
+
"author": "siddu1004",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/siddu1004/SFP#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/siddu1004/SFP.git"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"registry": "https://registry.npmjs.org",
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/siddu1004/SFP/issues"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"ai",
|
|
21
|
+
"agent",
|
|
22
|
+
"skills",
|
|
23
|
+
"mcp",
|
|
24
|
+
"claude-code",
|
|
25
|
+
"cursor",
|
|
26
|
+
"antigravity",
|
|
27
|
+
"copilot",
|
|
28
|
+
"developer-tools",
|
|
29
|
+
"productivity",
|
|
30
|
+
"hive",
|
|
31
|
+
"vibecoding"
|
|
32
|
+
],
|
|
33
|
+
"main": "./bin/sfp.js",
|
|
34
|
+
"bin": {
|
|
35
|
+
"sfp": "./bin/sfp.js",
|
|
36
|
+
"sfp-hive": "./bin/sfp.js"
|
|
37
|
+
},
|
|
38
|
+
"preferGlobal": true,
|
|
39
|
+
"scripts": {
|
|
40
|
+
"start": "node ./bin/sfp.js",
|
|
41
|
+
"sfp": "node ./bin/sfp.js",
|
|
42
|
+
"update": "node ./bin/sfp.js update",
|
|
43
|
+
"doctor": "node ./bin/sfp.js doctor",
|
|
44
|
+
"test": "node ./bin/sfp.js doctor"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"bin/",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE"
|
|
50
|
+
],
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18"
|
|
53
|
+
}
|
|
54
|
+
}
|