Shared build configuration monorepo for JavaScript/TypeScript projects.
| Package | Description |
|---|---|
| @gtbuchanan/cli | Shared build CLI (gtb) |
| @gtbuchanan/eslint-config | Shared ESLint configuration |
| @gtbuchanan/eslint-plugin-agent-skills | Agent Skills schema + spec-specific rule |
| @gtbuchanan/eslint-plugin-markdownlint | ESLint plugin wrapping markdownlint |
| @gtbuchanan/eslint-plugin-md-frontmatter | ESLint plugin validating Markdown frontmatter via JSON Schema |
| @gtbuchanan/eslint-plugin-yamllint | ESLint plugin for yamllint gap rules |
| @gtbuchanan/hk-config | Shared hk pre-commit preset (Pkl, GitHub-release published) |
| @gtbuchanan/libsql-termux-shim | libsql binding shim for Termux/Android (os: ["android"]) |
| @gtbuchanan/pnpm-termux-shim | pnpm bin shim for Termux/Android (os: ["android"]) |
| @gtbuchanan/tsconfig | Shared TypeScript base configuration |
| @gtbuchanan/vitest-config | Shared Vitest configuration |
A consuming repo copies two pipeline workflows — one per trigger —
whose jobs call this repo's single-concern reusable workflows, each
delegating with secrets: inherit:
# .github/workflows/pr.yml
name: PR
on:
pull_request:
branches: [main]
permissions:
contents: read
pull-requests: write # Dependencies posts a PR comment
jobs:
ci:
name: CI
uses: gtbuchanan/tooling/.github/workflows/ci.yml@main
secrets: inherit
changeset:
name: Changeset
uses: gtbuchanan/tooling/.github/workflows/changeset-check.yml@main
dependencies:
name: Dependencies
uses: gtbuchanan/tooling/.github/workflows/dependency-review.yml@main
pre-commit:
name: Pre-Commit
uses: gtbuchanan/tooling/.github/workflows/pre-commit.yml@main# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
permissions:
contents: read
jobs:
ci:
name: CI
uses: gtbuchanan/tooling/.github/workflows/ci.yml@main
secrets: inherit
cd:
name: CD
needs: ci
permissions:
contents: write # changesets release tags/PR
id-token: write # npm trusted publishing (OIDC)
uses: gtbuchanan/tooling/.github/workflows/cd.yml@main
secrets: inheritThe reusable workflows each job calls:
| Reusable | Description |
|---|---|
ci.yml |
Build + e2e + optional slow tests |
cd.yml |
changesets version + publish (OIDC) |
changeset-check.yml |
Verify changeset exists |
dependency-review.yml |
Scan PR dep changes for vulns + licenses |
pre-commit.yml |
Run hk hooks on changed files |
Permissions narrow down the call chain but never elevate, so each
pipeline grants the superset its jobs need (shown above). Required
status checks key on the leaf job name (Build, E2E Test,
Dependency Review, …), so the pipeline job names (CI, CD,
Dependencies) are just grouping.
CI automatically uploads coverage to Codecov via
a per-package turbo task. The workflow installs the
Codecov CLI and runs
coverage:codecov:upload per package. The task is uncached, so every
package uploads on every commit — that is what keeps Codecov's commit
statuses dependable enough to require in branch protection.
Add a CODECOV_TOKEN repository secret; secrets: inherit on the CI
job (shown in the pipelines above) forwards it. To pass it explicitly
instead:
jobs:
ci:
uses: gtbuchanan/tooling/.github/workflows/ci.yml@main
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}Each upload names its flag after the package's unscoped
package.json name (@acme/utils → utils). Codecov compares a flag
against its own history across commits, so the name has to mean the
same thing in every checkout — which rules out the directory basename,
since worktrees and clones rename it.
codecov.yml lists no flags. Per-package rules live in
flag_management.default_rules, which Codecov applies to whatever
flags it ingests, so adding a package needs no config change. Copy
this repo's codecov.yml as a starting point and edit the targets.
Two repo-wide checks come back from Codecov: codecov/project
(the whole report against itself, auto target with a 1% threshold)
and codecov/patch (lines the PR changed, 80% target). Neither names
a flag, so both cover every package under one context and both report
on any commit that uploads — which is what makes them safe to list as
required status checks. flag_management defines no per-flag statuses:
twelve more checks per commit would bury the packages that moved, and
the set would shift as packages come and go, so no such check could be
a stable requirement. Per-package numbers live in the Codecov comment
and the Flags tab.
Drift risk: The Codecov job uses continue-on-error, so upload
failures never block PRs, and require_ci_to_pass: false keeps
Codecov's status and comment posting when an unrelated check fails.
carryforward: true holds a package's last known coverage on the run
that skips an upload anyway; without it Codecov reads the missing flag
as 0%. The cost is that Codecov cannot tell coverage it carried forward
from coverage that never arrived, so a failed upload reports stale data
until a later run replaces it. release.yml re-runs CI on merge to
main, which corrects a one-off failure.
Requiring these checks is a repository setting, not something gtb sync writes — add codecov/project and codecov/patch to the branch
ruleset yourself.
Repos customize behavior through Turborepo task graphs generated by
gtb sync. Per-package scripts delegate to gtb task <name> leaves,
and consumers can replace script values to customize individual tools.
ci.yml accepts inputs like run-e2e and run-slow-tests (pass via
with: on the CI job) to toggle test tiers. See the
CLI package for available commands.
dependency-review.yml runs two PR-time gates on newly-changed
dependencies:
- Review —
actions/dependency-review-actionfails on advisories atmoderateseverity or higher and on non-permissive licenses per this repo's shared policy (.github/dependency-review-config.yml). Consumer wrappers inherit the shared policy automatically — theconfig-fileinput defaults to a remote ref pointing at this repo's config. - Version check — fails if any newly-added dep isn't at its latest version. Resolves the change set via GitHub's dependency-graph compare API; looks up latest versions via deps.dev (npm, pip, maven, nuget, rubygems, go, cargo) and GitHub Releases (Actions). SHA-pinned Actions are accepted as intentional.
Both jobs require GitHub's Dependency Graph to be enabled at
Settings → Code security and analysis. Coverage is limited to
ecosystems the dep graph indexes — for JS/TS projects, that's npm and
GitHub Actions. mise tools and hk.pkl steps aren't covered;
Renovate's managers handle those independently on their normal
cadence.
A failure summary is posted as a PR comment, so the PR pipeline must
grant pull-requests: write (shown in the setup above).
Override defaults — e.g. a repo-local license policy or a stricter
severity threshold — via with: on the Dependencies job:
jobs:
dependencies:
name: Dependencies
uses: gtbuchanan/tooling/.github/workflows/dependency-review.yml@main
with:
config-file: .github/dependency-review-config.yml
fail-on-severity: lowTurborepo manages task orchestration. The task graph is defined in
turbo.json (generated by gtb sync) and declares dependencies
between leaf tasks:
typecheck:ts ─┬─ lint:eslint ── lint ──┐
└─ test:vitest:fast ─────┤ check ─┬─ compile:ts → pack
│ ├─ test:vitest:slow
│ └─ test:vitest:e2e
└────────────────── build
Turbo resolves the graph, caches results, and runs tasks in parallel where dependencies allow.
The build:ci task produces two outputs:
packages/*/dist/source/— publishable contents per packagedist/packages/*.tgz— tarballs for e2e tests
Consumer customization:
- Consumers replace the values of generated
package.jsonscripts to override individual tools. There is no hook system —gtb syncgenerates the scripts, and consumers edit them directly. publishConfig.directory— Set todist/sourcefor packages that need a clean publish directory. Thepackcommand generatespackage.jsonand.npmignorethere automatically.
The CD job (cd.yml) requires:
releaseGitHub environment with npm trusted publishing (OIDC)- A GitHub App with
contents: writeandpull-requests: writepermissions installed on the repo (so changeset PRs trigger checks) - Repo variable
APP_IDand repo secretAPP_PRIVATE_KEYfrom the App @changesets/clias a devDependency
The repo publishes a shareable Renovate config as default.json.
Extend it from a consuming repo's Renovate config
(e.g., .github/renovate.json):
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>gtbuchanan/tooling"]
}This pulls in config:recommended plus a small set of repo-wide
opinions: 3-day release-age quarantine, OSV vulnerability alerts,
pnpm dedupe after updates, verified-commit platform API, pre-commit
manager enabled, and America/Chicago timezone for the weekly
lockfile maintenance schedule.
Run gtb sync to generate turbo.json, tsconfigs, per-package scripts,
codecov.yml, and (in repos using mise) mise.tasks.toml from project
discovery. Use --force to overwrite existing scripts, or pass scope
args (e.g. gtb sync mise) to limit it. Run gtb verify to check
generated config hasn't drifted.
See the CLI package for all available commands.
See CONTRIBUTING.md for development setup, scripts, and versioning workflow.