opencode-skills-collection 4.0.77 → 4.1.1

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.

Potentially problematic release.


This version of opencode-skills-collection might be problematic. Click here for more details.

package/README.md CHANGED
@@ -28,11 +28,13 @@
28
28
 
29
29
  ## Overview
30
30
 
31
- **OpenCode Skills Collection** ships a pre-bundled snapshot of 1595+ universal skills for the OpenCode.
31
+ **OpenCode Skills Collection** ships a pre-bundled snapshot of 2400+ universal skills for OpenCode.
32
32
 
33
- Instead of loading every skill into the AI context at startup — which would consume ~80k tokens and cause compaction
34
- loops — the plugin uses a **SkillPointer** architecture: skills are organized into categories inside a hidden vault and
35
- only loaded into context on demand.
33
+ Instead of registering every skill with OpenCode at startup — which would flood the model's available-skills list with
34
+ thousands of entries — the plugin uses a **SkillPointer** architecture: skills are stored in a hidden vault organized by
35
+ category, and only ~100 lightweight pointer skills are registered. At each model step OpenCode advertises the pointers
36
+ (ID, name, description); the model loads a pointer via the `skill` tool, reads which vault skills match the task, then
37
+ loads the chosen vault `SKILL.md` via `read`.
36
38
 
37
39
  ---
38
40
 
@@ -42,28 +44,36 @@ The plugin operates in two phases:
42
44
 
43
45
  **1. Local deployment (startup)**
44
46
 
45
- When OpenCode starts, the plugin copies the pre-bundled skills from the npm package and runs the SkillPointer pipeline:
47
+ When OpenCode starts, the plugin runs the SkillPointer pipeline synchronously before anything else. No hooks, tools,
48
+ or commands are registered — the only side effect is files on disk:
46
49
 
47
50
  ```
48
- bundled-skills/ (npm package)
51
+ bundled-skills/ (npm package) + skills_index.json
49
52
  │
50
- ▼
51
- ~/.config/opencode/skills/ ← OpenCode reads this
53
+ ▼ runSkillPointer()
54
+ ├─ filterIndex → drops skills matching excluded risk levels / IDs
55
+ ├─ installSkillsToVault → copies kept skills into the vault by category,
56
+ │ removes vault entries no longer in the filtered index
57
+ ├─ applySkillPatches → regex find/replace from skill-filter.jsonc on vault copies
58
+ └─ generatePointers → writes one <category>-category-pointer/SKILL.md per
59
+ category into the active skills dir, removes stale pointers
52
60
  │
53
- └── SkillPointer pipeline
54
- │
55
- ├─ risk-filter → excludes skills by risk level or ID
56
- ├─ content-scanner → quarantines skills with dangerous patterns
57
- ├─ vault-manager → moves safe skills to the vault
58
- ├─ skill-patcher → applies config-driven content patches
59
- └─ pointer-generator → writes ~35 lightweight pointer files
61
+ ├── ~/.config/opencode/skill-libraries/<category>/<skill>/SKILL.md (vault, NOT registered)
62
+ └── ~/.config/opencode/skills/<category>-category-pointer/SKILL.md (registered by OpenCode)
60
63
  ```
61
64
 
62
- **2. On-demand skill loading**
65
+ Content scanning is NOT a runtime stage: dangerous skills are quarantined at CI time (sync-skills.yml) and never
66
+ reach the npm package.
63
67
 
64
- Each pointer file tells the AI: *"there are N skills for this category in the vault — use `list_dir` / `view_file` to
65
- retrieve them when needed."*
66
- The full skill content is only injected into context when the AI actually needs it.
68
+ **2. On-demand skill loading (at inference time)**
69
+
70
+ 1. OpenCode discovers pointer skills in `~/.config/opencode/skills/` and advertises ID + name + description to the
71
+ model at each step (body stays out of context).
72
+ 2. The model loads the matching pointer via the `skill` tool (`{"id": "<category>-category-pointer"}`); OpenCode
73
+ injects the pointer body — the categorized skill list plus vault path.
74
+ 3. The model reads the chosen vault file via `read` (`skill-libraries/<category>/<skill>/SKILL.md`) and follows it.
75
+
76
+ Vault skills are never registered with OpenCode directly, so they never appear in the advertised list.
67
77
 
68
78
  ---
69
79
 
@@ -91,12 +101,12 @@ After the first startup, your `~/.config/opencode/` directory looks like this:
91
101
 
92
102
  ## Context Usage
93
103
 
94
- | | Without SkillPointer | With SkillPointer |
95
- |----------------------|----------------------|---------------------|
96
- | Folders in `skills/` | ~1000 | ~35 |
97
- | Tokens at startup | ~80,000 | ~255 |
98
- | Skills available | All injected upfront | On-demand via vault |
99
- | Compaction loops | ✗ frequent | ✓ none |
104
+ | | Without SkillPointer | With SkillPointer |
105
+ |------------------------------|----------------------|-----------------------|
106
+ | Entries in `skills/` | ~2450 | ~100 pointers |
107
+ | Skills advertised per step | ~2450 | ~100 |
108
+ | Full bodies in context | On explicit load | On explicit load |
109
+ | Vault skills loaded | n/a | Via `read` after pointer |
100
110
 
101
111
  ---
102
112
 
@@ -104,8 +114,20 @@ After the first startup, your `~/.config/opencode/` directory looks like this:
104
114
 
105
115
  Add the plugin to your global OpenCode configuration file at `~/.config/opencode/opencode.json`:
106
116
 
107
- ```json
117
+ ```jsonc
108
118
  {
119
+ // OpenCode V2
120
+ "plugins": [
121
+ "opencode-skills-collection@latest"
122
+ ]
123
+ }
124
+ ```
125
+
126
+ For OpenCode V1 (>= 1.18.29), use the `plugin` key instead (older V1 releases expect a function entrypoint and cannot load this version):
127
+
128
+ ```jsonc
129
+ {
130
+ // OpenCode V1
109
131
  "plugin": [
110
132
  "opencode-skills-collection@latest"
111
133
  ]
@@ -119,29 +141,23 @@ needed.
119
141
 
120
142
  ## Usage
121
143
 
122
- Once installed, all skills are available in three ways:
123
-
124
- **Explicit invocation via CLI:**
144
+ The plugin registers pointer skills, not commands. There is no `/skill-name` slash command and no `opencode run /...`
145
+ syntax — slash commands live in `commands/`, this plugin only writes to `skills/`.
125
146
 
126
- ```bash
127
- opencode run /brainstorming help me plan a new feature
128
- opencode run /refactor clean up this function
129
- ```
147
+ **How a skill gets used (V2 runtime):**
130
148
 
131
- **Slash commands in the OpenCode chat:**
149
+ 1. You describe the task in plain language (CLI `opencode run "..."`, TUI chat, or session).
150
+ 2. OpenCode advertises the ~100 pointer skills (ID + description) to the model.
151
+ 3. The model loads the matching `<category>-category-pointer` via the `skill` tool, picks the vault skill from its
152
+ list, reads `skill-libraries/<category>/<skill>/SKILL.md` via `read`, and follows it.
132
153
 
133
154
  ```
134
- /brainstorming
135
- /refactor
136
- /document
155
+ "Help me design a REST API" → model loads backend-dev-category-pointer → reads laravel-expert/SKILL.md
137
156
  ```
138
157
 
139
- **Natural language — OpenCode picks the right skill automatically:**
140
-
141
- ```
142
- "Help me brainstorm ideas for a REST API design"
143
- "Refactor this function to be more readable"
144
- ```
158
+ Skills without a `description` are never advertised; skills can opt out of the advertised list with
159
+ `metadata.opencode/autoinvoke: false` but remain loadable by exact ID. The `skill` tool takes an exact,
160
+ case-sensitive ID.
145
161
 
146
162
  ---
147
163
 
@@ -249,8 +265,20 @@ Beta versions are published from the `develop` branch for testing before officia
249
265
 
250
266
  To use the latest beta version, update your `~/.config/opencode/opencode.json`:
251
267
 
252
- ```json
268
+ ```jsonc
269
+ {
270
+ // OpenCode V2
271
+ "plugins": [
272
+ "opencode-skills-collection@beta"
273
+ ]
274
+ }
275
+ ```
276
+
277
+ For OpenCode V1 (>= 1.18.29):
278
+
279
+ ```jsonc
253
280
  {
281
+ // OpenCode V1
254
282
  "plugin": [
255
283
  "opencode-skills-collection@beta"
256
284
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "updatedAt": "2026-09-29T03:02:52.069Z",
3
+ "updatedAt": "2026-09-30T02:44:27.590Z",
4
4
  "entries": [
5
5
  "00-andruia-consultant",
6
6
  "007",
@@ -1665,6 +1665,7 @@
1665
1665
  "office-productivity",
1666
1666
  "okta-attack",
1667
1667
  "ollama-stack",
1668
+ "omentir-linkedin-outreach",
1668
1669
  "omp-delegate",
1669
1670
  "on-call-handoff-patterns",
1670
1671
  "onboarding",
@@ -2054,6 +2055,7 @@
2054
2055
  "signup-flow-cro",
2055
2056
  "similarity-search-patterns",
2056
2057
  "simplify-code",
2058
+ "since-cutoff",
2057
2059
  "site-architecture",
2058
2060
  "skill-audit",
2059
2061
  "skill-check",
@@ -933,9 +933,9 @@
933
933
  "license": "ISC"
934
934
  },
935
935
  "node_modules/ip-address": {
936
- "version": "10.4.0",
937
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz",
938
- "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==",
936
+ "version": "10.7.2",
937
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz",
938
+ "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==",
939
939
  "license": "MIT",
940
940
  "engines": {
941
941
  "node": ">= 12"
@@ -25,6 +25,7 @@
25
25
  "overrides": {
26
26
  "diff": "4.0.4",
27
27
  "path-to-regexp": "0.1.13",
28
- "qs": "^6.16.0"
28
+ "qs": "^6.16.0",
29
+ "ip-address": "^10.5.1"
29
30
  }
30
31
  }
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: omentir-linkedin-outreach
3
+ description: "Run LinkedIn prospecting and outreach through the Omentir MCP server: find people, score fit, draft messages, and check campaigns. Never signs into LinkedIn."
4
+ category: marketing
5
+ risk: critical
6
+ source: https://github.com/vanshyadav1408/Omentir/tree/main/plugins/omentir/skills/linkedin-outreach
7
+ source_repo: vanshyadav1408/Omentir
8
+ source_type: official
9
+ date_added: "2026-09-28"
10
+ author: vanshyadav1408
11
+ tags: [linkedin, sales, outreach, lead-generation, prospecting, mcp]
12
+ tools: [claude, cursor, codex]
13
+ license: MIT
14
+ license_source: https://github.com/vanshyadav1408/Omentir/blob/main/LICENSE
15
+ ---
16
+
17
+ # LinkedIn outreach through Omentir
18
+
19
+ Omentir already holds the user's LinkedIn connection and daily send limits. Talk to that workspace over MCP. Do not open LinkedIn in the Bot browser. Do not ask the user to take over for a LinkedIn password, passkey, two-factor code, or CAPTCHA.
20
+
21
+ > Imported from the official Omentir `linkedin-outreach` skill ([source](https://github.com/vanshyadav1408/Omentir/blob/main/plugins/omentir/skills/linkedin-outreach/SKILL.md), MIT). The opening paragraph and the First calls, Finding people, Sending, and Grok Bot sections are the upstream text, unchanged. Overview, When to Use This Skill, Prerequisites, Examples, and Limitations were added for this catalog.
22
+
23
+ ## Overview
24
+
25
+ Omentir is an open-source AI sales workspace for LinkedIn. This skill tells the agent how to use the Omentir MCP server to find and score prospects, draft messages, and check campaigns. It defaults to research and drafts only. It never sends unless the user asks, and it never signs into LinkedIn.
26
+
27
+ ## When to Use This Skill
28
+
29
+ - Use when the user wants to find LinkedIn prospects that match their product, and the Omentir MCP server is connected.
30
+ - Use when the user wants fit scoring or first-message drafts for leads already in their Omentir workspace.
31
+ - Use when the user asks about the state of an Omentir campaign: agents, scheduled sends, replies, or stats.
32
+ - Do not use it to drive LinkedIn in a browser. This skill works only through Omentir MCP tools.
33
+
34
+ ## Prerequisites
35
+
36
+ - An Omentir account with a LinkedIn account connected inside Omentir. The hosted service is Pro at $49/month; self-hosting is free under MIT.
37
+ - The Omentir MCP server connected in the host: `https://omentir.com/api/agent/v1/mcp` (streamable HTTP). Sign-in is OAuth 2.1. An API key from https://omentir.com/api-keys also works as `Authorization: Bearer <key>`.
38
+ - Installing this skill alone does not connect the server.
39
+
40
+ ## First calls
41
+
42
+ 1. `omentir_get_context`
43
+ 2. `omentir_list_workspaces` if the user has more than one company, then `omentir_switch_workspace` after they pick
44
+ 3. `omentir_get_product_profile`
45
+ 4. `omentir_list_linkedin_accounts`
46
+ 5. `omentir_list_agents`
47
+
48
+ If LinkedIn is not connected or Workspace is empty, stop and tell the user to finish that in Omentir. Do not guess ICP from a homepage.
49
+
50
+ ## Finding people
51
+
52
+ - Classic finder: `omentir_create_agent` with a prompt plus titles, industries, locations, and keywords. `omentir_draft_agent_setup` fills those from Workspace. Show the config and wait for a yes before creating.
53
+ - Steal Customers: `mode: "steal_customers"` plus competitor or founder URLs. Workspace must already be set.
54
+ - Outreach only: `mode: "outreach"` plus `csvContents` or `omentir_import_csv_leads`. Pass `steps` for a custom sequence.
55
+ - After create, discovery can still be empty. Use `omentir_list_activity` before treating that as failure.
56
+ - Score from evidence on the lead. Rewrite a note that could fit two buyers.
57
+
58
+ ## Sending
59
+
60
+ Default to research and drafts only. Do not send, enroll, or reply unless the user asks in this session.
61
+
62
+ If they do ask to send, Omentir's planner owns timing unless they ask to send now (`omentir_run_scheduled_action_now`). Read `omentir_list_scheduled_actions` for committed send times. Stay inside `omentir_get_context` remaining invite and message allowance. Stop one lead with `omentir_stop_lead_outreach`.
63
+
64
+ Replies go through `omentir_reply_to_lead` on a captured thread, or `omentir_reply_to_chat` on a live inbox chat (attachments allowed). List live chats with `omentir_list_inbox`.
65
+
66
+ ## Grok Bot
67
+
68
+ Installed plugins are account-wide. Attach this plugin with `@omentir`. Keep this stop rule in the Bot description: research and draft only. Never send. Never enroll. Never sign into LinkedIn.
69
+
70
+ ## Examples
71
+
72
+ ### Connect the server in Claude Code
73
+
74
+ ```bash
75
+ claude mcp add --transport http omentir https://omentir.com/api/agent/v1/mcp
76
+ ```
77
+
78
+ ### Research and drafts only
79
+
80
+ ```text
81
+ User: Find heads of sales at seed-stage SaaS companies in Germany and draft a first message for the best five. Do not send anything.
82
+
83
+ Agent: calls omentir_get_context, omentir_get_product_profile,
84
+ omentir_list_linkedin_accounts, and omentir_list_agents; uses
85
+ omentir_draft_agent_setup to propose titles, industries, locations, and
86
+ keywords; shows that config and waits for a yes before omentir_create_agent;
87
+ checks omentir_list_activity while discovery runs; then scores leads from
88
+ omentir_list_leads / omentir_get_lead and returns five drafts without sending.
89
+ ```
90
+
91
+ ## Limitations
92
+
93
+ - Needs an Omentir workspace with LinkedIn already connected. The agent cannot create an Omentir account, change billing, connect LinkedIn, create or delete a workspace, or mint API keys.
94
+ - Sends are human-paced and capped by the daily invite and message allowance that `omentir_get_context` reports.
95
+ - Lead discovery is asynchronous, so a new agent can show no leads for a while.
96
+ - The agent never sees the user's LinkedIn password and does not open LinkedIn in a browser.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: since-cutoff
3
+ description: "Find which APIs of a project's pinned Python dependencies changed after the model's training cutoff, where the code uses them, and write short AGENTS.md or CLAUDE.md notes."
4
+ category: development
5
+ risk: safe
6
+ source: https://github.com/MohammadHijjawi97/since-cutoff/tree/f2108c13c112dce0ca3597b5a2b79ca01afa7b80/skills/since-cutoff
7
+ source_repo: MohammadHijjawi97/since-cutoff
8
+ source_type: official
9
+ date_added: "2026-09-28"
10
+ author: Mohammad Hijjawi
11
+ tags: [python, dependencies, api-changes, knowledge-cutoff, agents-md, static-analysis]
12
+ tools: [claude, codex, cursor, gemini]
13
+ license: MIT
14
+ license_source: https://github.com/MohammadHijjawi97/since-cutoff/blob/f2108c13c112dce0ca3597b5a2b79ca01afa7b80/LICENSE
15
+ ---
16
+
17
+ # since-cutoff: dependency API changes after the model's training cutoff
18
+
19
+ ## Overview
20
+
21
+ A coding model learns each library's API as it was at its training cutoff, but the project's lockfile keeps moving. This skill runs the since-cutoff CLI (MIT, PyPI `since-cutoff`, pinned here to release 0.4.1). For each pinned dependency, the CLI takes the latest release on or before the model's cutoff and compares that release's public API with the pinned release. The comparison is static (griffe), so no package code runs. It then reports the changed APIs that the project's code uses, with the files that use them. If the user agrees, it writes short notes into AGENTS.md or CLAUDE.md, each tagged with the evidence behind it (for example `[diff]`). `scan` makes no model calls and needs no API key. This adapts the [upstream skill](https://github.com/MohammadHijjawi97/since-cutoff/tree/f2108c13c112dce0ca3597b5a2b79ca01afa7b80/skills/since-cutoff) under its [MIT license](https://github.com/MohammadHijjawi97/since-cutoff/blob/f2108c13c112dce0ca3597b5a2b79ca01afa7b80/LICENSE).
22
+
23
+ ## When to Use
24
+
25
+ - Use when the user asks whether you know the versions of their Python dependencies, or what changed since your training data.
26
+ - Use when code keeps failing on a renamed, moved or removed function, class or parameter of a pinned library.
27
+ - Use after a dependency upgrade, before writing code against the upgraded library.
28
+ - Do not use for projects that are not Python.
29
+
30
+ ## How It Works
31
+
32
+ 1. Work from the project root, the directory that has `pyproject.toml`, `requirements*.txt` or a lockfile (`uv.lock`, `poetry.lock`, `pdm.lock`, `pylock.toml`, `Pipfile.lock`).
33
+ 2. Check the runner with `since-cutoff --version`. If it is missing or does not report 0.4.1, ask the user before running `uvx since-cutoff@0.4.1`, which downloads that release from PyPI the first time. Do not install anything else or change the user's environment.
34
+ 3. Run the read-only scan and name the model you are: `uvx since-cutoff@0.4.1 scan --model <provider>:<model>` (for example `anthropic:claude-sonnet-4-5` or `openai:gpt-5.4`). Without `--model`, it reads the model from the coding agent's settings and prints where it found it. The scan reads the project's files, PyPI and models.dev. It sends none of the project's code anywhere.
35
+ 4. Summarise the result for the user: the model and its cutoff, which dependencies changed, and which changed APIs the code uses, with the files that use them.
36
+ 5. Write notes only if the user asks for them. Run `uvx since-cutoff@0.4.1 sync --dry-run` and show the user the diff it prints. Run `uvx since-cutoff@0.4.1 sync --yes` only after they agree. It writes one marked block into AGENTS.md (or into CLAUDE.md if that is the file the project uses) and leaves the rest of the file unchanged. Run after later upgrades, it keeps the block in step with the lockfile. Exit code 4 means the block was edited by hand: tell the user, and pass `--force` only if they say so. `uvx since-cutoff@0.4.1 unapply` removes the block.
37
+ 6. Treat the notes as reference facts about the versions the project pins, and check them when you write code that uses those libraries.
38
+ 7. Optional: `since-cutoff run` measures which of the changes the model actually gets wrong. It sends prompts to the model provider the user picks (package names, versions, public API signatures and generated tasks, never the project's source code) and uses their credits or usage, so ask first.
39
+
40
+ ## Examples
41
+
42
+ ```bash
43
+ uvx since-cutoff@0.4.1 scan --model anthropic:claude-sonnet-4-5
44
+ ```
45
+
46
+ Output on the project's sample app, abridged to one package:
47
+
48
+ ```text
49
+ Your code uses 2 APIs that changed after claude-sonnet-4-5's training cutoff (2025-07-31)
50
+
51
+ anthropic 0.60.0 -> 1.8.0 (0.60.0 was the latest release at the cutoff; pyproject.toml pins 1.8.0)
52
+ Messages.create: temperature, top_k and top_p were removed uses this API
53
+ app/main.py calls create
54
+ Note: `Messages.create()` no longer accepts `temperature`, `top_k` or `top_p` as keyword
55
+ arguments. If the API still needs them, pass them through its `extra_body` or
56
+ `extra_query` argument. [diff]
57
+ ```
58
+
59
+ ## Limitations
60
+
61
+ - Python projects only.
62
+ - It compares the shape of the public API: names, signatures, parameters and deprecation markers. A change in behaviour behind an unchanged signature is invisible to it.
63
+ - The training cutoff only decides which changes to look at. It does not show what the model memorised; `run` measures that.
64
+ - It needs network access to PyPI, and to models.dev for model cutoffs. The first scan downloads the releases it compares. Results are cached locally.
65
+
66
+ ## Security Notes
67
+
68
+ `scan` and `status` do not change project files: they write only to their own git-ignored `.since-cutoff/` folder and a local cache. `sync` writes one marked block to AGENTS.md or CLAUDE.md, and only after the user agrees. No package code and no model-written code is executed. Credentials are needed only for the optional `run`.
package/dist/index.d.ts CHANGED
@@ -1,13 +1,8 @@
1
- import type { Plugin } from "@opencode-ai/plugin";
2
- /**
3
- * OpenCode Skills Collection plugin.
4
- *
5
- * On every OpenCode startup:
6
- * 1. Copies bundled skills directly into the vault
7
- * (~/.config/opencode/skill-libraries/) organised by category.
8
- * The active skills directory is never used as staging.
9
- * 2. Generates lightweight category pointer SKILL.md files in
10
- * ~/.config/opencode/skills/ without touching user custom skills.
11
- */
12
- declare const OpenCodeSkillsCollection: Plugin;
13
- export default OpenCodeSkillsCollection;
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import { Plugin } from "@opencode/plugin";
3
+ declare const _default: {
4
+ id: string;
5
+ setup: (context: Plugin.Context) => Promise<Plugin.Cleanup | void> | Plugin.Cleanup | void;
6
+ server(ctx: PluginInput): Promise<import("@opencode-ai/plugin").Hooks>;
7
+ };
8
+ export default _default;
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Plugin } from "@opencode/plugin";
1
2
  import os from "os";
2
3
  import path from "path";
3
4
  import { fileURLToPath } from "url";
@@ -11,8 +12,14 @@ function resolveBundledSkillsPath() {
11
12
  function resolveActiveSkillsDir() {
12
13
  return path.join(os.homedir(), ...ACTIVE_SKILLS_PATH_SEGMENTS);
13
14
  }
15
+ function runStartupPipeline() {
16
+ const bundledSkillsPath = resolveBundledSkillsPath();
17
+ const activeSkillsDir = resolveActiveSkillsDir();
18
+ ensureDir(activeSkillsDir);
19
+ runSkillPointer({ bundledSkillsPath, activeSkillsDir });
20
+ }
14
21
  /**
15
- * OpenCode Skills Collection plugin.
22
+ * OpenCode Skills Collection plugin (V1 + V2 from a single entrypoint).
16
23
  *
17
24
  * On every OpenCode startup:
18
25
  * 1. Copies bundled skills directly into the vault
@@ -21,16 +28,28 @@ function resolveActiveSkillsDir() {
21
28
  * 2. Generates lightweight category pointer SKILL.md files in
22
29
  * ~/.config/opencode/skills/ without touching user custom skills.
23
30
  */
24
- const OpenCodeSkillsCollection = async (_ctx) => {
31
+ const OpenCodeSkillsCollectionV1 = async (_ctx) => {
25
32
  try {
26
- const bundledSkillsPath = resolveBundledSkillsPath();
27
- const activeSkillsDir = resolveActiveSkillsDir();
28
- ensureDir(activeSkillsDir);
29
- runSkillPointer({ bundledSkillsPath, activeSkillsDir });
33
+ runStartupPipeline();
30
34
  }
31
35
  catch (error) {
32
36
  process.stderr.write(`[opencode-skills-collection] ${error}\n`);
33
37
  }
34
38
  return {};
35
39
  };
36
- export default OpenCodeSkillsCollection;
40
+ export default {
41
+ ...Plugin.define({
42
+ id: "opencode-skills-collection",
43
+ async setup(_ctx) {
44
+ try {
45
+ runStartupPipeline();
46
+ }
47
+ catch (error) {
48
+ process.stderr.write(`[opencode-skills-collection] ${error}\n`);
49
+ }
50
+ },
51
+ }),
52
+ async server(ctx) {
53
+ return OpenCodeSkillsCollectionV1(ctx);
54
+ },
55
+ };
@@ -21,7 +21,8 @@ export interface SkillPointerOptions {
21
21
  * 3. Copies skills into the vault, categorised by the index.
22
22
  * 4. Applies config-driven content patches to installed skills.
23
23
  * 5. Generates pointer SKILL.md files in activeSkillsDir with full skill
24
- * listings so keyword searches (e.g. "laravel") resolve out of the box.
24
+ * listings. The listings are visible to the model only after it loads
25
+ * the pointer via the `skill` tool (per step it sees ID + description).
25
26
  *
26
27
  * Content safety scanning is performed at CI time (sync-skills.yml),
27
28
  * not at runtime — dangerous skills are removed before npm publish.
@@ -18,7 +18,8 @@ function resolveDefaultVaultDir() {
18
18
  * 3. Copies skills into the vault, categorised by the index.
19
19
  * 4. Applies config-driven content patches to installed skills.
20
20
  * 5. Generates pointer SKILL.md files in activeSkillsDir with full skill
21
- * listings so keyword searches (e.g. "laravel") resolve out of the box.
21
+ * listings. The listings are visible to the model only after it loads
22
+ * the pointer via the `skill` tool (per step it sees ID + description).
22
23
  *
23
24
  * Content safety scanning is performed at CI time (sync-skills.yml),
24
25
  * not at runtime — dangerous skills are removed before npm publish.
@@ -3,8 +3,9 @@ import type { SkillIndexEntry } from "./vault-installer.js";
3
3
  * Scans every category directory in the vault and writes
4
4
  * a lightweight pointer SKILL.md into the active skills directory.
5
5
  *
6
- * Each pointer includes the full list of skill names + descriptions
7
- * so keyword searches (e.g. "laravel", "wordpress") resolve correctly
8
- * via get_available_skills without loading every SKILL.md.
6
+ * Each pointer includes the full list of skill names + descriptions.
7
+ * NOTE: the model only sees a pointer's ID + frontmatter description until
8
+ * it loads the pointer via the `skill` tool — the body list is visible
9
+ * only after that first load, followed by a `read` of the vault file.
9
10
  */
10
11
  export declare function generatePointers(activeSkillsDir: string, vaultDir: string, index?: SkillIndexEntry[]): void;
@@ -28,7 +28,7 @@ ${skillList}
28
28
  ## How to load a skill
29
29
 
30
30
  1. Identify the skill name above matching your task.
31
- 2. Use \`view_file\` to read its \`SKILL.md\` from the vault:
31
+ 2. Use \`read\` to load its \`SKILL.md\` from the vault:
32
32
  \`${normalizedPath}/<skill-name>/SKILL.md\`
33
33
  3. Follow those instructions to complete the request.
34
34
 
@@ -43,9 +43,10 @@ ${skillList}
43
43
  * Scans every category directory in the vault and writes
44
44
  * a lightweight pointer SKILL.md into the active skills directory.
45
45
  *
46
- * Each pointer includes the full list of skill names + descriptions
47
- * so keyword searches (e.g. "laravel", "wordpress") resolve correctly
48
- * via get_available_skills without loading every SKILL.md.
46
+ * Each pointer includes the full list of skill names + descriptions.
47
+ * NOTE: the model only sees a pointer's ID + frontmatter description until
48
+ * it loads the pointer via the `skill` tool — the body list is visible
49
+ * only after that first load, followed by a `read` of the vault file.
49
50
  */
50
51
  export function generatePointers(activeSkillsDir, vaultDir, index = []) {
51
52
  const byCategory = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-skills-collection",
3
- "version": "4.0.77",
3
+ "version": "4.1.1",
4
4
  "description": "OpenCode CLI plugin that automatically downloads and keeps skills up to date.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,17 +33,17 @@
33
33
  ],
34
34
  "author": "Davide Ladisa <info@davideladisa.it>",
35
35
  "license": "MIT",
36
- "packageManager": "bun@1.3.14",
36
+ "packageManager": "bun@1.4.2",
37
37
  "publishConfig": {
38
38
  "access": "public",
39
39
  "provenance": true
40
40
  },
41
41
  "dependencies": {
42
42
  "@opencode-ai/plugin": "^1.15.5",
43
+ "@opencode/plugin": "^2.0.18",
43
44
  "strip-json-comments": "^5.0.3"
44
45
  },
45
46
  "devDependencies": {
46
- "@opencode-ai/sdk": "^1.15.5",
47
47
  "@types/bun": "*",
48
48
  "@types/node": "^26.0.0",
49
49
  "@types/strip-json-comments": "^3.0.0",