skillex 0.2.0 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.1] - 2026-04-07
11
+
12
+ ### Changed
13
+ - Skills and generated symlink sources are now stored in `~/.skillex/` (user-level) instead of `<project>/.agent-skills/`, so a single install is shared across all workspaces and symlinks always resolve correctly
14
+ - `claude` adapter: switched from managed-block in `CLAUDE.md` to a dedicated file at `.claude/skills/skillex-skills.md`; old `CLAUDE.md` block cleaned up automatically on next `sync`
15
+ - `gemini` adapter: switched from managed-block in `GEMINI.md` to a dedicated file at `.gemini/skills/skillex-skills.md`; old `GEMINI.md` block cleaned up automatically on next `sync`
16
+ - `codex` adapter: switched from managed-block in `AGENTS.md` to a dedicated file at `.codex/skills/skillex-skills.md` (introduced in this cycle)
17
+ - Symlinks are now absolute paths instead of relative, ensuring they work regardless of project depth
18
+ - `copilot` is now the only adapter that uses managed-block injection
19
+ - `--agent-skills-dir` flag still overrides to a project-local directory when isolation is needed
20
+
10
21
  ## [0.2.0] - 2026-04-07
11
22
 
12
23
  ### Added
package/README.md CHANGED
@@ -42,10 +42,13 @@ npx skillex@latest list
42
42
  # 3. Install a skill
43
43
  npx skillex@latest install create-skills
44
44
 
45
- # 4. Sync skills into your agent's config file
45
+ # 4. Write the installed skills into your agent's config file
46
+ # ⚠️ This step is required — without it, your agent cannot see the skills.
46
47
  npx skillex@latest sync
47
48
  ```
48
49
 
50
+ > **Important:** `install` downloads skill files locally. `sync` is what actually writes the skill instructions into your agent's configuration file (e.g. `.claude/skills/skillex-skills.md`, `.codex/skills/skillex-skills.md`, `.github/copilot-instructions.md`). **You must run `sync` after every install or update for your agent to pick up the changes.** Use `--auto-sync` at `init` time to have this happen automatically.
51
+
49
52
  After `init`, Skillex saves the configured source list in the local lockfile. New workspaces start with `lgili/skillex@main` by default, and you can add more sources later with `skillex source add`.
50
53
 
51
54
  ---
@@ -162,6 +165,8 @@ skillex install owner/repo/path/to/skill@main --trust
162
165
  | `--repo <owner/repo>` | Limit resolution to a single source when needed. |
163
166
  | `--trust` | Skip confirmation prompt for direct GitHub installs. |
164
167
 
168
+ > **After installing,** run `skillex sync` to write the skills into your agent's config file. Without this step, the agent will not see the newly installed skills. If you initialized with `--auto-sync`, this happens automatically.
169
+
165
170
  ---
166
171
 
167
172
  ### `update`
@@ -191,7 +196,7 @@ skillex rm git-master code-review
191
196
 
192
197
  ### `sync`
193
198
 
194
- Write all installed skills into the active adapter's config file.
199
+ Write all installed skills into the active adapter's config file (e.g. `.claude/skills/skillex-skills.md`, `.codex/skills/skillex-skills.md`, `.github/copilot-instructions.md`). **This is the step that makes skills visible to your AI agent.** Run it after every `install`, `update`, or `remove`.
195
200
 
196
201
  ```bash
197
202
  # Sync to the detected adapter
@@ -213,6 +218,25 @@ skillex sync --mode copy
213
218
  | `--adapter <id>` | Override the active adapter for this sync. |
214
219
  | `--mode copy\|symlink` | File write strategy (default: `symlink` for dedicated-file adapters). |
215
220
 
221
+ #### Using multiple agents in the same workspace
222
+
223
+ `sync` writes to one adapter at a time. If you use more than one AI agent in the same folder (e.g. Claude and Codex), run `sync` once for each:
224
+
225
+ ```bash
226
+ # Write skills into .claude/skills/skillex-skills.md
227
+ skillex sync --adapter claude
228
+
229
+ # Write skills into .codex/skills/skillex-skills.md
230
+ skillex sync --adapter codex
231
+ ```
232
+
233
+ Each adapter writes to its own target file, so the two syncs are independent and non-destructive. To avoid running both commands manually after every change, initialize with `--auto-sync` and then re-run `skillex init --adapter <id>` for each adapter you want covered — or simply alias both commands in your workflow:
234
+
235
+ ```bash
236
+ # Sync to all agents at once (shell alias / Makefile target)
237
+ skillex sync --adapter claude && skillex sync --adapter codex
238
+ ```
239
+
216
240
  ---
217
241
 
218
242
  ### `run`
@@ -337,17 +361,19 @@ Skillex auto-detects the AI agent you use by looking for known marker files in y
337
361
 
338
362
  | Adapter ID | Agent | Detection Markers | Sync Target |
339
363
  |------------|-------|-------------------|-------------|
340
- | `codex` | OpenAI Codex | `AGENTS.md`, `.codex/` | `AGENTS.md` |
364
+ | `codex` | OpenAI Codex | `AGENTS.md`, `.codex/` | `.codex/skills/skillex-skills.md` |
341
365
  | `copilot` | GitHub Copilot | `.github/copilot-instructions.md` | `.github/copilot-instructions.md` |
342
366
  | `cline` | Cline / Roo Code | `.cline/`, `.roo/`, `.clinerules` | `.clinerules/skillex-skills.md` |
343
367
  | `cursor` | Cursor | `.cursor/`, `.cursorrules` | `.cursor/rules/skillex-skills.mdc` |
344
- | `claude` | Claude Code | `CLAUDE.md`, `.claude/` | `CLAUDE.md` |
345
- | `gemini` | Gemini CLI | `GEMINI.md`, `.gemini/` | `GEMINI.md` |
368
+ | `claude` | Claude Code | `CLAUDE.md`, `.claude/` | `.claude/skills/skillex-skills.md` |
369
+ | `gemini` | Gemini CLI | `GEMINI.md`, `.gemini/` | `.gemini/skills/skillex-skills.md` |
346
370
  | `windsurf` | Windsurf | `.windsurf/`, `.windsurf/rules/` | `.windsurf/rules/skillex-skills.md` |
347
371
 
348
- **Shared-file adapters** (`codex`, `copilot`, `claude`, `gemini`) use a **managed block** — Skillex writes between `<!-- SKILLEX:START -->` and `<!-- SKILLEX:END -->` markers while preserving everything else in the file.
372
+ **Shared-file adapter** (`copilot`) uses a **managed block** — Skillex writes between `<!-- SKILLEX:START -->` and `<!-- SKILLEX:END -->` markers inside `.github/copilot-instructions.md`, preserving everything else in the file.
373
+
374
+ **Dedicated-file adapters** (`codex`, `cline`, `claude`, `cursor`, `gemini`, `windsurf`) each generate a file in `~/.skillex/generated/<adapter>/` and create an absolute symlink at the adapter's target path (e.g. `.claude/skills/skillex-skills.md`). Use `--mode copy` to write directly instead.
349
375
 
350
- **Dedicated-file adapters** (`cline`, `cursor`, `windsurf`) generate a file in `.agent-skills/generated/` and create a relative symlink at the adapter's target path. Use `--mode copy` to write directly instead.
376
+ > **Migrating from a previous version?** If you had skill content injected into `CLAUDE.md`, `GEMINI.md`, or `AGENTS.md` by an older version of Skillex, those legacy files are cleaned up automatically on the next `sync`. You can also remove the block manually.
351
377
 
352
378
  Compatibility aliases are normalized automatically: `claude-code` → `claude`, `github-copilot` → `copilot`, `roo-code` → `cline`, `gemini-cli` → `gemini`.
353
379
 
package/dist/adapters.js CHANGED
@@ -10,8 +10,8 @@ const ADAPTERS = [
10
10
  { path: ".codex", weight: 12 },
11
11
  { path: ".codex/skills", weight: 16 },
12
12
  ],
13
- syncTarget: "AGENTS.md",
14
- syncMode: "managed-block",
13
+ syncTarget: ".codex/skills/skillex-skills.md",
14
+ syncMode: "managed-file",
15
15
  },
16
16
  {
17
17
  id: "copilot",
@@ -52,8 +52,9 @@ const ADAPTERS = [
52
52
  { path: "CLAUDE.md", weight: 16 },
53
53
  { path: ".claude", weight: 18 },
54
54
  ],
55
- syncTarget: "CLAUDE.md",
56
- syncMode: "managed-block",
55
+ syncTarget: ".claude/skills/skillex-skills.md",
56
+ legacySyncTargets: ["CLAUDE.md"],
57
+ syncMode: "managed-file",
57
58
  },
58
59
  {
59
60
  id: "gemini",
@@ -62,8 +63,9 @@ const ADAPTERS = [
62
63
  { path: "GEMINI.md", weight: 16 },
63
64
  { path: ".gemini", weight: 18 },
64
65
  ],
65
- syncTarget: "GEMINI.md",
66
- syncMode: "managed-block",
66
+ syncTarget: ".gemini/skills/skillex-skills.md",
67
+ legacySyncTargets: ["GEMINI.md"],
68
+ syncMode: "managed-file",
67
69
  },
68
70
  {
69
71
  id: "windsurf",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as path from "node:path";
2
2
  import { listAdapters } from "./adapters.js";
3
3
  import { computeCatalogCacheKey, loadCatalog, readCatalogCache, searchCatalogSkills, } from "./catalog.js";
4
- import { DEFAULT_AGENT_SKILLS_DIR, getStatePaths } from "./config.js";
4
+ import { DEFAULT_AGENT_SKILLS_DIR, getDefaultSkillsDir, getStatePaths } from "./config.js";
5
5
  import { addProjectSource, getInstalledSkills, initProject, installSkills, listProjectSources, loadProjectCatalogs, removeProjectSource, removeSkills, resolveProjectSource, syncInstalledSkills, updateInstalledSkills, } from "./install.js";
6
6
  import * as output from "./output.js";
7
7
  import { setVerbose } from "./output.js";
@@ -750,12 +750,15 @@ function commonOptions(flags, userConfig = {}) {
750
750
  options.timeout = timeout;
751
751
  if (noCache !== undefined)
752
752
  options.noCache = noCache;
753
+ // Default to user-level storage so symlinks always point to a stable path.
754
+ if (!options.agentSkillsDir)
755
+ options.agentSkillsDir = getDefaultSkillsDir();
753
756
  return options;
754
757
  }
755
758
  /** Returns cache-related options to spread into a loadCatalog call. */
756
759
  function cacheOptions(opts) {
757
760
  const cwd = opts.cwd ?? process.cwd();
758
- const stateDir = path.join(cwd, opts.agentSkillsDir ?? DEFAULT_AGENT_SKILLS_DIR);
761
+ const stateDir = path.resolve(cwd, opts.agentSkillsDir ?? getDefaultSkillsDir());
759
762
  return {
760
763
  cacheDir: path.join(stateDir, ".cache"),
761
764
  ...(opts.noCache !== undefined ? { noCache: opts.noCache } : {}),
package/dist/config.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import type { StatePaths } from "./types.js";
2
2
  export declare const DEFAULT_AGENT_SKILLS_DIR = ".agent-skills";
3
+ /**
4
+ * Returns the default user-level Skillex directory (`~/.skillex`).
5
+ */
6
+ export declare function getDefaultSkillsDir(): string;
3
7
  export declare const DEFAULT_LOCKFILE = "skills.json";
4
8
  export declare const DEFAULT_LOCAL_SKILLS_DIR = "skills";
5
9
  export declare const DEFAULT_GENERATED_DIR = "generated";
package/dist/config.js CHANGED
@@ -1,5 +1,12 @@
1
+ import * as os from "node:os";
1
2
  import * as path from "node:path";
2
3
  export const DEFAULT_AGENT_SKILLS_DIR = ".agent-skills";
4
+ /**
5
+ * Returns the default user-level Skillex directory (`~/.skillex`).
6
+ */
7
+ export function getDefaultSkillsDir() {
8
+ return path.join(os.homedir(), ".skillex");
9
+ }
3
10
  export const DEFAULT_LOCKFILE = "skills.json";
4
11
  export const DEFAULT_LOCAL_SKILLS_DIR = "skills";
5
12
  export const DEFAULT_GENERATED_DIR = "generated";
package/dist/fs.js CHANGED
@@ -97,15 +97,15 @@ export async function removePath(targetPath) {
97
97
  * @returns Symlink creation result.
98
98
  */
99
99
  export async function createSymlink(targetPath, linkPath) {
100
- const relativeTarget = path.relative(path.dirname(linkPath), targetPath) || ".";
100
+ const absoluteTarget = path.resolve(targetPath);
101
101
  await ensureDir(path.dirname(linkPath));
102
102
  await removePath(linkPath);
103
103
  try {
104
- await fs.symlink(relativeTarget, linkPath);
104
+ await fs.symlink(absoluteTarget, linkPath);
105
105
  return {
106
106
  ok: true,
107
107
  fallback: false,
108
- relativeTarget,
108
+ relativeTarget: absoluteTarget,
109
109
  };
110
110
  }
111
111
  catch (error) {
@@ -116,7 +116,7 @@ export async function createSymlink(targetPath, linkPath) {
116
116
  return {
117
117
  ok: false,
118
118
  fallback: true,
119
- relativeTarget,
119
+ relativeTarget: absoluteTarget,
120
120
  };
121
121
  }
122
122
  throw error;
package/dist/sync.js CHANGED
@@ -139,7 +139,7 @@ export async function prepareSyncAdapterFiles(options) {
139
139
  const generatedSourcePath = path.join(options.statePaths.generatedDirPath, adapter.id, path.basename(adapter.syncTarget));
140
140
  const currentDescriptor = await describeTarget(targetPath);
141
141
  const currentVisibleContent = (await readText(targetPath, "")) || "";
142
- const nextDescriptor = `symlink -> ${toPosix(path.relative(path.dirname(targetPath), generatedSourcePath))}\n`;
142
+ const nextDescriptor = `symlink -> ${toPosix(generatedSourcePath)}\n`;
143
143
  const descriptorChanged = normalizeComparableText(currentDescriptor) !== normalizeComparableText(nextDescriptor);
144
144
  const contentChanged = normalizeComparableText(currentVisibleContent) !== normalizeComparableText(nextContent);
145
145
  return {
@@ -154,7 +154,7 @@ export async function prepareSyncAdapterFiles(options) {
154
154
  targetPath: relativeTargetPath,
155
155
  currentDescriptor,
156
156
  nextDescriptor,
157
- generatedPath: toPosix(path.relative(options.cwd, generatedSourcePath)),
157
+ generatedPath: toPosix(generatedSourcePath),
158
158
  currentContent: currentVisibleContent,
159
159
  nextContent,
160
160
  }),
@@ -237,6 +237,9 @@ function buildManagedFileContent(adapterId, body, autoInjectBlock) {
237
237
  "",
238
238
  ].join("\n");
239
239
  case "cline":
240
+ case "codex":
241
+ case "claude":
242
+ case "gemini":
240
243
  return `${sections.join("\n\n")}\n`;
241
244
  default:
242
245
  throw new SyncError(`Adapter desconhecido: ${adapterId}`, "SYNC_ADAPTER_UNKNOWN");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillex",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI to list, install, and synchronize AI agent skills from GitHub-hosted catalogs.",
5
5
  "type": "module",
6
6
  "repository": {