@waynesutton/convex-skills 1.0.7 → 1.0.9

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/AGENTS.md CHANGED
@@ -40,7 +40,6 @@ This repository provides two complementary approaches for AI coding agents:
40
40
  | Skill | Description |
41
41
  | ------------------------------------------------------------------------ | ----------------------------------------------------- |
42
42
  | [convex-best-practices](skills/convex-best-practices/SKILL.md) | Guidelines for building production-ready Convex apps |
43
- | [convex-eslint](skills/convex-eslint/SKILL.md) | Write linter-compliant Convex code |
44
43
  | [convex-functions](skills/convex-functions/SKILL.md) | Writing queries, mutations, actions, and HTTP actions |
45
44
  | [convex-realtime](skills/convex-realtime/SKILL.md) | Patterns for building reactive applications |
46
45
  | [convex-schema-validator](skills/convex-schema-validator/SKILL.md) | Database schema definition and validation |
package/README.md CHANGED
@@ -1,4 +1,11 @@
1
- # Convex (unofficial) Skills v1
1
+ # For official Convex Skills use Convex Agent Plugins
2
+
3
+ Official Convex plugins for AI coding agents, providing development tools for building reactive backends with TypeScript.
4
+
5
+ https://github.com/get-convex/convex-agent-plugins
6
+
7
+
8
+ ## Convex (unofficial) Skills
2
9
 
3
10
  [![npm version](https://img.shields.io/npm/v/@waynesutton/convex-skills.svg)](https://www.npmjs.com/package/@waynesutton/convex-skills)
4
11
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
@@ -16,7 +23,7 @@ All skills are designed to produce code that passes @convex-dev/eslint-plugin by
16
23
  - **Skills** prevent mistakes at generation time
17
24
  - **ESLint** catches anything that slips through at build time
18
25
 
19
- See the [convex-eslint](/skills/convex-eslint/SKILL.md) skill for setup instructions.
26
+ See the Code Quality section in [convex-best-practices](/skills/convex-best-practices/SKILL.md) for setup instructions.
20
27
 
21
28
  ## Installation
22
29
 
@@ -35,6 +42,12 @@ convex-skills install convex-best-practices
35
42
  # Install all skills
36
43
  convex-skills install-all
37
44
 
45
+ # Install all skills to .agents/skills
46
+ convex-skills install-all --target agents
47
+
48
+ # Symlink SKILL.md files instead of copying
49
+ convex-skills install-all --target agents --link
50
+
38
51
  # Install templates (CLAUDE.md + skill templates)
39
52
  convex-skills install-templates
40
53
  ```
@@ -84,6 +97,15 @@ Codex will auto-discover `SKILL.md` files in that directory on the next start.
84
97
 
85
98
  If you are working from a repo clone, Codex also auto-discovers skills from `.codex/skills` at the repo root. You can symlink this repo’s `skills/*` into `.codex/skills` so updates flow through without copying.
86
99
 
100
+ ### Standard Agent Skills Path
101
+
102
+ Some tools are standardizing on `.agents/skills` for discovery. This repo supports that layout via the CLI:
103
+
104
+ ```bash
105
+ convex-skills install-all --target agents
106
+ convex-skills install-all --target agents --link
107
+ ```
108
+
87
109
  ### OpenCode
88
110
 
89
111
  OpenCode discovers skills from `~/.claude/skills/<name>/SKILL.md` automatically. See OpenCode Skills docs for more details.
@@ -113,7 +135,6 @@ Copy the desired skill's `SKILL.md` file to your project's `.claude/skills/` dir
113
135
  | Skill | Description |
114
136
  | ------------------------------------------------------------------------ | ----------------------------------------------------- |
115
137
  | [convex-best-practices](skills/convex-best-practices/SKILL.md) | Guidelines for building production-ready Convex apps |
116
- | [convex-eslint](skills/convex-eslint/SKILL.md) | Write linter-compliant Convex code |
117
138
  | [convex-functions](skills/convex-functions/SKILL.md) | Writing queries, mutations, actions, and HTTP actions |
118
139
  | [convex-realtime](skills/convex-realtime/SKILL.md) | Patterns for building reactive applications |
119
140
  | [convex-schema-validator](skills/convex-schema-validator/SKILL.md) | Database schema definition and validation |
@@ -133,8 +154,6 @@ convex-skills/
133
154
  ├── skills/ # Core Convex skills for AI agents
134
155
  │ ├── convex-best-practices/
135
156
  │ │ └── SKILL.md
136
- │ ├── convex-eslint/
137
- │ │ └── SKILL.md
138
157
  │ ├── convex-functions/
139
158
  │ │ └── SKILL.md
140
159
  │ ├── convex-cron-jobs/
@@ -142,6 +161,7 @@ convex-skills/
142
161
  │ └── ...
143
162
  ├── .codex/ # Codex integration (symlink skills here)
144
163
  │ └── README.md # Codex setup instructions
164
+ ├── .agents/ # Standard agent skills path
145
165
  ├── command/ # Slash command definitions (OpenCode)
146
166
  │ └── convex.md # /convex command entrypoint
147
167
  ├── templates/ # Templates for forking developers
package/bin/cli.js CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  existsSync,
10
10
  copyFileSync,
11
11
  readdirSync,
12
+ symlinkSync,
12
13
  } from "fs";
13
14
 
14
15
  const __filename = fileURLToPath(import.meta.url);
@@ -18,7 +19,6 @@ const packageRoot = join(__dirname, "..");
18
19
  const SKILLS = {
19
20
  "convex-best-practices":
20
21
  "Guidelines for building production-ready Convex apps",
21
- "convex-eslint": "Write linter-compliant Convex code",
22
22
  "convex-functions": "Writing queries, mutations, actions, and HTTP actions",
23
23
  "convex-realtime": "Patterns for building reactive applications",
24
24
  "convex-schema-validator": "Database schema definition and validation",
@@ -32,6 +32,12 @@ const SKILLS = {
32
32
  "convex-component-authoring": "Creating reusable Convex components",
33
33
  };
34
34
 
35
+ const TARGET_ALIASES = new Map([
36
+ ["claude", ".claude/skills"],
37
+ ["codex", ".codex/skills"],
38
+ ["agents", ".agents/skills"],
39
+ ]);
40
+
35
41
  function printHelp() {
36
42
  console.log(`
37
43
  convex-skills - Agent skills for building Convex applications
@@ -49,12 +55,17 @@ COMMANDS:
49
55
 
50
56
  OPTIONS:
51
57
  --dir <path> Target directory (default: current directory)
58
+ --target <name|path> Install target: claude, codex, agents, or a path
59
+ --link Symlink SKILL.md instead of copying
52
60
  --help, -h Show this help message
53
61
 
54
62
  EXAMPLES:
55
63
  convex-skills list
56
64
  convex-skills install convex-best-practices
57
65
  convex-skills install-all
66
+ convex-skills install-all --target agents
67
+ convex-skills install convex-functions --target .agents/skills
68
+ convex-skills install convex-best-practices --target codex --link
58
69
  convex-skills install-templates
59
70
  convex-skills show convex-functions
60
71
 
@@ -73,7 +84,27 @@ function listSkills() {
73
84
  console.log("");
74
85
  }
75
86
 
76
- function installSkill(skillName, targetDir) {
87
+ function ensureDir(dirPath) {
88
+ if (!existsSync(dirPath)) {
89
+ mkdirSync(dirPath, { recursive: true });
90
+ }
91
+ }
92
+
93
+ function resolveTargetSkillsDir(targetDir, target) {
94
+ if (!target) {
95
+ return join(targetDir, ".claude", "skills");
96
+ }
97
+
98
+ const alias = TARGET_ALIASES.get(target);
99
+ if (alias) {
100
+ return join(targetDir, alias);
101
+ }
102
+
103
+ const resolved = resolve(targetDir, target);
104
+ return resolved.endsWith("skills") ? resolved : join(resolved, "skills");
105
+ }
106
+
107
+ function installSkill(skillName, targetSkillsDir, useSymlink) {
77
108
  const skillsPath = join(packageRoot, "skills", skillName, "SKILL.md");
78
109
 
79
110
  if (!existsSync(skillsPath)) {
@@ -82,24 +113,24 @@ function installSkill(skillName, targetDir) {
82
113
  process.exit(1);
83
114
  }
84
115
 
85
- const targetPath = join(
86
- targetDir,
87
- ".claude",
88
- "skills",
89
- skillName,
90
- "SKILL.md",
91
- );
116
+ const targetPath = join(targetSkillsDir, skillName, "SKILL.md");
92
117
  const targetSkillDir = dirname(targetPath);
93
118
 
94
- if (!existsSync(targetSkillDir)) {
95
- mkdirSync(targetSkillDir, { recursive: true });
119
+ ensureDir(targetSkillDir);
120
+
121
+ if (useSymlink) {
122
+ if (!existsSync(targetPath)) {
123
+ symlinkSync(skillsPath, targetPath);
124
+ }
125
+ console.log(`Linked ${skillName} to ${targetPath}`);
126
+ return;
96
127
  }
97
128
 
98
129
  copyFileSync(skillsPath, targetPath);
99
130
  console.log(`Installed ${skillName} to ${targetPath}`);
100
131
  }
101
132
 
102
- function installAllSkills(targetDir) {
133
+ function installAllSkills(targetSkillsDir, useSymlink) {
103
134
  const skillsDir = join(packageRoot, "skills");
104
135
  const skills = readdirSync(skillsDir, { withFileTypes: true })
105
136
  .filter((dirent) => dirent.isDirectory())
@@ -108,11 +139,11 @@ function installAllSkills(targetDir) {
108
139
  console.log(`Installing ${skills.length} skills...\n`);
109
140
 
110
141
  skills.forEach((skillName) => {
111
- installSkill(skillName, targetDir);
142
+ installSkill(skillName, targetSkillsDir, useSymlink);
112
143
  });
113
144
 
114
145
  console.log(
115
- `\nDone! Installed ${skills.length} skills to ${join(targetDir, ".claude", "skills")}`,
146
+ `\nDone! Installed ${skills.length} skills to ${targetSkillsDir}`,
116
147
  );
117
148
  }
118
149
 
@@ -139,9 +170,7 @@ function installTemplates(targetDir) {
139
170
  );
140
171
  const targetSkillsDir = join(targetDir, ".claude", "skills");
141
172
 
142
- if (!existsSync(targetSkillsDir)) {
143
- mkdirSync(targetSkillsDir, { recursive: true });
144
- }
173
+ ensureDir(targetSkillsDir);
145
174
 
146
175
  templates.forEach((template) => {
147
176
  const src = join(skillTemplatesDir, template);
@@ -184,6 +213,8 @@ function printSkillPath(skillName) {
184
213
  // Parse arguments
185
214
  const args = process.argv.slice(2);
186
215
  let targetDir = process.cwd();
216
+ let target = null;
217
+ let useSymlink = false;
187
218
 
188
219
  // Check for --dir flag
189
220
  const dirIndex = args.indexOf("--dir");
@@ -192,8 +223,21 @@ if (dirIndex !== -1 && args[dirIndex + 1]) {
192
223
  args.splice(dirIndex, 2);
193
224
  }
194
225
 
226
+ const targetIndex = args.indexOf("--target");
227
+ if (targetIndex !== -1 && args[targetIndex + 1]) {
228
+ target = args[targetIndex + 1];
229
+ args.splice(targetIndex, 2);
230
+ }
231
+
232
+ const linkIndex = args.indexOf("--link");
233
+ if (linkIndex !== -1) {
234
+ useSymlink = true;
235
+ args.splice(linkIndex, 1);
236
+ }
237
+
195
238
  const command = args[0];
196
239
  const arg = args[1];
240
+ const targetSkillsDir = resolveTargetSkillsDir(targetDir, target);
197
241
 
198
242
  switch (command) {
199
243
  case "list":
@@ -205,10 +249,10 @@ switch (command) {
205
249
  console.log("Run 'convex-skills list' to see available skills.");
206
250
  process.exit(1);
207
251
  }
208
- installSkill(arg, targetDir);
252
+ installSkill(arg, targetSkillsDir, useSymlink);
209
253
  break;
210
254
  case "install-all":
211
- installAllSkills(targetDir);
255
+ installAllSkills(targetSkillsDir, useSymlink);
212
256
  break;
213
257
  case "install-templates":
214
258
  installTemplates(targetDir);
package/index.js CHANGED
@@ -54,7 +54,6 @@ export function getSkillPath(skillName) {
54
54
  export const SKILLS = {
55
55
  "convex-best-practices":
56
56
  "Guidelines for building production-ready Convex apps",
57
- "convex-eslint": "Write linter-compliant Convex code",
58
57
  "convex-functions": "Writing queries, mutations, actions, and HTTP actions",
59
58
  "convex-realtime": "Patterns for building reactive applications",
60
59
  "convex-schema-validator": "Database schema definition and validation",
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@waynesutton/convex-skills",
3
- "version": "1.0.7",
4
- "description": "Agent skills for building production-ready Convex applications. Includes best practices, functions, realtime patterns, schema validation, file storage, security audits, and more.",
5
- "author": "Wayne Sutton",
3
+ "version": "1.0.9",
4
+ "description": "For official Convex Skills use Convex Agent Plugins at https://github.com/get-convex/convex-agent-plugins. This package provides unofficial agent skills for building production-ready Convex applications.",
5
+ "author": "Wayne Sutton - @waynesutton",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -9,14 +9,32 @@ Build production-ready Convex applications by following established patterns for
9
9
 
10
10
  ## Code Quality
11
11
 
12
- All patterns in this skill comply with @convex-dev/eslint-plugin rules.
13
- Install the linter for build-time validation:
12
+ All patterns in this skill comply with `@convex-dev/eslint-plugin`. Install it for build-time validation:
14
13
 
15
14
  ```bash
16
15
  npm i @convex-dev/eslint-plugin --save-dev
17
16
  ```
18
17
 
19
- See [convex-eslint](../convex-eslint/SKILL.md) for configuration details.
18
+ ```js
19
+ // eslint.config.js
20
+ import { defineConfig } from "eslint/config";
21
+ import convexPlugin from "@convex-dev/eslint-plugin";
22
+
23
+ export default defineConfig([
24
+ ...convexPlugin.configs.recommended,
25
+ ]);
26
+ ```
27
+
28
+ The plugin enforces four rules:
29
+
30
+ | Rule | What it enforces |
31
+ | ----------------------------------- | --------------------------------- |
32
+ | `no-old-registered-function-syntax` | Object syntax with `handler` |
33
+ | `require-argument-validators` | `args: {}` on all functions |
34
+ | `explicit-table-ids` | Table name in db operations |
35
+ | `import-wrong-runtime` | No Node imports in Convex runtime |
36
+
37
+ Docs: https://docs.convex.dev/eslint
20
38
 
21
39
  ## Documentation Sources
22
40
 
@@ -19,7 +19,7 @@ All examples in this skill comply with @convex-dev/eslint-plugin rules:
19
19
  - Argument validators on all functions
20
20
  - Explicit table names in database operations
21
21
 
22
- See [convex-eslint](../convex-eslint/SKILL.md) for linting setup.
22
+ See the Code Quality section in [convex-best-practices](../convex-best-practices/SKILL.md) for linting setup.
23
23
 
24
24
  ## Documentation Sources
25
25
 
@@ -1,145 +0,0 @@
1
- ---
2
- name: convex-eslint
3
- description: Write Convex code that passes @convex-dev/eslint-plugin rules by default
4
- version: 1.0.0
5
- author: Convex
6
- tags: [convex, eslint, linting, code-quality, validation]
7
- ---
8
-
9
- # Convex ESLint Compliance
10
-
11
- Write all Convex functions to pass @convex-dev/eslint-plugin. These rules prevent common bugs, security issues, and ensure code quality.
12
-
13
- ## Documentation Sources
14
-
15
- - https://docs.convex.dev/eslint
16
- - https://www.npmjs.com/package/@convex-dev/eslint-plugin
17
-
18
- ## Setup
19
-
20
- Install the plugin:
21
-
22
- ```bash
23
- npm i @convex-dev/eslint-plugin --save-dev
24
- ```
25
-
26
- Configure `eslint.config.js`:
27
-
28
- ```javascript
29
- import { defineConfig } from "eslint/config";
30
- import convexPlugin from "@convex-dev/eslint-plugin";
31
-
32
- export default defineConfig([...convexPlugin.configs.recommended]);
33
- ```
34
-
35
- ## Rules
36
-
37
- ### 1. no-old-registered-function-syntax
38
-
39
- Always use object syntax with a `handler` property.
40
-
41
- ```typescript
42
- // Correct
43
- export const list = query({
44
- args: {},
45
- handler: async (ctx) => {
46
- return await ctx.db.query("messages").collect();
47
- },
48
- });
49
-
50
- // Wrong - bare function syntax
51
- export const list = query(async (ctx) => {
52
- return await ctx.db.query("messages").collect();
53
- });
54
- ```
55
-
56
- ### 2. require-argument-validators
57
-
58
- Always include `args` object, even when empty.
59
-
60
- ```typescript
61
- // Correct - with arguments
62
- export const get = query({
63
- args: { id: v.id("messages") },
64
- handler: async (ctx, { id }) => {
65
- return await ctx.db.get("messages", id);
66
- },
67
- });
68
-
69
- // Correct - no arguments
70
- export const listAll = query({
71
- args: {},
72
- handler: async (ctx) => {
73
- return await ctx.db.query("messages").collect();
74
- },
75
- });
76
-
77
- // Wrong - missing args
78
- export const get = query({
79
- handler: async (ctx, { id }: { id: Id<"messages"> }) => {
80
- return await ctx.db.get("messages", id);
81
- },
82
- });
83
- ```
84
-
85
- ### 3. explicit-table-ids
86
-
87
- Use explicit table names in all database operations (Convex 1.31.0+).
88
-
89
- ```typescript
90
- // Correct
91
- const message = await ctx.db.get("messages", messageId);
92
- await ctx.db.patch("messages", messageId, { text: "updated" });
93
- await ctx.db.replace("messages", messageId, {
94
- text: "replaced",
95
- author: "Alice",
96
- });
97
- await ctx.db.delete("messages", messageId);
98
-
99
- // Wrong - implicit table from ID type
100
- const message = await ctx.db.get(messageId);
101
- await ctx.db.patch(messageId, { text: "updated" });
102
- await ctx.db.replace(messageId, { text: "replaced", author: "Alice" });
103
- await ctx.db.delete(messageId);
104
- ```
105
-
106
- Migration codemod available:
107
-
108
- ```bash
109
- npx @convex-dev/codemod@latest explicit-ids
110
- ```
111
-
112
- ### 4. import-wrong-runtime
113
-
114
- Never import Node.js runtime files into Convex runtime files.
115
-
116
- ```typescript
117
- // convex/queries.ts (no "use node" directive)
118
-
119
- // Correct - importing from Convex runtime file
120
- import { helper } from "./utils"; // utils.ts has no "use node"
121
-
122
- // Wrong - importing from Node runtime file
123
- import { nodeHelper } from "./nodeUtils"; // nodeUtils.ts has "use node"
124
- ```
125
-
126
- ## Best Practices
127
-
128
- 1. Run ESLint before committing: `npx eslint convex/`
129
- 2. Use auto-fix for quick migrations: `npx eslint convex/ --fix`
130
- 3. Add to CI pipeline to catch violations early
131
- 4. Configure your editor for real-time feedback
132
-
133
- ## Quick Reference
134
-
135
- | Rule | What it enforces |
136
- | ----------------------------------- | --------------------------------- |
137
- | `no-old-registered-function-syntax` | Object syntax with `handler` |
138
- | `require-argument-validators` | `args: {}` on all functions |
139
- | `explicit-table-ids` | Table name in db operations |
140
- | `import-wrong-runtime` | No Node imports in Convex runtime |
141
-
142
- ## References
143
-
144
- - [ESLint Plugin Docs](https://docs.convex.dev/eslint)
145
- - [Explicit IDs Announcement](https://news.convex.dev/db-table-name/)