"Use Vite with vanilla JavaScript. Keep images local and store metadata in SQLite."
That sentence is the /speckit-plan example straight from the Spec Kit README — one line of guidance to a coding agent, and it contains a complete deployment plan: the runtime, the storage backend, and the data-locality constraint. A developer pushing that repo to a git-push PaaS today gets a build pipeline that reads exactly none of it. The platform's detection layer will find package.json, infer Node, install, build, and serve — and will never know the app was specified to keep state in a local SQLite file rather than a managed database, because nothing in package.json says so.
That gap is about to get wider. GitHub's Spec Kit — the open-source, MIT-licensed toolkit for spec-driven development, sitting past 111,000 stars with integrations for 30+ coding agents — is turning "write the spec before the code" from a methodology pitch into a repo-layout convention: specs/<NNN-feature>/spec.md, plan.md, and tasks.md at the repo root, committed alongside the code they produced. Tenants will push repos carrying a structured artifact trail describing what the app is, why it changed, and what it needs — and every buildpack-detection layer in production today is blind to all of it.
Here is the mapping a detection layer would need, the concrete platform action each artifact unlocks, and the trust boundary that keeps the whole idea safe:
| Artifact | Signal it carries | Platform action it unlocks | Verified against |
|---|---|---|---|
plan.md | Intended stack and services ("Vite… SQLite") | Pre-warm the right builder; flag a code/spec storage mismatch | Lockfile, Dockerfile, build output |
spec.md | What the feature is and why it exists | Preview-env description; deploy-context changelog entry | The diff it ships with |
tasks.md | Implementation progress and scope | Per-deploy progress narrative for review apps | Commit history |
constitution.md | Project-wide constraints ("SQLite only") | Policy hints: skip managed-Postgres provisioning prompts | Actual dependency graph |
The rest of this post earns each row: what Spec Kit puts in a repo, what detection reads today, and why every row ends in a verification column.
What Spec Kit actually puts in the repo
Spec-driven development, as Spec Kit implements it, is a simple contract: requirements become a specification, the specification becomes a technical plan, the plan becomes actionable tasks, and the agent implements against those artifacts — with a human checkpoint between phases. Constitution once per project; specify → plan → tasks → implement → converge per feature, with optional clarify, checklist, and analyze gates for extra rigor. Bug fixing and idea assessment ship as opt-in extensions with their own artifact trails (bug reports land in .specify/bugs/<slug>/ with a verified/partial/failed verdict).
What matters for a platform is not the workflow but the residue it leaves on disk. Every feature branch produces a predictable, machine-discoverable layout:
specs/<NNN-feature>/spec.md— the functional specification: user stories, acceptance criteria, what and why, no implementation detail.specs/<NNN-feature>/plan.md— the technical plan: stack choices, architecture, data model, the "how."specs/<NNN-feature>/tasks.md— the decomposed work items with checkboxes the agent ticks off as it implements..specify/— templates and helper scripts (not the generated specs), plus the project's constitution: standing principles every feature's plan must satisfy.
The invocation syntax has already churned twice — bare /specify in 2025 write-ups, namespaced /speckit.*, now /speckit-* agent skills (with Codex CLI using $speckit-*) — but the artifact layout has held steady, which is exactly what makes it a viable detection signal: platforms can key off file paths that survive command renames. And the scale says this convention will show up in tenant repos whether platforms prepare or not. Past 111,000 stars, an MIT license, first-class integrations across Copilot, Claude Code, Gemini CLI, Cursor, Windsurf, and Codex CLI, plus convergent implementations (AWS Kiro, OpenSpec, Cursor Plan Mode) all emitting the same spec → plan → tasks shape — the artifact trail is becoming what package.json was a decade ago: just a thing repos contain.
What build detection reads today
To see what the spec trail adds, inventory what a git-push deploy learns about a repo right now. The answer is: file-existence probes, and nothing else.
Cloud Native Buildpacks run a bin/detect phase: each buildpack tests the source tree for its marker — the Node buildpack looks for package.json, the Python buildpack for requirements.txt or pyproject.toml, the Go buildpack for go.mod — and the first group that opts in wins the build. Railpack, Railway's open-source successor in spirit, does the same detection with more sophistication (language plus framework plus package-manager sniffing) and emits a structured build plan, but its inputs are the same class of evidence: manifest files, lockfiles, Dockerfiles. Everything downstream — builder image, install command, start command — derives from what the code is, inferred from its packaging metadata.
That works, and it will keep working. But notice the three things no detect script can answer: what the app is for (intent), what external services it needs at runtime (a package.json with pg in dependencies implies Postgres, but so does a migration script that runs once, and neither says which), and why this push differs from the last one. Platforms fill those holes with guesses and tenant-supplied config: dashboard environment-variable forms, "add a Postgres plugin" buttons, deploy logs that say "commit 9f3a1c2" and nothing about what 9f3a1c2 was for. The spec trail is interesting because it answers exactly those three questions, in files the tenant's own agent already wrote.
The mapping: artifact → signal → platform action
Walk the table row by row, with a worked example each.
plan.md → stack validation and builder selection. The README's own example — "Use Vite with vanilla JavaScript. Keep images local and store metadata in SQLite" — names a static frontend with file-local state. A detection layer that parses that (more on how below) learns two deploy-relevant facts no manifest states: no database service needs provisioning, and the app expects a persistent local filesystem for its SQLite file — meaningful on platforms where filesystems are ephemeral by default. The verification is cheap: does the lockfile agree (no pg/mysql2 lurking), and does the build output? When plan and code disagree, the platform has found something worth surfacing — "your plan says SQLite but your dependencies include a Postgres client" is a genuinely useful deploy-time warning, the kind that today arrives as a 3 a.m. connection-string mystery instead.
spec.md → deploy context. Every platform shows a deploy list; nearly all of them describe each entry with a commit SHA and a timestamp. But the spec for the feature that push implements contains the user story and acceptance criteria — "albums grouped by date with a tile preview" — which is what a reviewer, or an operating agent deciding whether to promote a preview to production, actually needs. Surfacing the linked spec in preview environments turns "review app for PR #412" into "review app for dated album grouping, acceptance criteria attached." The verification source is the diff the spec ships with: spec text describes intent, the diff proves execution, and the platform presents both without conflating them.
tasks.md → progress narrative. Spec Kit agents check off tasks as they implement, so tasks.md at push time is a progress record: which work items this branch completed. For deploy previews tied to feature branches, that is a better "what's in this environment" story than a commit list — especially when the commits are agent-generated ("implement task T-014" tells a human nothing; the checked task box tells them the album-grid empty state is done). Verified against commit history, never trusted alone.
constitution.md → policy hints. The constitution holds standing constraints — "SQLite only," "no external network calls in request path," data-residency rules. A platform that reads it can skip irrelevant provisioning prompts (don't offer managed Postgres to a SQLite-only project), preselect compliant regions, or flag a plan that violates the project's own constitution before the build even runs. This is the highest-leverage row and the lowest-trust one: project principles are exactly the kind of thing tenants customize, so the platform treats them as defaults to confirm, not rules to enforce.
Note what this mapping is not: a new build target. Nobody is proposing a spec.md buildpack that compiles markdown into containers. The spec trail is context, not instructions — a structured artifact trail the pipeline surfaces to tenants and operating agents, distinct from anything a Dockerfile or detect script already provides.
The trust boundary: hints, never orders
Every row above ends in a verification column, and that is the entire safety story. Three properties of spec artifacts force it:
Prose, not schema. spec.md is markdown written for agents and humans, not a railpack-plan.json. Extracting "SQLite" as a storage decision from "store metadata in SQLite" requires language understanding — an LLM parse at detect time, or a constrained extraction prompt with a strict output schema — not a file-existence check. That makes spec-reading detection probabilistic where today's detection is deterministic, slower (a model call in the critical deploy path needs caching and timeouts), and version-sensitive to how agents phrase plans. Platforms should treat extraction confidence as a first-class signal: high-confidence, verified-against-lockfile findings become warnings and pre-selections; low-confidence parses stay out of the build path entirely.
Specs drift from code. This is not a hypothetical failure mode — it is the failure mode the Spec Kit ecosystem already tools around. Community skills exist solely to detect spec→plan and plan→tasks drift, to stop execution against a stale tasks.md, and to instruct agents to report implementation/spec drift rather than silently rewriting specs to match code. If the agent workflow that writes these files needs drift-sync tooling, a deploy pipeline reading them must assume staleness as the default: re-verify every extracted claim against the code on every push, timestamp the extraction, and never cache a spec-derived fact across pushes without re-checking.
Tenants control the input. The spec trail arrives in the same untrusted push as the code. Spec text must never override explicit configuration — a plan.md claiming "this app needs no environment variables" cannot suppress the platform's required-vars check — and extracted text must never flow unescaped into build decisions, shell commands, or prompts with higher privilege. The threat model is prompt injection wearing a specs/ path: tenant-authored markdown parsed by a platform-operated model in the deploy pipeline. Sandboxed extraction, strict schemas, and a hard rule that specs only annotate decisions made from verified sources keep that boundary clean.
The one-line policy: specs are hints, never orders. The lockfile decides the runtime, the Dockerfile (when present) decides the image, explicit tenant config decides the services — and the spec trail explains, annotates, and occasionally contradicts, with every contradiction resolved in favor of verified evidence and surfaced to the tenant as information.
Detection layers that read intent win the agent era
Step back and the direction is clear. Build detection spent a decade getting very good at answering "what is this code" from packaging metadata. The agent era is adding a second question — "what is this code for" — and, for the first time, repos are arriving with a committed, conventionally-located, machine-readable answer. The spec trail is the cheapest context source a platform will ever get: tenants' own agents write it, for free, as a side effect of how the code gets built.
The platforms that read it well will feel different to operate: previews that explain themselves, deploys that warn about plan/code mismatches before they become incidents, provisioning flows that already know the answer. The platforms that ignore it will keep asking tenants to retype, into dashboard forms, facts their repos already state. Detection that reads file markers was the right design when repos contained only code. Repos now contain intent — and the detection layer is where intent meets infrastructure.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with AI agents as first-class operators that read your repo's full context, not just its lockfile. Star the repo on GitHub or deploy your first app today.



