domain:* / type / priority are triage's.
Found while building a real app on the published scaffold (objectstack-ai/ats, an open-source recruiting marketplace on protocol ^17) — not from a sweep. Two silent-at-authoring defects were caught there only because a human remembered to run the gates by hand; nothing in the project would have caught either.
Measured (origin/main 3e270d4e)
find packages/create-objectstack/src/templates -path '*.github*' → no match. The blank template contains no .github directory and no workflow of any kind.
packages/create-objectstack/src/index.ts:287 — the scaffolder does create .github/, at runtime, for exactly one file:
const copilotPath = path.join(targetDir, '.github', 'copilot-instructions.md');
fs.mkdirSync(path.dirname(copilotPath), { recursive: true });
packages/create-objectstack/src/created-summary.ts:17 records the same count: .github/ 1.
packages/create-objectstack/src/templates/blank/package.json declares validate, typecheck (and build, dev, start). Every one of them is a script a human has to remember.
- For contrast, this repository runs 19 workflows on itself (
.github/workflows/: ci.yml, codeql.yml, docs-drift-check.yml, governed-surface-guard.yml, …). The framework holds itself to machine-enforced gates and hands its users none.
So the directory is there and the workflow is not, which reads as "CI was considered and dropped" rather than "CI was out of scope".
Why this one matters more than a usual scaffold nicety
The product claim is that metadata mistakes fail silently at runtime and the gates are the only place they surface early — templates/AGENTS.md says so in its own words ("Metadata mistakes fail silently at runtime, not at edit time… Never report a metadata change as done until npm run validate passes"). A scaffold that ships the gates as unwired npm scripts makes that instruction advisory.
And the documented workflow is AI authoring. The agent is precisely the party that most needs an unskippable gate, and the least able to be trusted to remember an optional one.
Evidence from the app built on this scaffold, both caught by pnpm validate / pnpm lint and invisible in review:
security-owd-* — an allowRead grant on a private object with no readScope is owner-only. A recruiter would not have seen an application a colleague created; the shared pipeline would silently have been a set of private inboxes.
hook-body/not-lowerable — handlers sharing a module-level helper stop lowering to metadata-only bodies, so the app ships a bundled closure instead of pure metadata. A change of deployment shape, from a refactor that looks like tidying.
Neither is visible by reading the diff. On that repo get_check_runs returned total_count: 0 for its first PR, and every gate result was a human pasting a terminal tail into the PR body.
The ask
Add packages/create-objectstack/src/templates/blank/.github/workflows/ci.yml, running on push and pull_request:
actions/checkout, pnpm/action-setup, actions/setup-node (Node 22 per the template's engines, pnpm cache)
pnpm install --frozen-lockfile
pnpm validate
pnpm lint
pnpm typecheck
Pin action versions the way this repo pins its own. Keep it one job and one file — a starting point, not a CI framework. If the template gains pnpm test from #15952, this workflow is where that step lands; the two cards touch the same template, so whichever lands second rebases.
The file must survive the template copy: confirm the packaging step does not drop dot-directories (a .github inside src/templates/blank/ is the first one the template has ever had — _gitignore is renamed precisely because dotfiles were a problem, so verify, do not assume).
Acceptance
- A freshly scaffolded app contains
.github/workflows/ci.yml, and that workflow's steps pass against the scaffolded project as generated.
create-objectstack's own scaffold test asserts the file exists and parses as YAML.
- Changeset:
create-objectstack minor (new template file).
Not in this card
The three-copy skills install (separate card). Any workflow for release, publish or deploy. Any change to this repository's own .github/workflows/.
domain:*/ type / priority are triage's.Found while building a real app on the published scaffold (
objectstack-ai/ats, an open-source recruiting marketplace on protocol ^17) — not from a sweep. Two silent-at-authoring defects were caught there only because a human remembered to run the gates by hand; nothing in the project would have caught either.Measured (
origin/main3e270d4e)find packages/create-objectstack/src/templates -path '*.github*'→ no match. The blank template contains no.githubdirectory and no workflow of any kind.packages/create-objectstack/src/index.ts:287— the scaffolder does create.github/, at runtime, for exactly one file:packages/create-objectstack/src/created-summary.ts:17records the same count:.github/ 1.packages/create-objectstack/src/templates/blank/package.jsondeclaresvalidate,typecheck(andbuild,dev,start). Every one of them is a script a human has to remember..github/workflows/:ci.yml,codeql.yml,docs-drift-check.yml,governed-surface-guard.yml, …). The framework holds itself to machine-enforced gates and hands its users none.So the directory is there and the workflow is not, which reads as "CI was considered and dropped" rather than "CI was out of scope".
Why this one matters more than a usual scaffold nicety
The product claim is that metadata mistakes fail silently at runtime and the gates are the only place they surface early —
templates/AGENTS.mdsays so in its own words ("Metadata mistakes fail silently at runtime, not at edit time… Never report a metadata change as done untilnpm run validatepasses"). A scaffold that ships the gates as unwired npm scripts makes that instruction advisory.And the documented workflow is AI authoring. The agent is precisely the party that most needs an unskippable gate, and the least able to be trusted to remember an optional one.
Evidence from the app built on this scaffold, both caught by
pnpm validate/pnpm lintand invisible in review:security-owd-*— anallowReadgrant on aprivateobject with noreadScopeis owner-only. A recruiter would not have seen an application a colleague created; the shared pipeline would silently have been a set of private inboxes.hook-body/not-lowerable— handlers sharing a module-level helper stop lowering to metadata-only bodies, so the app ships a bundled closure instead of pure metadata. A change of deployment shape, from a refactor that looks like tidying.Neither is visible by reading the diff. On that repo
get_check_runsreturnedtotal_count: 0for its first PR, and every gate result was a human pasting a terminal tail into the PR body.The ask
Add
packages/create-objectstack/src/templates/blank/.github/workflows/ci.yml, running onpushandpull_request:actions/checkout,pnpm/action-setup,actions/setup-node(Node 22 per the template's engines, pnpm cache)pnpm install --frozen-lockfilepnpm validatepnpm lintpnpm typecheckPin action versions the way this repo pins its own. Keep it one job and one file — a starting point, not a CI framework. If the template gains
pnpm testfrom #15952, this workflow is where that step lands; the two cards touch the same template, so whichever lands second rebases.The file must survive the template copy: confirm the packaging step does not drop dot-directories (a
.githubinsidesrc/templates/blank/is the first one the template has ever had —_gitignoreis renamed precisely because dotfiles were a problem, so verify, do not assume).Acceptance
.github/workflows/ci.yml, and that workflow's steps pass against the scaffolded project as generated.create-objectstack's own scaffold test asserts the file exists and parses as YAML.create-objectstackminor (new template file).Not in this card
The three-copy skills install (separate card). Any workflow for release, publish or deploy. Any change to this repository's own
.github/workflows/.