docs/contributing/workflow.md
This guide covers the path from a working development environment to a reviewed pull request. Use the development setup first if Ghost is not already running locally.
Issues labelled good first issue are intended to be approachable first contributions. The broader help wanted list contains other contributions the project would welcome.
Discuss new features and substantial product or architectural changes in the Ghost Forum before implementing them. A focused bug fix or agreed improvement can usually proceed directly.
mainUpdate the canonical checkout, then create a descriptive branch:
git fetch origin
git switch main
git pull --ff-only origin main
pnpm setup
git switch -c concise-change-name
Keep unrelated changes on separate branches and in separate pull requests. If a
larger effort needs a shared or release branch, agree that with the maintainers
first; ordinary pull requests target main.
Add or update automated tests when behavior changes. Run the most focused checks for the code you touched, following the README beside that workspace. Before handing off a change, use the repository's one-stop lint and test command:
pnpm check
pnpm check runs pnpm lint followed by pnpm test. It does not include the
browser E2E suite or Ember Admin tests, so run those separately when the affected
area requires them. CI uses the Nx affected graph and path filters to select the
relevant lint, unit, integration, acceptance, build, and browser-test jobs for a
pull request.
Changes that affect a publishable @tryghost/* package under koenig/ or
packages/, including changes to catalog entries consumed by that package, need
a changeset so the package receives an appropriate version and changelog entry:
pnpm change
Choose patch, minor, or major according to the package's public compatibility impact. The summary becomes the changelog entry, so describe the result for the package's consumers.
A package README.md is included when the package is published, so changing it
requires a release. Repository-only Markdown such as AGENTS.md, CLAUDE.md,
changelogs, and files under a package's docs/ directory does not.
If a changed publishable package genuinely requires no release—for example, a test-only or internal tooling change—record that explicitly:
pnpm change --bump none
Use pnpm change status to inspect pending release intent. CI rejects changes
that affect publishable packages without a covering changeset. Changes that do
not affect a publishable package do not need one.
Follow the canonical commit message guidelines.
Everyone can clone, run, and modify the canonical repository without a fork. The
publication step depends on whether you can push branches to TryGhost/Ghost.
Push the current branch directly:
git push -u origin HEAD
gh pr create --base main
Create a fork when the change is ready to publish. With the GitHub CLI, the fork can be created from the existing canonical checkout and added as a separate remote:
gh repo fork --remote --remote-name fork
git push -u fork HEAD
gh pr create --repo TryGhost/Ghost --base main
The equivalent GitHub web or desktop flow is also fine. Tooling or a coding agent may perform these steps on your behalf; check the proposed remote, branch, and pull request before authorizing a push.
Target main unless a maintainer has asked for another base branch. The pull
request should explain:
Link the issue when one exists and include screenshots for visible UI changes. Keep the branch current if requested and respond to review feedback with new commits. CI must pass before merge; skipped jobs are expected when they are not relevant to the changed paths.