{"id":50139447,"url":"https://github.com/ctxr-dev/kit","last_synced_at":"2026-05-24T00:06:19.636Z","repository":{"id":351081031,"uuid":"1209496830","full_name":"ctxr-dev/kit","owner":"ctxr-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-21T00:22:38.000Z","size":312,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T05:53:49.371Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ctxr-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-13T13:40:52.000Z","updated_at":"2026-04-18T23:02:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ctxr-dev/kit","commit_stats":null,"previous_names":["ctxr-dev/kit"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/ctxr-dev/kit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctxr-dev%2Fkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctxr-dev%2Fkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctxr-dev%2Fkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctxr-dev%2Fkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ctxr-dev","download_url":"https://codeload.github.com/ctxr-dev/kit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctxr-dev%2Fkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33416317,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"ssl_error","status_checked_at":"2026-05-23T22:14:43.778Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-24T00:06:18.719Z","updated_at":"2026-05-24T00:06:19.625Z","avatar_url":"https://github.com/ctxr-dev.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @ctxr/kit\n\n[![npm](https://img.shields.io/npm/v/@ctxr/kit)](https://www.npmjs.com/package/@ctxr/kit)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Agent Skills](https://img.shields.io/badge/Agent%20Skills-Claude%20Code%20%7C%20Codex%20CLI-blue)](https://agentskills.io)\n\nUniversal CLI for [Agent Skills](https://agentskills.io) artifacts: install,\nvalidate, update, and scaffold **skills, agents, commands, rules,\noutput-styles, and teams** for Claude Code, OpenAI Codex CLI, and any other\nharness that follows the open Agent Skills standard. The canonical install\nlocation is `.agents/\u003ctype\u003e/\u003cname\u003e/` (project) and `~/.agents/\u003ctype\u003e/\u003cname\u003e/`\n(user); kit auto-creates discovery-mirror symlinks at `.claude/\u003ctype\u003e/\u003cname\u003e`\nand `~/.codex/\u003ctype\u003e/\u003cname\u003e` so harnesses that don't read `.agents/` natively\nstill find the artefact. The `package.json` `files` field is the single\nsource of truth for what each package ships, and the manifest filename\n`.ctxr-manifest.json` is written per install root. Run the CLI via\n`npx @ctxr/kit`; no global install required.\n\n## Quick start\n\n```bash\nnpx @ctxr/kit install @ctxr/skill-code-review     # add the code-review skill\nnpx @ctxr/kit list                                # see what's installed\n```\n\nThat's the whole loop. Run `npx @ctxr/kit --help` for the full command set.\n\n## Prerequisites\n\n- **Node.js ≥ 18.0.0** (uses ESM, `node:test`, and the modern `node:fs` API)\n- A project directory where you want artifacts installed. Project-scope\n  installs land canonically under `.agents/\u003ctype\u003e/`; user-scope installs\n  (`--user`) land canonically under `~/.agents/\u003ctype\u003e/`. Discovery-mirror\n  symlinks at `.claude/\u003ctype\u003e/` (and `~/.codex/\u003ctype\u003e/` at user scope)\n  are created automatically so Claude Code and Codex CLI both find every\n  installed artefact without extra configuration.\n\n## Install\n\nKit is run exclusively via `npx` — no global install required.\n\n```bash\nnpx @ctxr/kit \u003ccommand\u003e\n```\n\nEvery example below uses the `npx @ctxr/kit` form. If you prefer a short\nalias, add one to your shell (`alias kit='npx @ctxr/kit'`) — kit itself\nnever asks you to install it globally.\n\n## Interactive mode (default)\n\n`kit` is **interactive by default**. In a terminal, every command that has\na choice to make prompts you with an arrow-key menu or a short question:\n\n- `install` shows a destination menu with the canonical candidate\n  locations (`.agents/\u003ctype\u003e/`, `~/.agents/\u003ctype\u003e/`, or a custom path\n  you type) and pre-highlights the one kit would auto-pick.\n- For any artifact you're installing that's already installed at a\n  *different* location than you just picked, `install` asks per-item\n  whether to **keep** it there (update in place) or **move** it to the\n  chosen destination.\n- `update` pre-flights the list — if any identifier you named isn't\n  installed yet, it prints the missing list and exits so you don't\n  silently update \"everything except those\".\n- `remove` that finds an artifact in multiple locations asks which one to\n  remove. Missing identifiers are soft-skipped with a one-line note.\n- `init` runs a 9-question wizard (type, name, author, description,\n  license, target, overwrite confirmation, git init, npm install) with\n  smart defaults drawn from `git config` and the current directory name.\n\n### Non-interactive / scripted use\n\nNon-interactive mode kicks in automatically in three cases, no flag\nrequired:\n\n1. **`CI=true`** environment variable is set (GitHub Actions, GitLab CI,\n   CircleCI, Travis, Buildkite, and most other CI runners set this).\n2. **stdin is not a TTY** (e.g. `kit install X \u003c /dev/null`, or kit\n   running under `spawn()` with piped stdio).\n3. **Explicit `--yes` / `-y`** flag on the command line.\n\nIn non-interactive mode every prompt resolves to its declared default, and\n`install` never destructively moves an existing install — it updates in\nplace at whatever location the artifact is currently at. This keeps\nautomation stable: pipelines that run `npx @ctxr/kit install X` will\nalways land the artifact in a predictable place.\n\n```bash\n# All equivalent — all three trigger silent, no-prompt behavior:\nnpx @ctxr/kit install @ctxr/skill-code-review --yes\nCI=true npx @ctxr/kit install @ctxr/skill-code-review\nnpx @ctxr/kit install @ctxr/skill-code-review \u003c /dev/null\n```\n\n### Forcing interactive mode in CI\n\nIf you need prompts even under `CI=true` (rare, but useful in dev\ncontainers), pass `-i` / `--interactive`. That flag overrides all three\nauto-detection triggers.\n\n## Artifact types\n\n`kit` understands every artifact type the Agent Skills standard recognises,\nplus a `team` meta-type that bundles several of them into a single\ninstallable package.\n\n| Type           | Canonical install path           | `ctxr.target`     | Typical payload          |\n|----------------|----------------------------------|-------------------|--------------------------|\n| `skill`        | `.agents/skills/\u003cname\u003e/`         | `folder`          | `SKILL.md` + assets      |\n| `agent`        | `.agents/agents/\u003cname\u003e.md`       | `file` or `folder`| Single `.md` (or bundle) |\n| `command`      | `.agents/commands/\u003cname\u003e.md`     | `file`            | Single `.md`             |\n| `rule`         | `.agents/rules/\u003cname\u003e.md`        | `file`            | Single `.md`             |\n| `output-style` | `.agents/output-styles/\u003cname\u003e.md`| `file`            | Single `.md`             |\n| `team`         | (cascades to `ctxr.includes`)    | n/a               | No payload               |\n\nEach canonical install also gets a discovery-mirror symlink at\n`.claude/\u003ctype\u003e/\u003cname\u003e` (project) and `~/.codex/\u003ctype\u003e/\u003cname\u003e` (user\nscope) so Claude Code and Codex CLI both auto-discover the artefact;\nsee [Install locations](#install-locations) below.\n\n## Per-package schema\n\nEvery artifact package declares a `ctxr` block in its `package.json`. Only\n`type` and `target` (or `includes` for teams) are required — kit reads\nnothing else. The npm-native `files` field is the **single source of truth**\nfor what ships in the package.\n\n```json\n{\n  \"name\": \"@ctxr/skill-code-review\",\n  \"version\": \"1.0.5\",\n  \"files\": [\n    \"SKILL.md\",\n    \"code-reviewer.md\",\n    \"reviewers\",\n    \"overlays\",\n    \"README.md\",\n    \"LICENSE\"\n  ],\n  \"ctxr\": {\n    \"type\": \"skill\",\n    \"target\": \"folder\"\n  }\n}\n```\n\n```json\n{\n  \"name\": \"@ctxr/team-full-stack\",\n  \"files\": [\"README.md\"],\n  \"ctxr\": {\n    \"type\": \"team\",\n    \"includes\": [\n      \"@ctxr/skill-code-review\",\n      \"@ctxr/agent-researcher\",\n      \"@ctxr/rule-typescript-strict\"\n    ]\n  }\n}\n```\n\n- **`ctxr.type`** — one of `skill | agent | command | rule | output-style | team`. Picks the destination directory.\n- **`ctxr.target`** — `\"folder\"` (wrap full payload in a folder) or `\"file\"` (copy the single payload file flat). Required for every non-team type.\n- **`ctxr.includes`** — required only for teams. Array of package specs to install when this team is installed.\n\n`kit` never introduces a second copy list. There is no `ctxr.copy`, no\n`ctxr.entry`, no prefix-inferred type. If `npm pack` would ship it, `kit`\ninstalls it; if not, it doesn't.\n\n## Commands\n\n### `npx @ctxr/kit install \u003csource\u003e [\u003csource\u003e...] [options]`\n\nInstall one or more artifacts in a single command. Sources can be mixed —\nnpm packages, GitHub shorthand, and local paths all work side by side.\n\n```bash\n# single artifact\nnpx @ctxr/kit install @ctxr/skill-code-review\n\n# mixed batch — different types, different sources\nnpx @ctxr/kit install \\\n  @ctxr/skill-code-review \\\n  @ctxr/agent-researcher \\\n  @ctxr/rule-typescript-strict \\\n  github:ctxr-dev/output-style-teaching\n\n# team meta-package — cascades to every member\nnpx @ctxr/kit install @ctxr/team-full-stack\n\n# user-global instead of project-local\nnpx @ctxr/kit install @ctxr/skill-code-review --user\n\n# explicit destination\nnpx @ctxr/kit install @ctxr/skill-code-review --dir .agents/skills\n\n# local path (must start with ./, /, or ~/)\nnpx @ctxr/kit install ./path/to/local-skill\n```\n\n**Batch behavior:** if one package in the batch fails (broken `ctxr` block,\n`target: \"file\"` payload that resolves to ≠1 file, network error on a single\nfetch), that package is reported and skipped — the rest of the batch\nproceeds and `kit` exits non-zero only if anything failed. No all-or-nothing\nabort.\n\n#### Install locations\n\n| Location                  | Role                                                  |\n|---------------------------|-------------------------------------------------------|\n| `.agents/\u003ctype\u003e/`         | Project-scope canonical (real files live here)        |\n| `.claude/\u003ctype\u003e/`         | Project-scope discovery mirror (symlink, auto)        |\n| `~/.agents/\u003ctype\u003e/`       | User-global canonical (real files live here)          |\n| `~/.claude/\u003ctype\u003e/`       | User-global discovery mirror for Claude Code (symlink)|\n| `~/.codex/\u003ctype\u003e/`        | User-global discovery mirror for Codex CLI (symlink)  |\n| Custom path               | Via `--dir \u003cpath\u003e` (mirrors are skipped)              |\n\nFor project-scope installs `kit` also upserts a row in `AGENTS.md` at\nthe project root, with stable `\u003c!-- ctxr:skills:start --\u003e` /\n`\u003c!-- ctxr:skills:end --\u003e` markers. Anything you author outside the\nmarkers is preserved verbatim across re-installs and removes.\n\nTo disable kit's `AGENTS.md` emitter entirely (no creates, no upserts,\nno removes) set `CTXR_NO_AGENTS_MD=1` in the environment. Useful when\n`AGENTS.md` is hand-authored, kept in `.gitignore`, or otherwise managed\noutside kit.\n\n#### Migration of legacy `.claude/\u003ctype\u003e/\u003cname\u003e/` installs\n\nWhen `kit install` runs and detects a real (non-symlink) directory at\nthe legacy `.claude/\u003ctype\u003e/\u003cname\u003e/` path with a recorded manifest row,\nit moves the directory to `.agents/\u003ctype\u003e/\u003cname\u003e/`, replaces the\noriginal with a symlink, and migrates the manifest row. The same\napplies to user-scope installs at `~/.claude/\u003ctype\u003e/`. Migration is\nidempotent and skipped when `--dir` is set (a deliberate custom layout\nis left alone). `kit update` does NOT auto-migrate; it preserves\nwhatever layout you originally chose so a routine update never\nsurprises you with a relocation.\n\nAuto-detect: `kit` always installs canonically to `.agents/\u003ctype\u003e/`\nand creates the discovery mirrors automatically. If a legacy real\n`.claude/\u003ctype\u003e/\u003cname\u003e/` install is found, the migration step above\nmoves it to the canonical path before installing.\n\n### `npx @ctxr/kit update [name]`\n\nRe-install one or all artifacts in place using the source recorded in the\nmanifest. Searches every project- and user-scope manifest, so you don't\nneed to remember where each artifact lives.\n\n```bash\nnpx @ctxr/kit update                          # update everything\nnpx @ctxr/kit update ctxr-skill-code-review   # update one\n```\n\nTeam updates cascade to every member.\n\n### `npx @ctxr/kit remove \u003cname\u003e [--keep-members]`\n\nRemove an installed artifact (or team). For teams, every member listed in\nthe manifest is removed too unless `--keep-members` is passed.\n\n```bash\nnpx @ctxr/kit remove ctxr-skill-code-review\nnpx @ctxr/kit remove ctxr-team-full-stack --keep-members\n```\n\n### `npx @ctxr/kit list [path]`\n\nList installed artifacts from every discovered location, grouped by type.\n\n```bash\nnpx @ctxr/kit list\nnpx @ctxr/kit list ./other-project\n```\n\n### `npx @ctxr/kit info \u003csource\u003e`\n\nShow details about an installed or remote artifact: type, target layout,\nsource, version, file count, install paths.\n\n```bash\nnpx @ctxr/kit info @ctxr/skill-code-review\nnpx @ctxr/kit info ctxr-agent-researcher\n```\n\n### `npx @ctxr/kit validate [path]`\n\nValidate an artifact package's structure ahead of publishing. Dispatches\nto a per-type validator: skill validation (frontmatter, broken-link\nchecker, file budget) is the heaviest; the rest are thin frontmatter\nsanity checks plus the universal `target: \"file\"` ⇒ exactly-one-`.md`-file\nrule that the installer enforces.\n\n```bash\nnpx @ctxr/kit validate                  # validate package in current dir\nnpx @ctxr/kit validate ./my-skill       # validate at a path\n```\n\n### `npx @ctxr/kit init [--type \u003ctype\u003e] [name]`\n\nScaffold a new artifact package from a template. Defaults to\n`--type skill` because that's the most common authoring case.\n\n```bash\nnpx @ctxr/kit init my-skill                       # default --type skill\nnpx @ctxr/kit init --type agent my-agent          # scaffold an agent\nnpx @ctxr/kit init -t command deploy              # short-form flag\nnpx @ctxr/kit init --type team team-full-stack    # scaffold a team meta-package\n```\n\nEach template ships a `package.json` with the right `ctxr` block already\nfilled in, plus `README.md`, `LICENSE`, and `.gitignore` (the skill\ntemplate additionally ships `.markdownlint.jsonc` and a starter\n`SKILL.md`; file-target templates ship a pre-named `ctxr-{{name}}.md`).\nThe scaffolded result passes `npx @ctxr/kit validate` immediately — edit\nthe contents, then publish.\n\n## Global options\n\n| Flag                  | Effect                                                   |\n|-----------------------|----------------------------------------------------------|\n| `--dir \u003cpath\u003e`        | Operate against a specific directory                     |\n| `--user`              | Use `~/.claude/\u003ctype\u003e/` (user-global) instead of project |\n| `-i`, `--interactive` | Prompt for choices where applicable                      |\n| `--help`, `-h`        | Show help (top-level or per-command)                     |\n| `--version`, `-v`     | Print the installed version of `@ctxr/kit`               |\n\nRun `npx @ctxr/kit \u003ccommand\u003e --help` for command-specific options.\n\n## Releasing\n\nReleases are PR-gated. Version bumps land on `main` through a review gate like any other change; only the tag push is automated.\n\n### One-time setup\n\nEnable these on the repo before your first release:\n\n- Repository secret `NPM_TOKEN` set to an npm access token with publish rights on the `@ctxr` scope (`npm token create`, then **Settings → Secrets → Actions** → add `NPM_TOKEN`).\n- **Settings → Actions → General → Workflow permissions**: enable **Allow GitHub Actions to create and approve pull requests** so `release.yml` can open its version-bump PR with `GITHUB_TOKEN`. If the checkbox is greyed out, an organization-level Actions policy is restricting it; ask an org admin to unlock the setting first.\n- (Optional, recommended) GitHub-managed CodeQL default setup: **Security → Code security** → enable default setup for `javascript-typescript` and `actions`.\n- (Optional) A branch ruleset on `main` requiring PR review + code scanning. The release flow works without it; gates are strictly stricter when enabled.\n\n### Cutting a release\n\n1. **Actions → Release → Run workflow**.\n   - Branch selector: `main` (the workflow refuses any other ref).\n   - Version bump: `patch` / `minor` / `major`.\n   - Click **Run workflow**.\n2. The workflow bumps `package.json` on a fresh `release/v\u003cversion\u003e` branch and opens a PR to `main` titled `release: v\u003cversion\u003e`.\n3. Review the PR (diff is just version fields). Approve + merge.\n4. On merge, `tag-on-main.yml` fires automatically:\n   - Detects the version change.\n   - Creates and pushes the annotated `v\u003cversion\u003e` tag via `GITHUB_TOKEN`.\n5. **Actions → Publish to npm → Run workflow** on the `v\u003cversion\u003e` tag. The workflow re-runs `lint / validate / test:unit / test:integration / test:e2e`, verifies the tag matches `package.json`, and publishes `@ctxr/kit` to npm.\n\n\u003e **Why a manual dispatch for step 5?** GitHub's built-in `GITHUB_TOKEN` cannot trigger further workflows (`on: push: tags` won't fire when a workflow pushed the tag). So the tag auto-creation stops at the tag. Publishing is one extra click. To make it fully automatic, swap the push credential in `tag-on-main.yml` for a GitHub App token or fine-grained PAT stored as a repo secret (`actions/create-github-app-token` or a `secrets.TAG_PUSH_PAT`), then the `push: tags` trigger on `publish.yml` will fire and step 5 happens by itself.\n\nFrom **Run workflow** on Release to **published on npm** is one dispatch + one PR merge + one dispatch (or one dispatch + one PR merge, once a PAT/App-token is wired in).\n\n### Troubleshooting\n\n- **Release workflow fails with \"dispatched from non-main ref\"** — you selected a feature branch in the Actions UI. Re-dispatch with `main`.\n- **`tag-on-main` fails with \"Tag vX.Y.Z exists but points at …\"** — a stale/orphan tag from a prior failed release. Delete and re-run:\n\n  ```bash\n  git push origin --delete vX.Y.Z\n  ```\n\n  Then merge a trivial no-op PR to `main` (or revert-and-re-merge the release PR) to retrigger `tag-on-main`. Direct pushes to `main` may be blocked by branch protection, so the PR path is the reliable retrigger.\n- **`publish.yml` fails on \"Verify version matches tag\"** — tag and `package.json` disagree. Investigate the merge commit; this should not happen under the PR-based flow.\n- **GitHub Actions is not permitted to create pull requests** — org or enterprise policy blocks the `GITHUB_TOKEN` from opening PRs. Enable **Allow GitHub Actions to create and approve pull requests** at the org level (**Settings → Actions → General → Workflow permissions**), or ask the enterprise admin to unlock the setting.\n\n## Development\n\n```bash\nnpm install\nnpm test                  # unit + integration\nnpm run test:unit         # unit only\nnpm run test:integration  # integration only\nnpm run test:e2e          # multi-location + multi-type\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctxr-dev%2Fkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fctxr-dev%2Fkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctxr-dev%2Fkit/lists"}