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 +72 -44
- package/bundled-skills/.antigravity-install-manifest.json +3 -1
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package-lock.json +3 -3
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package.json +2 -1
- package/bundled-skills/omentir-linkedin-outreach/SKILL.md +96 -0
- package/bundled-skills/since-cutoff/SKILL.md +68 -0
- package/dist/index.d.ts +8 -13
- package/dist/index.js +26 -7
- package/dist/skill-pointer/index.d.ts +2 -1
- package/dist/skill-pointer/index.js +2 -1
- package/dist/skill-pointer/pointer-generator.d.ts +4 -3
- package/dist/skill-pointer/pointer-generator.js +5 -4
- package/package.json +3 -3
- package/skills_index.json +4312 -0
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
|
|
31
|
+
**OpenCode Skills Collection** ships a pre-bundled snapshot of 2400+ universal skills for OpenCode.
|
|
32
32
|
|
|
33
|
-
Instead of
|
|
34
|
-
|
|
35
|
-
only
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
|
95
|
-
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
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
|
-
```
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/
|
|
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
|
-
|
|
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
|
-
```
|
|
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-
|
|
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.
|
|
937
|
-
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.
|
|
938
|
-
"integrity": "sha512-
|
|
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"
|
|
@@ -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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
31
|
+
const OpenCodeSkillsCollectionV1 = async (_ctx) => {
|
|
25
32
|
try {
|
|
26
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
8
|
-
* via
|
|
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 \`
|
|
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
|
-
*
|
|
48
|
-
* via
|
|
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.
|
|
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.
|
|
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",
|