[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6KSDV8V74X8FZW7B8CNNNQ4":3,"skill-same:01M6KSDV8V74X8FZW7B8CNNNQ4":91},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":47,"repositoryHtmlUrl":48,"repositoryHomepageUrl":6,"ownerHtmlUrl":49,"ownerBlogUrl":50,"ownerDescription":6,"updatedAt":51,"install":52,"resources":64},"01M6KSDV8V74X8FZW7B8CNNNQ4","gtb-build-pipeline",null,"Build pipeline guidance for projects using @gtbuchanan\u002Fcli. Covers the Turborepo task graph, gtb sync and verify, the gtb hk pre-commit runner, the gtb changeset catalog gate, the gtb turbo wrapper (with the Android\u002FTermux escape hatch), consumer script customization, and test-bucket strategy. Trigger keywords - @gtbuchanan\u002Fcli, @gtbuchanan\u002Fpnpm-termux-shim, turbo.json, gtb sync, gtb verify, gtb turbo, gtb task, gtb hk, gtb changeset check, hk:all, hk:base, mise.tasks.toml, pnpm catalog, compile:ts, pack:npm, deploy:skills, task graph, transit.","gtbuchanan\u002Ftooling","gtbuchanan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F715687?v=4","01M6KSDRCB1XRM9B6QDZQRAFJ7","Taylor Buchanan","01M6KSDRHPP4GQYJDDTWE9V28T",0,"MIT","https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"gtb build pipeline","build","build pipeline","pipeline","trigger","compile","for","turbo","Wrapper","graph","pnpm","turborepo","sync","cli","commit","tasks","hk","changeset","runner","projects","2026-11-10 10:12:30",false,"---\nname: gtb-build-pipeline\ndescription: Build pipeline guidance for projects using @gtbuchanan\u002Fcli. Covers the Turborepo task graph, gtb sync and verify, the gtb hk pre-commit runner, the gtb changeset catalog gate, the gtb turbo wrapper (with the Android\u002FTermux escape hatch), consumer script customization, and test-bucket strategy. Trigger keywords - @gtbuchanan\u002Fcli, @gtbuchanan\u002Fpnpm-termux-shim, turbo.json, gtb sync, gtb verify, gtb turbo, gtb task, gtb hk, gtb changeset check, hk:all, hk:base, mise.tasks.toml, pnpm catalog, compile:ts, pack:npm, deploy:skills, task graph, transit.\n---\n\n# @gtbuchanan\u002Fcli build pipeline\n\nTurborepo-based build pipeline orchestrated by the `gtb` CLI. Each package defines leaf-task scripts in `package.json`; Turborepo handles dependency ordering, caching, and parallelism.\n\n## Orchestration\n\nIn a **monorepo**, root `package.json` scripts are thin aliases that\nroute through the `gtb turbo` wrapper:\n\n- `pnpm check` → `gtb turbo run check`\n- `pnpm build` → `gtb turbo run build`\n- `pnpm build:ci` → `gtb turbo run build:ci`\n- `pnpm pack` → `gtb turbo run pack`\n- `pnpm test:slow` → `gtb turbo run test:slow`\n- `pnpm test:e2e` → `gtb turbo run test:e2e`\n- `pnpm coverage:merge` → `gtb turbo run coverage:merge`\n- `pnpm deploy:skills` → `gtb turbo run deploy:skills`\n\n### Single-package repos have no aggregate aliases\n\nWhen the root _is_ the lone package (no `packages` globs in\n`pnpm-workspace.yaml`), `gtb sync` generates none of the scripts above —\ninvoke the aggregate directly instead:\n\n```sh\ngtb turbo run check\ngtb turbo run build\n```\n\nTurbo runs these as root tasks and, finding no command for them, just\nresolves their `dependsOn` chain down to the leaf scripts. Adding an\nalias back breaks the repo: turbo resolves the aggregate to the root\nscript, the script re-invokes turbo, and turbo aborts the run with its\n[`recursive_turbo_invocations`](https:\u002F\u002Fturborepo.dev\u002Fmessages\u002Frecursive-turbo-invocations)\nguard. The loop is real, not a heuristic false positive, so no rewrite\nof the alias escapes it — dispatching to the leaf tasks (`gtb turbo run\ntypecheck:ts lint:eslint`) trips the same guard, and a turbo-free alias\nwould run _in addition to_ the aggregate's dependencies. The leaf\nscripts are unaffected: they call `gtb task \u003Cname>` and never turbo.\n\n`gtb verify` reports any root script that shadows an aggregate, so a\nrepo synced before this rule landed is told which scripts to delete.\n\n`gtb turbo` is a thin pass-through to `turbo` on every supported\nplatform. On Android (`process.platform === 'android'`) it resolves\nthe global turbo binary installed via Termux's package registry\n(`$PREFIX\u002Fbin\u002Fturbo`) and execs it directly, bypassing the\nnode_modules launcher (which rejects the platform upfront). See\n[Android-Termux setup](#android-termux-setup) below.\n\n`pnpm verify`, `pnpm prepare`, and `pnpm run gtb \u003Ccmd>` invoke the CLI directly.\n\n## Task graph\n\nAggregate tasks exist only as `dependsOn` targets — no corresponding script:\n\n```text\ngenerate:* → generate + ^generate → typecheck:ts, compile:ts, lint:eslint, test:vitest:*\n^transit → transit → typecheck:ts, lint:eslint, test:vitest:*\n^generate + ^transit → \u002F\u002F#typecheck:ts, \u002F\u002F#lint:eslint\ntypecheck:ts → typecheck → check\ntypecheck:ts → lint:eslint → lint → check\n^compile + transit → test:vitest:fast → check\n^compile + transit → test:vitest:slow → test:slow → build\ncompile:ts → pack:npm → pack → test:vitest:e2e → test:e2e → build\nlint:eslint → deploy:skills → build\ncheck + compile + pack → build:ci → build\n```\n\nThis is the maximal graph. Every node and edge above is capability-conditional — `gtb sync` emits only what the workspace's tools call for, so a workspace that publishes nothing gets no `^compile` edge on its test tasks (and no `compile:ts`, `pack:npm`, or `pack` at all), and one without ESLint gets no `lint:eslint`.\n\nLeaf tasks, per-package, run via `gtb task \u003Cname>`:\n\n- `typecheck:ts` — TypeScript type checking\n- `compile:ts` — TypeScript compilation to `dist\u002Fsource\u002F`\n- `lint:eslint` — ESLint with cache + zero-warning threshold\n- `pack:npm` — npm tarball creation (publishable packages only); also copies\n  the package `README.md` and its `LICENSE` (the package's own, else the\n  workspace-root one) into `dist\u002Fsource\u002F` so the tarball ships them\n- `test:vitest:fast` — fast unit\u002Fintegration tests with coverage\n- `test:vitest:slow` — slow tests (testcontainers, etc.) with coverage\n- `test:vitest:e2e` — e2e tests against packed tarballs, no coverage\n- `test:vitest` — fast + slow (coverage merged)\n- `coverage:vitest:merge` — merge fast + slow coverage blobs\n- `coverage:codecov:upload` — upload the coverage reports (CI only)\n- `deploy:skills` — symlink authored Agent Skills to agent directories\n\nTest tasks hash `CI` into their cache key (`env: [\"CI\"]` in `turbo.json`) so local and CI caches don't collide — Vitest uses different reporters and coverage settings under CI.\n\n### Root tasks\n\nWork owned by the workspace root rather than any package is emitted as a turbo root task (`\u002F\u002F#\u003Cname>`), backed by a root `package.json` script of the same name and wired into the aggregate its per-package counterpart feeds:\n\n- `\u002F\u002F#lint:eslint` — root has its own `eslint.config.*`. Lints root files per-package lint never sees; `lint` depends on it.\n- `\u002F\u002F#deploy:skills` — root has its own `skills\u002F`. Skills consumed as `\u003Croot>\u002Fskills\u002F\u003Cname>\u002FSKILL.md` — the `skills` CLI reading a repo tarball, a dotfiles script symlinking a clone — can't move into a package, so a workspace can package everything else and still author skills at the root; `build` depends on it.\n- `\u002F\u002F#typecheck:ts` — root has TypeScript of its own, typically the `eslint.config.ts` \u002F `vitest.config.ts` that per-package `typecheck:ts` never sees; `typecheck` depends on it.\n\nAll are monorepo-only: where the root _is_ the lone package, its per-package task already covers those files.\n\n**`\u002F\u002F#typecheck:ts` keys on sources, not on a tsconfig.** Sync writes a root `tsconfig.json` at every workspace root, so its presence says nothing about whether there is anything to check — and a config whose `include` matches no file is an error to tsc (`TS18003`), not a no-op. The task is therefore emitted only when the root actually holds a TypeScript file that `include` reaches: a root-level `*.ts`, or one nested under `bin\u002F`, `scripts\u002F`, `src\u002F`, `test\u002F`, or `e2e\u002F`.\n\n**`\u002F\u002F#lint:eslint` and `\u002F\u002F#typecheck:ts` depend on `^transit`.** Turbo resolves `^transit` from the root through the root manifest's workspace dependencies, so an edit to a workspace package the root consumes — its ESLint config, a shared tsconfig — reaches the root task's hash. A bare `transit` or `generate` would resolve against the root itself and dangle. Nothing is lost on the artifact side: workspace packages export TypeScript source in-workspace, so the root type-checks and lints against sources without waiting on a compile.\n\nA root task's script _is_ its command, so a root owning one gets no `gtb turbo run \u003Cname>` alias for it — the alias would re-enter turbo and trip the recursion guard above. At such a root `pnpm deploy:skills` deploys the root's own skills; `pnpm build` (or `gtb turbo run deploy:skills`) reaches every package's copy.\n\n### Codegen tasks (`generate:*`)\n\nAny `generate:*` script in a package's `package.json` is picked up as codegen and ordered ahead of the tasks reading generated sources. Those also wait on their dependencies' codegen ([why](references\u002Ftransit-node.md)).\n\nWhere the _leaf_ tasks get declared depends on the repo shape, because only the package knows what its codegen reads and writes. That matters: turbo restores a cached task's declared `outputs` on a hit, so a leaf with none skips the run and restores nothing, and the generated files stay missing while every downstream task reports success. A script name can't tell `gtb sync` its outputs.\n\n**Monorepo** — the root `generate` aggregate names no leaves, only `^generate`, and each package declares its own leaves in a package configuration (`packages\u002F\u003Cpkg>\u002Fturbo.json`):\n\n```json\n{\n  \"extends\": [\"\u002F\u002F\"],\n  \"tasks\": {\n    \"generate\": { \"dependsOn\": [\"$TURBO_EXTENDS$\", \"generate:prisma\"] },\n    \"generate:prisma\": {\n      \"inputs\": [\"prisma\u002Fschema.prisma\"],\n      \"outputs\": [\"src\u002Fgenerated\u002F**\"]\n    }\n  }\n}\n```\n\n`$TURBO_EXTENDS$` keeps the root's `^generate`, which this `dependsOn` would replace (below turbo 2.7, list `^generate`). The root names no leaves, because turbo aborts the entire run when a task in `dependsOn` resolves to no definition anywhere in the config chain (`Could not find \"\u003Cpkg>#generate:prisma\" in root turbo.json`). A package that never writes this file therefore fails quietly: codegen is skipped and downstream tasks read whatever is on disk. `gtb verify` closes that gap: it reports packages with `generate:*` scripts and no package configuration, leaves missing from `generate`'s `dependsOn` or `$TURBO_EXTENDS$` not first in it, and leaves declaring neither `outputs` nor `cache: false`.\n\n**Single-package repo** — turbo offers package configurations only for workspace packages, and the lone `turbo.json` is sync-owned, so there is no seam to hand off to. Sync declares the leaves itself with `cache: false`. Codegen then re-runs on every invocation, which is slower than a cache hit and the only safe default when the outputs are unknowable.\n\n### Non-obvious dependencies\n\n- **`lint:eslint` depends on `typecheck:ts`** — prevents confusing linter output from type errors. ESLint (via `typescript-eslint`) runs its own type resolution, so the dep isn't strictly required; consumers who prefer parallelism over cleaner output can remove it. Cross-package invalidation doesn't ride on this edge — `lint:eslint` declares its own `transit` dep — so dropping it costs only the output ordering.\n- **`typecheck:ts`, `lint:eslint`, and every vitest task depend on `transit`** — see [The `transit` node](#the-transit-node). This includes `test:vitest:e2e`: it reads packed tarballs, but its own sources import fixture helpers from source-only workspace packages.\n- **Test tasks gate on `^compile`, not `^compile:ts`** — the aggregate covers every compile flavour a dependency publishes from (`compile:skills` today), where the leaf names one toolchain. It still resolves to a no-op for a dependency that compiles nothing.\n- **Test tasks don't depend on `typecheck:ts`** — parallelism wins.\n- **`deploy:skills` depends on `lint:eslint` same-package (no `^`)** — catches broken frontmatter and markdown in `SKILL.md` before deploy. Skills are authored independently per package; there's no topological chain.\n- **`build:ci` excludes `test:slow`, `test:e2e`, `deploy:skills`** — CI runs fast tests; slow\u002Fe2e run on full builds; CI has no agents to serve skills to.\n\n`deploy:skills` keys on `skills\u002F**` and `skills-npm.config.ts` only. If you install or remove an agent and want existing skills resymlinked into the new agent's project-local dir, run `gtb turbo run deploy:skills --force` once — turbo's cache otherwise reports HIT and skips the redeploy.\n\n### Who owns what in `dist\u002Fsource`\n\nSeveral tasks write the published output directory, each declaring `outputs` for only its own share, and `compile:ts` clears the directory before emitting. See [the `dist\u002Fsource` ownership reference](references\u002Fdist-source-ownership.md) before changing an input or output glob or overriding `compile:ts`.\n\n### The `transit` node\n\n`transit` is a scriptless turbo node, depending only on `^transit`, that pulls every transitive workspace dependency's file hashes into a consumer's task hash. Tasks reading a dependency as source rather than as a build artifact need it — without it they replay a cached pass after that dependency changed, a stale green. See [the `transit` node reference](references\u002Ftransit-node.md).\n\n## `gtb sync` and `gtb verify`\n\n`gtb sync` reconciles generated state:\n\n- `turbo.json` tasks + aggregates, rewriting any hand edit\n- per-package `tsconfig.json` \u002F `tsconfig.build.json`, plus a scaffolded root `tsconfig.base.json`, keeping keys gtb doesn't write\n- per-package + root `package.json` scripts\n- `mise.tasks.toml` — the `hk:all` \u002F `hk:base` mise tasks, written only when the repo has a mise config (`mise.toml`, `.mise.toml`, `.config\u002Fmise.toml` or `.config\u002Fmise\u002Fconfig.toml`)\n\nRun after adding packages, changing the task graph, or updating tooling. Without `--force`, existing script values are preserved — this is how packages keep custom overrides. Use `--force` only when intentionally resetting scripts to their generated defaults.\n\n**Codecov flags and gating.** `coverage:codecov:upload` names each flag after the package's unscoped `package.json` name (`@acme\u002Futils` → `utils`), never the directory basename, which a worktree or clone renames. Packages colliding after scope-stripping silently share a flag. The leaf is uncached (`cache: false`) so every commit reaches Codecov: a cached skip leaves no report and so no status, and a required check that never reports blocks a PR forever. `codecov.yml` declares no per-flag statuses; the two repo-wide `coverage.status` checks cover every package and are the ones to require.\n\n**The base tsconfig.** Every generated config extends `.\u002Ftsconfig.base.json`, the one tsconfig the consumer hand-authors to pick a shared `@gtbuchanan\u002Ftsconfig` variant. Sync scaffolds it (extending `@gtbuchanan\u002Ftsconfig\u002Fnode.json`) only when absent and never overwrites it, so an edited variant survives re-sync. `gtb verify` checks its presence — not its contents — since a missing base silently breaks every generated config's `extends`.\n\n**Single-package tsconfigs.** When the root _is_ the lone package (no `packages` globs in `pnpm-workspace.yaml`), the root and per-package tsconfig layers target the same files, so sync collapses them into one: both `tsconfig.json` and `tsconfig.build.json` extend `.\u002Ftsconfig.base.json`, and the build config carries the root layer's `declaration`\u002F`sourceMap` alongside the package layer's `outDir`\u002F`rootDir`\u002F`include`. Package `extends` paths are derived from the package's actual depth below the root, not assumed to be `packages\u002F\u003Cname>`.\n\n`mise.tasks.toml` is loaded by a one-time manual `[task_config] includes = [\"mise.tasks.toml\"]` in `mise.toml` (so sync never round-trips the hand-authored file); `gtb verify` asserts the include is present and the file current. An explicit `includes` replaces mise's default `mise-tasks\u002F` discovery, so a repo keeping its own script tasks lists both: `includes = [\"mise-tasks\", \"mise.tasks.toml\"]`.\n\n`gtb verify` validates no drift from the expected baseline. Exits non-zero if anything is out of sync. Run in CI as a drift gate. It reports exactly what `gtb sync` would change, plus the problems only a hand edit fixes. Use `--ignore \u003Cname>` to skip a specific task or script — prefer fixing the drift. The mise check self-skips when the repo has no `mise.toml`, and the `turbo.json`, script and tsconfig checks when the root doesn't depend on `@gtbuchanan\u002Fcli`, so an hk-preset adopter runs plain `gtb sync`.\n\nMost checks compare a file against what sync would generate. One doesn't: the `generate:*` package configurations described above are author-owned, so verify asserts they exist and are wired correctly instead of regenerating them (`--ignore generate:\u003Cname>` opts a script out).\n\n**Published packages can't depend on private ones.** `gtb verify` carries the other non-generated check: every install-time workspace dependency of a published package must itself be published. pnpm rewrites a `workspace:` specifier to the linked package's concrete version at pack time and never asks whether that version reached the registry — a `private: true` package still has a `version` to substitute — so the tarball ships a dependency no consumer can resolve, and `pnpm publish` says nothing. The check covers `dependencies`, `peerDependencies`, and `optionalDependencies`, since all three survive publish and take the same rewrite. Two things are exempt: `devDependencies`, which publishing strips, and anything `bundleDependencies` actually bundles, which the tarball carries itself. The remedy is publishing the dependency, or moving it to `devDependencies` when it's build-time only — a workspace package a bundler inlines is exactly that, and belongs there regardless. See [the published dependencies reference](references\u002Fpublished-dependencies.md) before treating `bundleDependencies: true` as an exemption or leaning on an e2e suite to catch this.\n\n## Pre-commit hooks (`gtb hk`)\n\n`gtb hk` runs the [hk](https:\u002F\u002Fhk.jdx.dev) pre-commit hooks, and is what the generated `hk:all` \u002F `hk:base` mise tasks call. It locally applies fixes and in CI runs a non-modifying check (keyed on the `CI` env var), mirroring prek's `run`.\n\n- `gtb hk base [ref] [-- \u003Chk args>]` — runs hk on files changed from a base ref (default `origin\u002Fmain`; pass a ref to override). On shallow clones it fetches the base first, then hands the range to hk as `--from-ref=\u003Cbase> --to-ref=HEAD`. Forward args to hk after the ref, e.g. `gtb hk base -- -S eslint` targets a single hook.\n- `gtb hk all [-- \u003Chk args>]` — runs hk across every file.\n\nInvoked via mise (`mise run hk:base`) so hk and its tools resolve from mise. The mise task resolves `gtb` itself per repo shape — see the `mise.tasks.toml` notes above.\n\n## Changeset gate (`gtb changeset check`)\n\n`gtb changeset check [--since \u003Cref>] [--ignore \u003Cpkg>]` is the PR releasability gate. It runs `changeset status`, then a catalog gate that fails when a pnpm catalog change reaches a published package with no changeset releasing it — a bump `changeset status` cannot see, since the catalog lives at the workspace root and belongs to no package. Both run against one base ref (default `origin\u002Fmain`). An empty changeset is **not** coverage. See [the changeset gate reference](references\u002Fcatalog-changeset-gate.md) before changing what counts as a consumer, as coverage, or as a change.\n\n## Android-Termux setup\n\nTermux's Node reports `process.platform === 'android'`, which the `node_modules` turbo launcher rejects outright; install turbo from Termux's own registry (`pkg install turbo`) and `gtb turbo` execs it directly. Separately, run heavy aggregates (`build`, `test:slow`, `test:e2e`) with `--concurrency=1` on any memory-constrained host. See [the Android-Termux reference](references\u002Fandroid-termux.md) for the full setup, the `@gtbuchanan\u002Fpnpm-termux-shim` rationale, and why `gtb turbo` doesn't set the concurrency ceiling itself.\n\n## Customizing behavior\n\nConsumers override behavior by replacing `package.json` script values. No hooks or plugin system.\n\nTo keep a custom script value:\n\n1. Edit the script in `package.json`.\n1. Run `gtb sync` — non-destructive by default, preserves existing values.\n1. `gtb verify` still passes: the missing-script check flags absent required scripts, not different values.\n\nTo reset to generated defaults: `gtb sync --force`.\n\n## Test strategy\n\nTwo axes — speed (fast vs slow) and target (source vs artifact):\n\n|      | Source (coverage, no pack) | Artifact (no coverage, needs pack) |\n| ---- | -------------------------- | ---------------------------------- |\n| Fast | Unit + fast integration    | —                                  |\n| Slow | Testcontainers, etc.       | E2E (Playwright, CLI tools)        |\n\nPer-package configs:\n\n- `vitest.config.ts` — source tests (coverage via `configurePackage()`)\n- `vitest.config.e2e.ts` — artifact tests (no coverage)\n\nSlow tests use Vitest's native tag system; `--tags-filter` controls which run. Full Vitest configuration lives in the `gtb-vitest` skill (not yet published).\n\nCI coverage merging: per-package runs write to `dist\u002Fcoverage\u002F`. CI uploads fast and slow as separate artifacts; a merge job downloads both and runs `vitest --merge-reports` to produce the unified report.\n\n## Aggregate semantics\n\nNew per-package tasks plug into aggregates via `dependsOn`. Pick the aggregate by scope:\n\n- `check` — fast correctness checks. Runs on pre-commit. Put typecheck, lint, and fast tests here.\n- `build:ci` — PR-suitable. Skips slow tests, e2e, and skill deploys.\n- `build` — full local validation. Everything in `build:ci` plus `test:slow`, `test:e2e`, and `deploy:skills`.\n","# @gtbuchanan\u002Fcli build pipeline\n\nTurborepo-based build pipeline orchestrated by the `gtb` CLI. Each package defines leaf-task scripts in `package.json`; Turborepo handles dependency ordering, caching, and parallelism.\n\n## Orchestration\n\nIn a **monorepo**, root `package.json` scripts are thin aliases that\nroute through the `gtb turbo` wrapper:\n\n- `pnpm check` → `gtb turbo run check`\n- `pnpm build` → `gtb turbo run build`\n- `pnpm build:ci` → `gtb turbo run build:ci`\n- `pnpm pack` → `gtb turbo run pack`\n- `pnpm test:slow` → `gtb turbo run test:slow`\n- `pnpm test:e2e` → `gtb turbo run test:e2e`\n- `pnpm coverage:merge` → `gtb turbo run coverage:merge`\n- `pnpm deploy:skills` → `gtb turbo run deploy:skills`\n\n### Single-package repos have no aggregate aliases\n\nWhen the root _is_ the lone package (no `packages` globs in\n`pnpm-workspace.yaml`), `gtb sync` generates none of the scripts above —\ninvoke the aggregate directly instead:\n\n```sh\ngtb turbo run check\ngtb turbo run build\n```\n\nTurbo runs these as root tasks and, finding no command for them, just\nresolves their `dependsOn` chain down to the leaf scripts. Adding an\nalias back breaks the repo: turbo resolves the aggregate to the root\nscript, the script re-invokes turbo, and turbo aborts the run with its\n[`recursive_turbo_invocations`](https:\u002F\u002Fturborepo.dev\u002Fmessages\u002Frecursive-turbo-invocations)\nguard. The loop is real, not a heuristic false positive, so no rewrite\nof the alias escapes it — dispatching to the leaf tasks (`gtb turbo run\ntypecheck:ts lint:eslint`) trips the same guard, and a turbo-free alias\nwould run _in addition to_ the aggregate's dependencies. The leaf\nscripts are unaffected: they call `gtb task \u003Cname>` and never turbo.\n\n`gtb verify` reports any root script that shadows an aggregate, so a\nrepo synced before this rule landed is told which scripts to delete.\n\n`gtb turbo` is a thin pass-through to `turbo` on every supported\nplatform. On Android (`process.platform === 'android'`) it resolves\nthe global turbo binary installed via Termux's package registry\n(`$PREFIX\u002Fbin\u002Fturbo`) and execs it directly, bypassing the\nnode_modules launcher (which rejects the platform upfront). See\n[Android-Termux setup](#android-termux-setup) below.\n\n`pnpm verify`, `pnpm prepare`, and `pnpm run gtb \u003Ccmd>` invoke the CLI directly.\n\n## Task graph\n\nAggregate tasks exist only as `dependsOn` targets — no corresponding script:\n\n```text\ngenerate:* → generate + ^generate → typecheck:ts, compile:ts, lint:eslint, test:vitest:*\n^transit → transit → typecheck:ts, lint:eslint, test:vitest:*\n^generate + ^transit → \u002F\u002F#typecheck:ts, \u002F\u002F#lint:eslint\ntypecheck:ts → typecheck → check\ntypecheck:ts → lint:eslint → lint → check\n^compile + transit → test:vitest:fast → check\n^compile + transit → test:vitest:slow → test:slow → build\ncompile:ts → pack:npm → pack → test:vitest:e2e → test:e2e → build\nlint:eslint → deploy:skills → build\ncheck + compile + pack → build:ci → build\n```\n\nThis is the maximal graph. Every node and edge above is capability-conditional — `gtb sync` emits only what the workspace's tools call for, so a workspace that publishes nothing gets no `^compile` edge on its test tasks (and no `compile:ts`, `pack:npm`, or `pack` at all), and one without ESLint gets no `lint:eslint`.\n\nLeaf tasks, per-package, run via `gtb task \u003Cname>`:\n\n- `typecheck:ts` — TypeScript type checking\n- `compile:ts` — TypeScript compilation to `dist\u002Fsource\u002F`\n- `lint:eslint` — ESLint with cache + zero-warning threshold\n- `pack:npm` — npm tarball creation (publishable packages only); also copies\n  the package `README.md` and its `LICENSE` (the package's own, else the\n  workspace-root one) into `dist\u002Fsource\u002F` so the tarball ships them\n- `test:vitest:fast` — fast unit\u002Fintegration tests with coverage\n- `test:vitest:slow` — slow tests (testcontainers, etc.) with coverage\n- `test:vitest:e2e` — e2e tests against packed tarballs, no coverage\n- `test:vitest` — fast + slow (coverage merged)\n- `coverage:vitest:merge` — merge fast + slow coverage blobs\n- `coverage:codecov:upload` — upload the coverage reports (CI only)\n- `deploy:skills` — symlink authored Agent Skills to agent directories\n\nTest tasks hash `CI` into their cache key (`env: [\"CI\"]` in `turbo.json`) so local and CI caches don't collide — Vitest uses different reporters and coverage settings under CI.\n\n### Root tasks\n\nWork owned by the workspace root rather than any package is emitted as a turbo root task (`\u002F\u002F#\u003Cname>`), backed by a root `package.json` script of the same name and wired into the aggregate its per-package counterpart feeds:\n\n- `\u002F\u002F#lint:eslint` — root has its own `eslint.config.*`. Lints root files per-package lint never sees; `lint` depends on it.\n- `\u002F\u002F#deploy:skills` — root has its own `skills\u002F`. Skills consumed as `\u003Croot>\u002Fskills\u002F\u003Cname>\u002FSKILL.md` — the `skills` CLI reading a repo tarball, a dotfiles script symlinking a clone — can't move into a package, so a workspace can package everything else and still author skills at the root; `build` depends on it.\n- `\u002F\u002F#typecheck:ts` — root has TypeScript of its own, typically the `eslint.config.ts` \u002F `vitest.config.ts` that per-package `typecheck:ts` never sees; `typecheck` depends on it.\n\nAll are monorepo-only: where the root _is_ the lone package, its per-package task already covers those files.\n\n**`\u002F\u002F#typecheck:ts` keys on sources, not on a tsconfig.** Sync writes a root `tsconfig.json` at every workspace root, so its presence says nothing about whether there is anything to check — and a config whose `include` matches no file is an error to tsc (`TS18003`), not a no-op. The task is therefore emitted only when the root actually holds a TypeScript file that `include` reaches: a root-level `*.ts`, or one nested under `bin\u002F`, `scripts\u002F`, `src\u002F`, `test\u002F`, or `e2e\u002F`.\n\n**`\u002F\u002F#lint:eslint` and `\u002F\u002F#typecheck:ts` depend on `^transit`.** Turbo resolves `^transit` from the root through the root manifest's workspace dependencies, so an edit to a workspace package the root consumes — its ESLint config, a shared tsconfig — reaches the root task's hash. A bare `transit` or `generate` would resolve against the root itself and dangle. Nothing is lost on the artifact side: workspace packages export TypeScript source in-workspace, so the root type-checks and lints against sources without waiting on a compile.\n\nA root task's script _is_ its command, so a root owning one gets no `gtb turbo run \u003Cname>` alias for it — the alias would re-enter turbo and trip the recursion guard above. At such a root `pnpm deploy:skills` deploys the root's own skills; `pnpm build` (or `gtb turbo run deploy:skills`) reaches every package's copy.\n\n### Codegen tasks (`generate:*`)\n\nAny `generate:*` script in a package's `package.json` is picked up as codegen and ordered ahead of the tasks reading generated sources. Those also wait on their dependencies' codegen ([why](references\u002Ftransit-node.md)).\n\nWhere the _leaf_ tasks get declared depends on the repo shape, because only the package knows what its codegen reads and writes. That matters: turbo restores a cached task's declared `outputs` on a hit, so a leaf with none skips the run and restores nothing, and the generated files stay missing while every downstream task reports success. A script name can't tell `gtb sync` its outputs.\n\n**Monorepo** — the root `generate` aggregate names no leaves, only `^generate`, and each package declares its own leaves in a package configuration (`packages\u002F\u003Cpkg>\u002Fturbo.json`):\n\n```json\n{\n  \"extends\": [\"\u002F\u002F\"],\n  \"tasks\": {\n    \"generate\": { \"dependsOn\": [\"$TURBO_EXTENDS$\", \"generate:prisma\"] },\n    \"generate:prisma\": {\n      \"inputs\": [\"prisma\u002Fschema.prisma\"],\n      \"outputs\": [\"src\u002Fgenerated\u002F**\"]\n    }\n  }\n}\n```\n\n`$TURBO_EXTENDS$` keeps the root's `^generate`, which this `dependsOn` would replace (below turbo 2.7, list `^generate`). The root names no leaves, because turbo aborts the entire run when a task in `dependsOn` resolves to no definition anywhere in the config chain (`Could not find \"\u003Cpkg>#generate:prisma\" in root turbo.json`). A package that never writes this file therefore fails quietly: codegen is skipped and downstream tasks read whatever is on disk. `gtb verify` closes that gap: it reports packages with `generate:*` scripts and no package configuration, leaves missing from `generate`'s `dependsOn` or `$TURBO_EXTENDS$` not first in it, and leaves declaring neither `outputs` nor `cache: false`.\n\n**Single-package repo** — turbo offers package configurations only for workspace packages, and the lone `turbo.json` is sync-owned, so there is no seam to hand off to. Sync declares the leaves itself with `cache: false`. Codegen then re-runs on every invocation, which is slower than a cache hit and the only safe default when the outputs are unknowable.\n\n### Non-obvious dependencies\n\n- **`lint:eslint` depends on `typecheck:ts`** — prevents confusing linter output from type errors. ESLint (via `typescript-eslint`) runs its own type resolution, so the dep isn't strictly required; consumers who prefer parallelism over cleaner output can remove it. Cross-package invalidation doesn't ride on this edge — `lint:eslint` declares its own `transit` dep — so dropping it costs only the output ordering.\n- **`typecheck:ts`, `lint:eslint`, and every vitest task depend on `transit`** — see [The `transit` node](#the-transit-node). This includes `test:vitest:e2e`: it reads packed tarballs, but its own sources import fixture helpers from source-only workspace packages.\n- **Test tasks gate on `^compile`, not `^compile:ts`** — the aggregate covers every compile flavour a dependency publishes from (`compile:skills` today), where the leaf names one toolchain. It still resolves to a no-op for a dependency that compiles nothing.\n- **Test tasks don't depend on `typecheck:ts`** — parallelism wins.\n- **`deploy:skills` depends on `lint:eslint` same-package (no `^`)** — catches broken frontmatter and markdown in `SKILL.md` before deploy. Skills are authored independently per package; there's no topological chain.\n- **`build:ci` excludes `test:slow`, `test:e2e`, `deploy:skills`** — CI runs fast tests; slow\u002Fe2e run on full builds; CI has no agents to serve skills to.\n\n`deploy:skills` keys on `skills\u002F**` and `skills-npm.config.ts` only. If you install or remove an agent and want existing skills resymlinked into the new agent's project-local dir, run `gtb turbo run deploy:skills --force` once — turbo's cache otherwise reports HIT and skips the redeploy.\n\n### Who owns what in `dist\u002Fsource`\n\nSeveral tasks write the published output directory, each declaring `outputs` for only its own share, and `compile:ts` clears the directory before emitting. See [the `dist\u002Fsource` ownership reference](references\u002Fdist-source-ownership.md) before changing an input or output glob or overriding `compile:ts`.\n\n### The `transit` node\n\n`transit` is a scriptless turbo node, depending only on `^transit`, that pulls every transitive workspace dependency's file hashes into a consumer's task hash. Tasks reading a dependency as source rather than as a build artifact need it — without it they replay a cached pass after that dependency changed, a stale green. See [the `transit` node reference](references\u002Ftransit-node.md).\n\n## `gtb sync` and `gtb verify`\n\n`gtb sync` reconciles generated state:\n\n- `turbo.json` tasks + aggregates, rewriting any hand edit\n- per-package `tsconfig.json` \u002F `tsconfig.build.json`, plus a scaffolded root `tsconfig.base.json`, keeping keys gtb doesn't write\n- per-package + root `package.json` scripts\n- `mise.tasks.toml` — the `hk:all` \u002F `hk:base` mise tasks, written only when the repo has a mise config (`mise.toml`, `.mise.toml`, `.config\u002Fmise.toml` or `.config\u002Fmise\u002Fconfig.toml`)\n\nRun after adding packages, changing the task graph, or updating tooling. Without `--force`, existing script values are preserved — this is how packages keep custom overrides. Use `--force` only when intentionally resetting scripts to their generated defaults.\n\n**Codecov flags and gating.** `coverage:codecov:upload` names each flag after the package's unscoped `package.json` name (`@acme\u002Futils` → `utils`), never the directory basename, which a worktree or clone renames. Packages colliding after scope-stripping silently share a flag. The leaf is uncached (`cache: false`) so every commit reaches Codecov: a cached skip leaves no report and so no status, and a required check that never reports blocks a PR forever. `codecov.yml` declares no per-flag statuses; the two repo-wide `coverage.status` checks cover every package and are the ones to require.\n\n**The base tsconfig.** Every generated config extends `.\u002Ftsconfig.base.json`, the one tsconfig the consumer hand-authors to pick a shared `@gtbuchanan\u002Ftsconfig` variant. Sync scaffolds it (extending `@gtbuchanan\u002Ftsconfig\u002Fnode.json`) only when absent and never overwrites it, so an edited variant survives re-sync. `gtb verify` checks its presence — not its contents — since a missing base silently breaks every generated config's `extends`.\n\n**Single-package tsconfigs.** When the root _is_ the lone package (no `packages` globs in `pnpm-workspace.yaml`), the root and per-package tsconfig layers target the same files, so sync collapses them into one: both `tsconfig.json` and `tsconfig.build.json` extend `.\u002Ftsconfig.base.json`, and the build config carries the root layer's `declaration`\u002F`sourceMap` alongside the package layer's `outDir`\u002F`rootDir`\u002F`include`. Package `extends` paths are derived from the package's actual depth below the root, not assumed to be `packages\u002F\u003Cname>`.\n\n`mise.tasks.toml` is loaded by a one-time manual `[task_config] includes = [\"mise.tasks.toml\"]` in `mise.toml` (so sync never round-trips the hand-authored file); `gtb verify` asserts the include is present and the file current. An explicit `includes` replaces mise's default `mise-tasks\u002F` discovery, so a repo keeping its own script tasks lists both: `includes = [\"mise-tasks\", \"mise.tasks.toml\"]`.\n\n`gtb verify` validates no drift from the expected baseline. Exits non-zero if anything is out of sync. Run in CI as a drift gate. It reports exactly what `gtb sync` would change, plus the problems only a hand edit fixes. Use `--ignore \u003Cname>` to skip a specific task or script — prefer fixing the drift. The mise check self-skips when the repo has no `mise.toml`, and the `turbo.json`, script and tsconfig checks when the root doesn't depend on `@gtbuchanan\u002Fcli`, so an hk-preset adopter runs plain `gtb sync`.\n\nMost checks compare a file against what sync would generate. One doesn't: the `generate:*` package configurations described above are author-owned, so verify asserts they exist and are wired correctly instead of regenerating them (`--ignore generate:\u003Cname>` opts a script out).\n\n**Published packages can't depend on private ones.** `gtb verify` carries the other non-generated check: every install-time workspace dependency of a published package must itself be published. pnpm rewrites a `workspace:` specifier to the linked package's concrete version at pack time and never asks whether that version reached the registry — a `private: true` package still has a `version` to substitute — so the tarball ships a dependency no consumer can resolve, and `pnpm publish` says nothing. The check covers `dependencies`, `peerDependencies`, and `optionalDependencies`, since all three survive publish and take the same rewrite. Two things are exempt: `devDependencies`, which publishing strips, and anything `bundleDependencies` actually bundles, which the tarball carries itself. The remedy is publishing the dependency, or moving it to `devDependencies` when it's build-time only — a workspace package a bundler inlines is exactly that, and belongs there regardless. See [the published dependencies reference](references\u002Fpublished-dependencies.md) before treating `bundleDependencies: true` as an exemption or leaning on an e2e suite to catch this.\n\n## Pre-commit hooks (`gtb hk`)\n\n`gtb hk` runs the [hk](https:\u002F\u002Fhk.jdx.dev) pre-commit hooks, and is what the generated `hk:all` \u002F `hk:base` mise tasks call. It locally applies fixes and in CI runs a non-modifying check (keyed on the `CI` env var), mirroring prek's `run`.\n\n- `gtb hk base [ref] [-- \u003Chk args>]` — runs hk on files changed from a base ref (default `origin\u002Fmain`; pass a ref to override). On shallow clones it fetches the base first, then hands the range to hk as `--from-ref=\u003Cbase> --to-ref=HEAD`. Forward args to hk after the ref, e.g. `gtb hk base -- -S eslint` targets a single hook.\n- `gtb hk all [-- \u003Chk args>]` — runs hk across every file.\n\nInvoked via mise (`mise run hk:base`) so hk and its tools resolve from mise. The mise task resolves `gtb` itself per repo shape — see the `mise.tasks.toml` notes above.\n\n## Changeset gate (`gtb changeset check`)\n\n`gtb changeset check [--since \u003Cref>] [--ignore \u003Cpkg>]` is the PR releasability gate. It runs `changeset status`, then a catalog gate that fails when a pnpm catalog change reaches a published package with no changeset releasing it — a bump `changeset status` cannot see, since the catalog lives at the workspace root and belongs to no package. Both run against one base ref (default `origin\u002Fmain`). An empty changeset is **not** coverage. See [the changeset gate reference](references\u002Fcatalog-changeset-gate.md) before changing what counts as a consumer, as coverage, or as a change.\n\n## Android-Termux setup\n\nTermux's Node reports `process.platform === 'android'`, which the `node_modules` turbo launcher rejects outright; install turbo from Termux's own registry (`pkg install turbo`) and `gtb turbo` execs it directly. Separately, run heavy aggregates (`build`, `test:slow`, `test:e2e`) with `--concurrency=1` on any memory-constrained host. See [the Android-Termux reference](references\u002Fandroid-termux.md) for the full setup, the `@gtbuchanan\u002Fpnpm-termux-shim` rationale, and why `gtb turbo` doesn't set the concurrency ceiling itself.\n\n## Customizing behavior\n\nConsumers override behavior by replacing `package.json` script values. No hooks or plugin system.\n\nTo keep a custom script value:\n\n1. Edit the script in `package.json`.\n1. Run `gtb sync` — non-destructive by default, preserves existing values.\n1. `gtb verify` still passes: the missing-script check flags absent required scripts, not different values.\n\nTo reset to generated defaults: `gtb sync --force`.\n\n## Test strategy\n\nTwo axes — speed (fast vs slow) and target (source vs artifact):\n\n|      | Source (coverage, no pack) | Artifact (no coverage, needs pack) |\n| ---- | -------------------------- | ---------------------------------- |\n| Fast | Unit + fast integration    | —                                  |\n| Slow | Testcontainers, etc.       | E2E (Playwright, CLI tools)        |\n\nPer-package configs:\n\n- `vitest.config.ts` — source tests (coverage via `configurePackage()`)\n- `vitest.config.e2e.ts` — artifact tests (no coverage)\n\nSlow tests use Vitest's native tag system; `--tags-filter` controls which run. Full Vitest configuration lives in the `gtb-vitest` skill (not yet published).\n\nCI coverage merging: per-package runs write to `dist\u002Fcoverage\u002F`. CI uploads fast and slow as separate artifacts; a merge job downloads both and runs `vitest --merge-reports` to produce the unified report.\n\n## Aggregate semantics\n\nNew per-package tasks plug into aggregates via `dependsOn`. Pick the aggregate by scope:\n\n- `check` — fast correctness checks. Runs on pre-commit. Put typecheck, lint, and fast tests here.\n- `build:ci` — PR-suitable. Skips slow tests, e2e, and skill deploys.\n- `build` — full local validation. Everything in `build:ci` plus `test:slow`, `test:e2e`, and `deploy:skills`.\n",{"name":5,"description":7},"main","99b9c292433895cde67aa2c853e236013a4dae32","packages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline",1,"https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling","https:\u002F\u002Fgithub.com\u002Fgtbuchanan","https:\u002F\u002Ftaylorbuchanan.com","2026-11-12 04:36:15",{"source":8,"skillName":5,"commands":53,"prompt":62,"zipAvailable":63},[54,57,60],{"tool":55,"command":56},"npx","npx skills add gtbuchanan\u002Ftooling --skill gtb-build-pipeline",{"tool":58,"command":59},"bunx","bunx skills add gtbuchanan\u002Ftooling --skill gtb-build-pipeline",{"tool":29,"command":61},"pnpm dlx skills add gtbuchanan\u002Ftooling --skill gtb-build-pipeline","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002FSKILL.md",true,[65,71,75,79,83,87],{"path":66,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":69,"sourceHtmlUrl":70},"evals\u002Fevals.json","REFERENCE","参考文档",14095,"https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002Fevals\u002Fevals.json",{"path":72,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":73,"sourceHtmlUrl":74},"references\u002Fandroid-termux.md",3463,"https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002Freferences\u002Fandroid-termux.md",{"path":76,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":77,"sourceHtmlUrl":78},"references\u002Fcatalog-changeset-gate.md",2649,"https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002Freferences\u002Fcatalog-changeset-gate.md",{"path":80,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":81,"sourceHtmlUrl":82},"references\u002Fdist-source-ownership.md",2258,"https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002Freferences\u002Fdist-source-ownership.md",{"path":84,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":85,"sourceHtmlUrl":86},"references\u002Fpublished-dependencies.md",1172,"https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002Freferences\u002Fpublished-dependencies.md",{"path":88,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":89,"sourceHtmlUrl":90},"references\u002Ftransit-node.md",2621,"https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Fcli\u002Fskills\u002Fgtb-build-pipeline\u002Freferences\u002Ftransit-node.md",[92,105,114,123,132,140],{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":98,"publishedAt":39},"01M6KSF1EAR45R1HTGZ7DQJXH6","three-evals","Fixture with three eval cases.","https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Feslint-plugin-agent-skills\u002Ftest\u002Ffixtures\u002Fmin-evals\u002Fthree-evals\u002FSKILL.md",[],[99,100,101,102,103,104],"evals","three","three evals","eval","fixture","with",{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":39},"01M6KSEXP87SH6WEZB82Y2N6YM","one-eval","Fixture with one eval case.","https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Feslint-plugin-agent-skills\u002Ftest\u002Ffixtures\u002Fmin-evals\u002Fone-eval\u002FSKILL.md",[],[102,112,104,113,103],"one eval","case",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":120,"publishedAt":39},"01M6KSEV10GHA9XX43PKN4AAFC","no-evals","Fixture without an evals\u002F directory.","https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Feslint-plugin-agent-skills\u002Ftest\u002Ffixtures\u002Fmin-evals\u002Fno-evals\u002FSKILL.md",[],[121,99,122,103],"no evals","directory",{"skillNo":124,"name":125,"nameZh":6,"description":126,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":127,"categories":128,"keywords":129,"publishedAt":39},"01M6KSEQHSJKJXJVQJBS7NFP5S","empty-evals","Fixture with an empty evals array.","https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Feslint-plugin-agent-skills\u002Ftest\u002Ffixtures\u002Fmin-evals\u002Fempty-evals\u002FSKILL.md",[],[99,130,131,104,103],"empty evals","empty",{"skillNo":133,"name":134,"nameZh":6,"description":135,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":138,"publishedAt":39},"01M6KSEKTK0DM06672CEGTGP3W","valid","Fixture with a valid evals.json.","https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Feslint-plugin-agent-skills\u002Ftest\u002Ffixtures\u002Fevals-schema\u002Fvalid\u002FSKILL.md",[],[134,104,103,99,139],"json",{"skillNo":141,"name":142,"nameZh":6,"description":143,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":144,"categories":145,"keywords":146,"publishedAt":39},"01M6KSEG50CQRQ071D3KJXZ16Y","non-sequential-ids","Fixture whose evals.json ids are not sequential.","https:\u002F\u002Fgithub.com\u002Fgtbuchanan\u002Ftooling\u002Fblob\u002Fmain\u002Fpackages\u002Feslint-plugin-agent-skills\u002Ftest\u002Ffixtures\u002Fevals-schema\u002Fnon-sequential-ids\u002FSKILL.md",[],[147,148,103,99,139],"ids","non sequential ids"]