Thanks for your interest in contributing! This guide covers local development and the release process (bumping versions and publishing packages).
Flatbread turns related content files in Git into typed data for TypeScript
apps. GraphQL is one way to read that data (see docs/glossary.md); it is
not the whole product.
For a first project with posts, authors, and tags, see the Flatbread package README quickstart.
- Node 20.19+
- pnpm 10.33.x via Corepack (
corepack enable && corepack prepare pnpm@10.33.0 --activate) - Clean git working tree (commit/stash your work first)
Use this path first. The Next.js app reads shared content from
examples/content through its content/ symlink:
- From the monorepo root:
pnpm installthenpnpm build(builds all packages exceptexamples/*). cd examples/nextjs- One-shot codegen:
pnpm exec flatbread codegen --verbose(output:generated/graphql.ts; globs and dirs come fromflatbread.config.js). - Run the app and Flatbread together with
flatbread start(there is noflatbread devsubcommand):pnpm dev— starts Next and watches Flatbread content, config, and GraphQL documents (pnpm exec flatbread start --watch -- next dev --turbopack). GraphQL runs on 5057 and Next on 3000.
Optional pnpm play from the repo root is a shortcut for cd examples/nextjs && pnpm dev — same as step 4 above, not a separate product command.
- Install dependencies:
pnpm install(orpnpm -w i) - Build all packages:
pnpm build - Workspace libraries (watch-only):
pnpm dev— runs packagedevscripts (e.g.tsup --watch) forpackages/*; it does not start the Next.js example. - Next.js example: prefer the flow under Recommended onboarding; or
pnpm playas a convenience alias. - Proof explorer:
- Run
pnpm play:efforts(builds@flatbread/explorerviapreplay:efforts, thenflatbread start --watch --open). - When
flatbread.config.jsusesproofContent(), Flatbread serves@flatbread/explorerathttp://localhost:5057/. The Apollo sandbox is at/graphql. - For hot module replacement (HMR) on the single-page app (SPA) shell, run
pnpm exec flatbread start --watchandpnpm --filter @flatbread/explorer devin parallel. Vite on 5173 proxies API routes to 5057.
- Run
- Check local CI parity before opening a PR:
pnpm verify
Open another terminal tab while keeping the dev server running.
-
Option 1 (preferred): use the Next.js example as a demo project
- Work in the full context of a Flatbread instance as an end-user would, while tinkering with
packages/*internals. - Commands: follow Recommended onboarding, or from root run
pnpm play(cd examples/nextjs && pnpm dev). - Good when you want to test without creating per-package temporary clutter.
- Work in the full context of a Flatbread instance as an end-user would, while tinkering with
-
Option 2: scope to a specific package
- Change directory:
cd packages/<package> - Run the package entry (ensure built first):
node dist/index.mjs - Tip: you may need to seed with
pnpm buildonce if types/builds are missing.
- Change directory:
Uses tsup to build each package in the monorepo (excluding integration examples):
pnpm build- Keep PRs small and focused; link related issues.
- Ensure CI passes all checks.
- Run
pnpm verifylocally when your change touches source, tests, package metadata, or CI. - Add test coverage for both positive and negative cases:
- Positive: expected success paths and typical inputs.
- Negative: invalid inputs, edge cases, and error handling/failure modes.
- Place tests in the relevant package and use its existing runner/config.
- Root
pnpm testbuilds the workspace, runs the AVA suite configured byava.config.js, then runs the package-local Vitest suites. - Vitest is currently used by
@flatbread/codegenand@flatbread/utils. - Most other packages are covered by the root AVA suite or do not yet expose a package-local
testscript.
- Root
pnpm lintis the enforced Prettier formatting gate. After editing, runpnpm lint:fix:fastso formatting matches CI (Cursor agents: see.cursor/rules/post-edit-lint-fix.mdc). On commit,.husky/pre-commitrunspnpm lint:fix(Pretty Quick on staged files).pnpm lint:eslintis an optional/manual root ESLint check until the linting stack is modernized.- Helpful commands:
- Local CI parity:
pnpm verify - Root test suite:
pnpm test - Package-local test scripts where present:
pnpm -r --if-present test - Single package:
pnpm -F <package-name> test - Watch (where supported):
pnpm -F <package-name> test:watch
- Local CI parity:
Oven (the DAG task runner for Cursor agents) now lives at https://github.com/FlatbreadLabs/oven.
There are two steps:
- Bump every public package to one version and file
CHANGELOG.md - Publish the release to npm and GitHub together
Every public package shares one version. A release bumps the whole set even when only one package changed. This keeps package combinations, the Proof skill manifest, and the Git tag tied to one release.
packages/proof/skills/proof/release.json records the version an
end user installs. Edit that file, not the copy in .agents/. Then run
pnpm skills:sync to refresh the .agents/ copy and pnpm skills:pack-check,
which fails unless flatbreadVersion and proofVersion match the current
package.json versions and gitTag equals v<flatbreadVersion>. pnpm verify
runs both checks.
Use the interactive bump script:
pnpm bumpWhat the script does:
- Detects whether any public package changed since the last publish by:
- Querying npm for the package's latest published version and its publish time
- Comparing git commits in
packages/<name>since that time - Ignoring commits that only change the
versionfield inpackage.json - Skipping packages that are not yet published on npm
- Passes every public package manifest to one
bumppcommand so one chosen version is written across the set - Moves
CHANGELOG.mdUnreleased list items under a new## <version>heading and leaves the empty Unreleased section (plus any trailing file note) in place. Those filed items become the GitHub release notes, after the centered Flatbread mark and aFlatbread - v<version> Release Notestitle. - Stops before publishing if any public package version differs
Notes:
-
Commit the version bumps and changelog after the script completes. For example:
git add packages/**/package.json packages/proof/skills/proof/release.json .agents/skills/proof/release.json CHANGELOG.md git commit -m "release: bump public packages"
-
If Unreleased has no list items, the bump creates an empty version heading and warns instead of claiming that it moved notes. Add release notes under that heading before publishing.
-
If versions are already bumped but Unreleased still has items, file them without bumping again:
pnpm changelog:shift --dry-run pnpm changelog:shift
-
Debugging: set
FLATBREAD_BUMP_DEBUG=1to see detection detailsFLATBREAD_BUMP_DEBUG=1 pnpm bump
-
New public packages join the same version as the rest of the release set.
Note: you must have access permissions on NPM and a logged-in GitHub CLI (
gh auth status). Push the release commit before publishing so GitHub can see the SHA.
When changing the Proof skill, edit the source files under
packages/proof/skills/proof/, then run these checks in order:
pnpm skills:sync
pnpm skills:check
pnpm skills:pack-checkBump and publish @flatbread/proof and flatbread together when the
skill and runtime need matching versions. The publish script checks the copied
skill files and package contents first. It then publishes ordinary packages,
@flatbread/proof, and finally flatbread, stopping at the first
failure. After every package is on npm, it creates the annotated
v<flatbread-version> tag, pushes that tag to origin, and opens a GitHub
release. The notes start with the centered Flatbread mark and a
Flatbread - v<version> Release Notes title, then the filed changelog
section.
Preview both sides without publishing:
pnpm publish:dryThe dry run uses the same clean-tree, changelog, GitHub CLI, pushed-commit, remote-tag, and npm registry gates as a real publish. It exits with an error if the release is not ready.
Publish all public packages and the matching GitHub release (the script checks for one shared version, builds, then attempts to publish each package):
pnpm publish:ciDetails:
-
Requires a clean working tree, a
CHANGELOG.mdsection for the release version, andghauthenticated against this repository -
Before publishing any package, checks
originfor the release tag. An absent tag or a tag on the release commit is safe. A tag on another commit stops the release. -
Builds the repo:
pnpm run build -
Iterates public packages in dependency-safe deterministic order and runs:
pnpm publish --access public --no-git-checks
-
Before each publish, checks
npm view <name>@<version> version --json. An exact version already in the registry is reported as already published and skipped; npm not-found responses proceed to publish, while authentication, network, and other errors abort before that package is published. -
If a release stops after some packages publish, rerun
pnpm publish:cisafely. Exact versions already published are skipped, and the script resumes with the first package that still needs publishing. The GitHub release is created only after every package is on npm. The script writes the annotated tag locally, pushesrefs/tags/v<version>toorigin, then runsgh release create --verify-tag. An existing GitHub release is skipped only when its body matches the filed changelog notes; a mismatch stops the release. -
Unpublished packages will be published for the first time
-
Dist-tags (alpha/beta) are currently disabled in the script. If you need them, bump with a pre-release version (
x.y.z-alpha.n) and add tagging logic inscripts/publish.ts
Protect release tags in the repository settings so they cannot be moved or deleted after publication.
End users do not copy a version or git tag. After a release is on npm they run:
npx --yes flatbread@latest proof install-skillThat command downloads the published CLI, pins that exact flatbread
version as a devDependency, and copies the Proof skill that shipped inside
the package. @latest only chooses which CLI to run. To pin an older
release, replace @latest with that version.
skills update does not advance an immutable install. To upgrade, run the
installer again from a newer CLI.
-
The bump script shows all packages as changed
- If npm is unreachable, the script may conservatively mark packages as changed
-
A package didn’t appear in the bump list
- If the local version is already higher than npm’s latest, it’s considered already bumped
- Unpublished packages are skipped during bump but will be published during
publish:ci
-
First-time publish of a new package
- Set an appropriate initial version in
packages/<name>/package.json - Run
pnpm publish:ci(the script will publish it)
- Set an appropriate initial version in
-
Publish stops because Unreleased still has items
- Versions were bumped without filing the changelog. Run
pnpm changelog:shift, commitCHANGELOG.md, then publish again.
- Versions were bumped without filing the changelog. Run
If something’s unclear or you hit an issue, please open an issue or ask in Slack.