{"id":50846142,"url":"https://github.com/sandermuller/boost-core","last_synced_at":"2026-06-14T10:00:48.342Z","repository":{"id":358538670,"uuid":"1241675907","full_name":"SanderMuller/boost-core","owner":"SanderMuller","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-13T23:01:37.000Z","size":5881,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T01:08:48.009Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","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/SanderMuller.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-17T17:21:01.000Z","updated_at":"2026-06-13T23:01:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SanderMuller/boost-core","commit_stats":null,"previous_names":["sandermuller/boost-core"],"tags_count":68,"template":false,"template_full_name":null,"purl":"pkg:github/SanderMuller/boost-core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMuller%2Fboost-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMuller%2Fboost-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMuller%2Fboost-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMuller%2Fboost-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SanderMuller","download_url":"https://codeload.github.com/SanderMuller/boost-core/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMuller%2Fboost-core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34316823,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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-06-14T10:00:28.107Z","updated_at":"2026-06-14T10:00:48.327Z","avatar_url":"https://github.com/SanderMuller.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# boost-core\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/sandermuller/boost-core.svg?style=flat-square)](https://packagist.org/packages/sandermuller/boost-core)\n[![Tests](https://img.shields.io/github/actions/workflow/status/sandermuller/boost-core/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/sandermuller/boost-core/actions/workflows/run-tests.yml)\n[![Total Downloads](https://img.shields.io/packagist/dt/sandermuller/boost-core.svg?style=flat-square)](https://packagist.org/packages/sandermuller/boost-core)\n[![License](https://img.shields.io/packagist/l/sandermuller/boost-core.svg?style=flat-square)](LICENSE)\n[![Laravel Boost](https://badge.laravel.cloud/boost-badge.svg?style=flat-square)](https://github.com/laravel/boost)\n\n\u003e AI agent configuration sync for any PHP project. Write skills, guidelines, and commands once in `.ai/`; boost-core publishes them to nine agents: Claude Code, Cursor, Copilot, Codex, Gemini, Junie, Kiro, OpenCode, Amp. No framework dependency.\n\n![overview image](overview.png)\n\n## Contents\n\n- [How sync works](#how-sync-works) · [Install](#install) · [Quickstart](#quickstart) · [What you get](#what-you-get)\n- [Skill sources](#skill-sources) · [Tag filtering](#tag-filtering) · [Commands](#commands) · [Skill rendering](#skill-rendering)\n- [Automating the sync](#automating-the-sync) · [Project Conventions](#project-conventions) · [File ownership](#file-ownership)\n- [CLI reference](#cli-reference) · [Environment variables](#environment-variables) · [Versioning \u0026 stability](#versioning--stability)\n\n## How sync works\n\nYou author three kinds of content under `.ai/`, and `boost sync` fans each out to\nevery agent you selected in `withAgents(...)`. One source, many agent-native copies:\n\n| You write in       | What it is                          | `boost sync` fans it out to                          |\n|---------------------|-------------------------------------|------------------------------------------------------|\n| `.ai/skills/`       | Agent Skills (`\u003cname\u003e/SKILL.md`)    | `.{agent}/skills/\u003cname\u003e/SKILL.md` per agent          |\n| `.ai/guidelines/`   | Always-loaded guidance             | `CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, Copilot file  |\n| `.ai/commands/`     | Slash-command prompt templates      | Per-agent command dirs (see [Commands](#commands))   |\n\nSkills and commands land in gitignored per-agent directories; the guidance files\nstay tracked. See [File ownership](#file-ownership) for why.\n\n## Install\n\n`boost-core` is the engine. You rarely install it directly. Instead you install\nthe **family package** (a thin wrapper that bundles boost-core with a curated\nskill set) that matches what you're building, and it pulls `boost-core` in.\n\n| You're building                       | Install                                                                                       | Ships                                                                                      |\n|---------------------------------------|-----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|\n| A PHP application (not a package)      | [`sandermuller/project-boost`](https://github.com/sandermuller/project-boost)                 | App-dev skills — DDD layering, repository pattern, DI, domain modeling, legacy coexistence |\n| A Laravel application                  | [`sandermuller/project-boost-laravel`](https://github.com/sandermuller/project-boost-laravel) | `laravel/boost` MCP coexistence + nine-agent fanout + tag filter + remote skills           |\n| A framework-agnostic Composer package  | [`sandermuller/package-boost-php`](https://github.com/sandermuller/package-boost-php)          | Package-author skills + `lean` / `gitattributes` commands                                  |\n| A Laravel package                      | [`sandermuller/package-boost-laravel`](https://github.com/sandermuller/package-boost-laravel)  | Laravel-package skills + `McpJsonEmitter`                                                  |\n| **Your own skill bundle / tooling**    | **`sandermuller/boost-core` directly**                                                         | **Just the sync engine — you supply the skills  ← you are here**                           |\n\n```bash\ncomposer require --dev sandermuller/boost-core\n```\n\nCoexists with [`laravel/boost`](https://github.com/laravel/boost) in Laravel\nprojects via [`project-boost-laravel`](https://github.com/sandermuller/project-boost-laravel).\n\n![family overview image](overview_family.png)\n\n## Quickstart\n\n```bash\nvendor/bin/boost install   # scaffold boost.php + pick agents, vendor allowlist, tags\nvendor/bin/boost sync      # fan out to selected agents\nvendor/bin/boost sync --check   # dry run — report drift, no writes\n```\n\nConfig lives at `boost.php` (repo root) or `.config/boost.php`; see\n[File ownership](#file-ownership) for the layout details. A minimal config:\n\n```php\nuse SanderMuller\\BoostCore\\Config\\BoostConfig;\nuse SanderMuller\\BoostCore\\Enums\\Agent;\n\nreturn BoostConfig::configure()\n    -\u003ewithAgents([Agent::CLAUDE_CODE, Agent::CURSOR]);\n```\n\nboost-core runs no install-time code of its own. It's a plain library, not a\nComposer plugin. Run `vendor/bin/boost sync` yourself (e.g. in CI), or wire the\n[autosync hook](#automating-the-sync) to re-sync on `composer install`.\n\n## What you get\n\n|                          | `laravel/boost`          | `boost-core`                                                                                                         |\n|--------------------------|--------------------------|----------------------------------------------------------------------------------------------------------------------|\n| Framework scope          | Laravel only             | **Any PHP** (Laravel, Symfony, plain-PHP, packages)                                                                  |\n| Skill sources            | bundled + `.ai/skills/`  | `.ai/skills/` + Composer packages (`resources/boost/skills/`) + `withRemoteSkills()` + `withAllowedVendors()` filter |\n| Tag filtering            | none                     | `withTags()` subset rule                                                                                             |\n| Remote skill sources     | none                     | `withRemoteSkills()` — GitHub bundles + path imports                                                                 |\n| User-scope sync          | none                     | `boost sync --scope=user` for globally-installed CLI tools                                                           |\n| Origin tracing           | none                     | `boost where` + `boost where --diff=\u003cname\u003e` (host / vendor / remote / shadow)                                        |\n| Doctor / path-repo audit | none                     | `boost doctor`, `boost doctor --check-versions`                                                                      |\n| `.ai/commands/` fan-out  | none                     | per-agent argument transpilation across 7 emit targets                                                               |\n| Project Conventions      | none                     | JSONSchema-validated slot fill-in via `boost validate` / `boost slots`                                               |\n\nThe MCP server (Model Context Protocol) + Laravel docs API are `laravel/boost`'s domain, so boost-core defers\nto them in Laravel projects (see\n[`project-boost-laravel`](https://github.com/sandermuller/project-boost-laravel)\nfor coexistence).\n\n## Skill sources\n\nSkills come from three places, all resolved on the same `composer install / update`\nlifecycle and fanned out side by side:\n\n1. **Host** — your project's own `.ai/skills/`.\n2. **Vendor packages** — any Composer package that ships\n   `resources/boost/skills/\u003cname\u003e/SKILL.md`. Allowlist the vendor to pick it up:\n\n   ```php\n   return BoostConfig::configure()\n       -\u003ewithAllowedVendors(['vendor/package'])\n       -\u003ewithAgents([Agent::CLAUDE_CODE]);\n   ```\n\n   This is how a team distributes one curated skill set across many repos: author\n   once in a package, allowlist everywhere.\n   [`sandermuller/boost-skills`](https://github.com/sandermuller/boost-skills) is\n   one example of the pattern.\n3. **Remote sources** — GitHub repos shipping `.skill` release bundles or skill\n   subdirs, declared with `withRemoteSkills()` (below).\n\n### Remote skill sources\n\n```php\nuse SanderMuller\\BoostCore\\Skills\\Remote\\RemoteSkillSource;\n\nreturn BoostConfig::configure()\n    -\u003ewithAgents([Agent::CLAUDE_CODE])\n    -\u003ewithRemoteSkills([\n        // Bundle mode — fetch the named `.skill` release asset and unzip it.\n        RemoteSkillSource::githubBundle('peterfox/agent-skills', 'v1.2.0', [\n            'composer-upgrade',\n            'phpstan-developer',\n        ]),\n\n        // Path mode — fetch the repo tarball at a ref and extract named subdirs.\n        // `.` covers a whole-repo-is-one-skill layout.\n        RemoteSkillSource::githubPath('mattpocock/skills', 'main', [\n            'grill-with-docs' =\u003e 'skills/engineering/grill-with-docs',\n        ]),\n    ]);\n```\n\nEach fetched skill fans out exactly like host and vendor skills: same layout,\nsame `withTags()` filtering, same `withExcludedSkills(['\u003cowner\u003e/\u003crepo\u003e:\u003cname\u003e'])`\ndeny-list. Removing an entry prunes its output on the next sync.\n\n- **Cache.** Bundles and tarballs land under\n  `${BOOST_CACHE_HOME:-${XDG_CACHE_HOME:-$HOME/.cache}}/boost/remote-skills/`.\n  Pinned refs (a tag or 40-char SHA) cache forever; moving refs (`main`, a branch)\n  re-resolve every 24h.\n- **Offline.** `boost sync --check` never hits the network. `boost doctor` lists\n  every source, flags moving refs, and reports cache presence.\n- **Rate limit.** Anonymous GitHub caps at 60 req/h. Set `BOOST_GITHUB_TOKEN`\n  (any token with `public_repo` scope) to lift it to 5000/h. Cold CI runs and\n  `boost doctor` over many sources need it.\n- **Trust.** Sources are opt-in by full path: `peterfox/agent-skills:composer-upgrade`\n  grants access to nothing else in the repo. Pin to a tag or SHA in production;\n  moving refs are convenient, but a source-side push silently changes what lands.\n  Archive extraction rejects path traversal, absolute paths, symlinks, and\n  oversized payloads (200 MB total / 50 MB per file / 10000 entries), and any\n  violation rejects the whole source rather than extracting part of it.\n- **Strict mode.** `BOOST_REMOTE_STRICT=1` escalates any source failure to a\n  sync-aborting error. Default is warn-and-skip.\n\n**Publishing a source** for remote consumption: treat the `SKILL.md` frontmatter\n`name` as durable public API (renaming breaks moving-ref consumers), keep source\ndirs symlink-free (extraction rejects any symlinked entry), and align\n`metadata.boost-tags` with the family's tag vocabulary.\n\n## Tag filtering\n\nVendor skills can be scoped to projects that want them, so a project with no Jira\nwork never receives a `jira-triage` skill (and its `description` never pollutes\nthe agent's skill-selection index).\n\nA skill declares tags in its `SKILL.md` frontmatter:\n\n```yaml\n---\nname: jira-triage\ndescription: Triage and label incoming Jira issues.\nmetadata:\n  boost-tags: \"php jira\"\n---\n```\n\nA project declares the tags it wants in `boost.php`:\n\n```php\nuse SanderMuller\\BoostCore\\Enums\\Tag;\n\nreturn BoostConfig::configure()\n    -\u003ewithAgents([Agent::CLAUDE_CODE])\n    -\u003ewithTags([Tag::Php, Tag::Jira])        // Tag enum cases or raw strings\n    -\u003ewithExcludedSkills(['acme/pack:unwanted-skill'])\n    -\u003ewithExcludedGuidelines(['acme/pack:unwanted-guideline']);\n```\n\n**The rule:** a vendor skill ships only when *every* tag in its `boost-tags` is\namong the project's `withTags()` (`skillTags ⊆ projectTags`). An untagged skill\nalways ships, so the feature is inert until skills and projects opt in.\n`withExcludedSkills()` drops a specific `vendor/package:skill-name` regardless of\ntags. Vendor **guidelines** filter the same way, tagged either by `metadata.boost-tags`\nor a sidecar `resources/boost/guidelines/.boost-tags.yaml` manifest (for guidelines\nthat must stay frontmatter-free for `laravel/boost`).\n\nThe `Tag` enum is just a convenience; the vocabulary is open, and any string is a\nvalid tag. `vendor/bin/boost tags` lists every tag installed skills/guidelines declare,\nwhich your `withTags()` filters out, and what to add to receive them;\n`boost install`'s interactive picker offers the same. When sync drops tagged skills\nbecause `withTags()` is empty, it prints a one-line nudge at `boost tags`.\n\n\u003e [!WARNING]\n\u003e Adding a tag to an **already-shipped** skill is consumer-breaking: every project\n\u003e that hasn't declared that tag loses the skill. Treat it as a breaking change.\n\nUse `boost where` to trace where every resolved skill, guideline, and command\ncomes from (host / vendor / remote), with host-override shadowing annotated\ninline. `boost where --diff=\u003cname\u003e` prints a unified diff between a host override\nand the vendor copy it shadows.\n\n## Commands\n\n`.ai/commands/*.md` holds reusable prompt templates: the slash-command files\nagents surface in their palette. `boost sync` fans each out to the seven agents\nwith a command surface:\n\n| Agent       | Command target                                 |\n|-------------|------------------------------------------------|\n| Claude Code | `.claude/commands/`                            |\n| Cursor      | `.cursor/commands/`                            |\n| Copilot     | `.github/prompts/` (as `\u003cname\u003e.prompt.md`)     |\n| Junie       | `.junie/commands/`                             |\n| OpenCode    | `.opencode/commands/`                          |\n| Amp         | `.agents/commands/`                            |\n| Kiro        | `.kiro/skills/\u003cname\u003e/SKILL.md` (slash-command) |\n\nCodex and Gemini have no committable command target boost-core can write into\n(Codex's prompts are deprecated/personal-only, Gemini uses TOML). When\n`.ai/commands/` is populated and one of those agents is selected, `boost doctor`\nprints the manual authoring path so the gap isn't silent. Override the source dir\nwith `-\u003ewithCommandsPath(...)`.\n\n**Argument placeholders are transpiled per-agent.** Author once using the canonical\nsyntax: `$ARGUMENTS` (unsplit), `$1`/`$2`/… (positional), `$name` (named, optionally\ndeclared in frontmatter `arguments:`), and `\\$` escapes for literals. On sync,\nboost-core converts each to the agent's native shape (Claude `$0`-indexed, Copilot\n`${input:…}`, and so on). Cursor and Amp have no placeholder support and emit\nverbatim with a warning. The bundled `command-arguments` skill documents the full\ntable.\n\n## Skill rendering\n\nSkill files default to plain markdown (`SKILL.md`). For template-flavored content\n(Blade, Twig, anything needing a render step), register a `SkillRenderer` in\n`boost.php`:\n\n```php\nuse SanderMuller\\ProjectBoostLaravel\\Rendering\\BladeRenderer;\n\nreturn BoostConfig::configure()\n    -\u003ewithAgents([Agent::CLAUDE_CODE])\n    -\u003ewithSkillRenderers([new BladeRenderer]);\n```\n\nThe dispatcher matches longest-extension-first, so a `BladeRenderer` claiming\n`blade.php` handles `SKILL.blade.php`. The built-in `PassthroughRenderer` always\nhandles `.md`. Render failures default to warn-and-skip (recorded in\n`SyncResult::errors`); `BOOST_RENDER_STRICT=1` escalates the first failure to a\nsync-aborting error. A source whose extension has **no** registered renderer\n(e.g. a `SKILL.blade.php` with no `BladeRenderer`) is flagged by `boost sync` and\n`boost doctor`. Register a renderer for it, or rename it to `SKILL.md`.\n\nThe `SkillRenderer` contract is `@api` (locked at 1.0). Plugin authors writing\nrenderers, `FileEmitter`s, or a `BoostWrapperContract` should work from\n[`PUBLIC_API.md`](PUBLIC_API.md), which pins the frozen contract surface.\n\n## Automating the sync\n\nboost-core ships no Composer plugin, so a `composer install` re-sync is opt-in.\nPick the entry point that fits:\n\n| Entry point                                  | Use for                                                              |\n|----------------------------------------------|---------------------------------------------------------------------|\n| `BoostAutoSync::run`                          | `post-install-cmd` / `post-update-cmd` hooks — silent on a no-op     |\n| `BoostAutoSync::runWithSummary`               | User-invoked scripts (`composer sync-ai`) — prints a summary always  |\n| `BoostAutoSync::syncUserScopeOnce`            | A globally-installed CLI tool self-syncing its own bundled skills    |\n\nAll three honor `BOOST_SKIP_AUTOSYNC=1`.\n\n### Composer hook (consumer project)\n\n```json\n\"scripts\": {\n    \"post-install-cmd\": [\"SanderMuller\\\\BoostCore\\\\Scripts\\\\BoostAutoSync::run\"],\n    \"post-update-cmd\":  [\"SanderMuller\\\\BoostCore\\\\Scripts\\\\BoostAutoSync::run\"],\n    \"sync-ai\":          [\"SanderMuller\\\\BoostCore\\\\Scripts\\\\BoostAutoSync::runWithSummary\"]\n}\n```\n\n`run` checks `Event::isDevMode()`, resolves the bin-dir, runs `vendor/bin/boost sync`,\nsurfaces non-zero exits through Composer's IO, and is **silent on a true no-op**\n(`wrote=0, deleted=0`). Output appears only when something changed or errored.\n`runWithSummary` prints the one-line success summary on *every* sync, including\nthe no-ops `run` keeps quiet (useful when debugging \"did the hook fire?\"). Both\nwork on Windows + Unix.\n\n\u003e [!IMPORTANT]\n\u003e **On Laravel + [`project-boost-laravel`](https://github.com/sandermuller/project-boost-laravel)**,\n\u003e use `@php artisan project-boost:sync` instead of `BoostAutoSync::run`. The\n\u003e artisan path runs through the Laravel container, which bootstraps `BladeRenderer`\n\u003e and delivers laravel/boost's bundled skills to every agent. The bare-CLI path\n\u003e bypasses both. See `project-boost-laravel`'s install guide for the canonical\n\u003e `scripts` shape.\n\n### CLI tool you publish (self-sync from bin script)\n\nA tool installed with `composer global require` keeps its own bundled skills\ncurrent by self-syncing from its bin script:\n\n```php\n#!/usr/bin/env php\n\u003c?php declare(strict_types=1);\n\nrequire __DIR__ . '/../vendor/autoload.php';\n\n\\SanderMuller\\BoostCore\\Scripts\\BoostAutoSync::syncUserScopeOnce(\n    packageRoot: dirname(__DIR__),\n    packageName: 'your-vendor/your-tool',\n);\n\n// ... the tool's own dispatch ...\n```\n\n`syncUserScopeOnce()` runs a user-scope sync the first time it sees a given\nversion, then writes a per-version sentinel so later runs are free.\n`syncUserScope()` is the ungated form. Both never throw, so the tool keeps running\neven if its sync fails.\n\nAfter `composer global require`-ing skill-bearing packages, run\n`vendor/bin/boost sync --scope=user --all` once to user-scope-sync every globally\ninstalled package that ships `resources/boost/skills/`, into\n`~/.{agent}/skills/\u003cvendor\u003e__\u003cpackage\u003e/\u003cskill\u003e/SKILL.md`. User scope publishes a\npackage's skills **wholesale**: there's no `boost.php`, so tag filters and the\nvendor allowlist (both project-scope controls) don't apply. Removed packages are\nreaped on the next `--all` run; see [File ownership](#file-ownership).\n\n## Project Conventions\n\nVendor skills often need project-specific context: a Jira key, a branch pattern,\na test runner. Project Conventions injects it via a JSONSchema slot fill-in.\nVendors declare slots in `resources/boost/conventions-schema.json`; consumers fill\nthem in `boost.php`:\n\n```php\nreturn BoostConfig::configure()\n    -\u003ewithAgents([Agent::CLAUDE_CODE])\n    -\u003ewithConventions([\n        'jira' =\u003e ['project_key' =\u003e 'HPB'],\n        'github' =\u003e ['default_base_branch' =\u003e 'develop'],\n    ]);\n```\n\nSkills consume a slot either with an inline `\u003c!--boost:conv path=\"…\" mode=\"…\"--\u003e`\ntoken (resolved into the emitted file) or via the rendered `## Project Conventions`\nblock in `CLAUDE.md`. `boost validate --strict` hard-fails CI on a leaked token;\n`boost slots` / `boost where --conventions` audit what's set.\n\n**See [`docs/conventions.md`](docs/conventions.md)** for the full reference:\ninline tokens, observability, legacy-ref migration, and migrating vendor skills.\n\n## File ownership\n\nboost-core generates files into your repo and home directory and tracks what it\nowns in a manifest, so a sync never silently overwrites hand-written content:\n\n- **Guidance files** (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, Copilot) are wholesale\n  boost-owned, markerless, and regenerated from `.ai/guidelines/` on every sync,\n  but kept **tracked** so output is reviewable in diffs. Author guidance in\n  `.ai/guidelines/`, never by hand-editing the target.\n- **Skill + command directories** are gitignored (100% generated from `.ai/`).\n- A file you've hand-edited (sha diverged from the manifest) is **never** blanked\n  or reaped. Adopting boost-core in a repo with an existing `CLAUDE.md` won't wipe it.\n- Removing a vendor dep or de-selecting an agent reaps the now-orphaned files it owned.\n\n**See [`docs/file-ownership.md`](docs/file-ownership.md)** for the manifest,\nlifecycle reap, the empty-assembly guard, `.config/` layout + relocation, managed\n`.gitignore`, and user-scope cleanup-on-remove.\n\n## CLI reference\n\n| Command                              | Purpose                                                                          |\n|--------------------------------------|----------------------------------------------------------------------------------|\n| `boost install`                      | Scaffold `boost.php` (if missing) + interactive agent / vendor / tag picker       |\n| `boost sync`                         | Fan out skills / guidelines / commands to selected agents                         |\n| `boost sync --check`                 | Dry run — report drift, no writes (offline; gate CI on this)                      |\n| `boost sync --scope=user [--all]`    | User-scope sync for globally-installed CLI tools                                  |\n| `boost where`                        | Origin-traced listing of every skill / guideline / command that would ship       |\n| `boost where --diff=\u003cname\u003e`          | Unified diff (skill OR guideline) between a host override and the vendor copy     |\n| `boost where --conventions [--json]` | Effective resolved conventions slots + provenance + block keep/drop status        |\n| `boost doctor`                       | Offline health check — config, remote sources, cache, emitters, token leaks. **Advisory only** — exits 0 unless config fails to load |\n| `boost doctor --check-versions`      | Opt-in Packagist comparison for path-repo shadows (one HTTP call per package)     |\n| `boost doctor --check-conventions`   | Report conventions slot status (missing, unknown, file-existence)                 |\n| `boost doctor --check-stale-paths`   | Read-only audit of the retired-paths registry — what the next sync would clean up |\n| `boost tags`                         | List available tags + their unlock counts across allowlisted vendors             |\n| `boost validate [--strict]`          | Validate `withConventions([...])` + scan for leaked tokens (`--strict` fails CI)  |\n| `boost slots [--missing\\|--filled]`  | List conventions slots, optionally filtered by fill state                         |\n| `boost paths`                        | List path globs boost-core manages                                               |\n| `boost convert-conventions`          | Legacy one-shot: extract 0.8.x marker YAML into `boost.php` (hidden, not a contract) |\n\nExit codes: `0` ok, `1` failure, `2` usage. `boost doctor` is advisory, so gate CI\non `sync --check` / `validate --strict` instead.\n\n## Environment variables\n\nEvery variable is opt-in; unset = default behavior.\n\n| Variable                 | Effect                                                                                  |\n|--------------------------|-----------------------------------------------------------------------------------------|\n| `BOOST_SKIP_AUTOSYNC=1`  | Skip the `BoostAutoSync` composer-hook sync entirely                                     |\n| `BOOST_SKIP_GITIGNORE=1` | Skip managed `.gitignore` updates (handy for CI / ephemeral Docker installs)             |\n| `BOOST_GITHUB_TOKEN`     | GitHub token (`public_repo` scope) — lifts remote-skill fetches from 60 to 5000 req/h   |\n| `BOOST_REMOTE_STRICT=1`  | Escalate any remote-skill source failure to a sync-aborting error (default: warn-and-skip) |\n| `BOOST_RENDER_STRICT=1`  | Escalate the first skill-render failure to a sync-aborting error (default: warn-and-skip)   |\n| `BOOST_CACHE_HOME`       | Override the remote-skill cache root (defaults to `$XDG_CACHE_HOME` / `~/.cache`)        |\n\n## Versioning \u0026 stability\n\nboost-core follows [Semantic Versioning](https://semver.org). The promise covers\nthe **public surface** only:\n\n- **Config authoring API** — `BoostConfig::configure()`, the `BoostConfigBuilder`\n  `with*()` methods, the `Agent` / `Tag` enums, and `RemoteSkillSource`.\n- **CLI** — command names, documented options, and exit codes.\n- **Composer hooks** — `BoostAutoSync::run` / `runWithSummary` (new parameters\n  always optional-with-default).\n- **Plugin contracts** — `FileEmitter`, `SkillRenderer`, `BoostWrapperContract`\n  and their DTOs. Parameterless constructors only.\n\nEverything marked `@internal` (the whole engine) and on-disk regenerable state\n(the sync manifest, ledgers, runtime dirs) may change in any release. The full\ncommitted surface is enumerated in [`PUBLIC_API.md`](PUBLIC_API.md). From `1.0.0`\non, breaking changes land only in a MAJOR bump and are called out in\n[`CHANGELOG.md`](CHANGELOG.md) and [`UPGRADING.md`](UPGRADING.md).\n\n## More\n\n- [`UPGRADING.md`](UPGRADING.md) — breaking-change migrations between versions\n- [`CHANGELOG.md`](CHANGELOG.md) — full release history ([releases page](https://github.com/sandermuller/boost-core/releases) has per-version notes)\n- [`CONTRIBUTING.md`](CONTRIBUTING.md) — dev setup, test conventions, pre-release gauntlet\n- [`PUBLIC_API.md`](PUBLIC_API.md) — the frozen semver surface in full\n\n### Testing\n\n```bash\ncomposer test            # full Pest suite (unit + integration, real composer-install subprocesses)\ncomposer test-coverage   # with coverage report\n```\n\n## Security\n\nEmail security issues to `github@scode.nl` rather than filing a public issue. See\n[`SECURITY.md`](SECURITY.md) for the disclosure policy.\n\n## Credits\n\n- [Sander Muller](https://github.com/sandermuller)\n- [All contributors](https://github.com/sandermuller/boost-core/contributors)\n\nHeavily inspired by [`laravel/boost`](https://github.com/laravel/boost). It's the\nframework-free sibling.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandermuller%2Fboost-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsandermuller%2Fboost-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandermuller%2Fboost-core/lists"}