Thanks for contributing to Foundry.
This guide is intentionally practical. It focuses on how this repository actually works today: Go for the core CMS, file-based content and themes, JS/CSS/HTML assets under themes/, the SDK under sdk/, and CI that expects formatting, plugin sync, buildability, and tests to pass.
- Use Go
1.25 - Install Node.js if you need to format web assets and docs
- Work from the repository root
- Prefer small, focused changes over broad mixed refactors
If you are changing core behavior, open an issue first unless the fix is obviously small, then just go for PR.
Important directories:
cmd/foundry: main CLI entrypointscmd/plugin-sync: regenerates plugin import wiringinternal/: Go application code - this is the CORE of the cmsthemes/: frontend themes and the default admin themeplugins/: built-in pluginssdk/: official browser SDK modulescontent/: example/default project content and configdata/: structured data and admin runtime statedocs/: published docs and coverage output
Repository rule:
internal/is Go-code-only- do not place YAML, JSON, fixtures, runtime state,
testdata/, or other artifact directories underinternal/ - read-only fixtures belong under
tests/fixtures/ - mutable runtime state belongs in project-root runtime/configured directories like
data/,public/, or.foundry/
Security rule:
- treat
data/admin/andcontent/config/admin-users.yamlas sensitive operational state - do not commit generated runtime auth files such as sessions or audit logs
- production deployments should provide:
admin.session_secretorFOUNDRY_ADMIN_SESSION_SECRETadmin.totp_secret_keyorFOUNDRY_ADMIN_TOTP_SECRET_KEY
- production admin access should sit behind HTTPS or a correctly configured TLS-terminating reverse proxy so secure cookies remain effective
- if either admin secret is rotated or lost, document the impact in the change:
- rotating
session_secretinvalidates browser sessions - rotating
totp_secret_keycan require TOTP re-enrollment
- rotating
Install dependencies:
go mod download
npm install (only needed for frontend/themes development)Common helpeful commands:
make plugins-sync
make serve
make preview
make build
make test
make lint
make fmt
make fmt-web
make fmt-allNotes:
make serve,make preview,make build, andmake testall rely on current geneerated plugin imports.- If you change plugin registration or plugin config wiring, run
make plugins-sync.
For containerized local development:
docker compose up -d --buildImportant detail:
- the repo is bind-mounted into the container
- runtime-writable directories
data/andpublic/are kept on named Docker volumes
That is required so admin sessions, audit/runtime files, and generated output stay writable inside the container.
If you change Go code, rebuild the image:
docker compose down
docker compose up -d --buildDo not assume a running container is using your latest Go backend changes just because the repo is mounted.
For development, prefer go run ./cmd/foundry serve with live-reload turned on - this ensures you are on the latest
build relative to your local branch and ensures no docker fuckery.
- run
gofmt - keep code idiomatic and direct
- prefer narrow changes over speculative abstraction
- keep errors actionable
- add tests for non-trivial behavior changes
- format with Prettier
- keep admin/theme code modular and scoped
- do not break the default admin theme without updating related views/events/state wiring
- do not hardcode theme/plugin assumptions into unrelated core code unless the contract genuinely requires it
- preserve theme/plugin install, validation, and runtime behavior where possible
- if you add contract requirements, update validation and docs in the same change
Before opening a PR, run the relevant checks locally.
Minimum expected for most code changes:
make plugins-sync
make fmt
make fmt-web
make lint
make testFor release/update work, also verify:
go fmt ./...
go test ./...
go vet ./...For admin UI changes, at minimum syntax-check the edited modules if you are not running the full app:
node --check themes/admin-themes/default/assets/admin.jsIf you touched multiple admin files, check those specific files too.
Update docs when you change:
- CLI behavior
- config keys or defaults
- Docker/runtime behavior
- backup/update/service workflows
- theme or plugin contracts
- release process
Common files that often need updates:
README.mddocs/getting-started/index.htmldocs/config/index.html- theme/plugin READMEs when applicable
Foundry uses semver-style tags in vX.Y.Z format.
To cut a release tag:
foundry release cut v1.3.3To cut and push in one step:
foundry release cut v1.3.3 --pushOr use:
scripts/release.sh v1.3.3 --pushPushing the tag triggers the GitHub release workflow, which builds and uploads release archives and checksum files.
A good PR should:
- explain what changed
- explain why it changed
- note any user-facing impact
- mention config, runtime, or migration implications
- include tests or explain why tests were not added
Please keep PRs focused. Avoid combining unrelated refactors with bug fixes.
Good issue reports include:
- Foundry version
- how Foundry was run:
foundry serveserve-standaloneservice install- Docker
- OS/environment
- exact steps to reproduce
- logs or screenshots
- whether the bug reproduces on a fresh clone or fresh Docker compose run
For Docker issues, include:
docker compose.ymlchanges if any- whether you rebuilt with
docker compose up -d --build
- Do not commit secrets
- Do not check in accidental runtime state unless the change is intentional
- Be careful with generated files and verify whether they belong in the diff
- Keep
internal/code-only; if you need fixtures, usetests/fixtures/instead of package-local data directories - Preserve backwards compatibility where reasonable, especially for:
- config
- admin APIs
- SDK shape
- theme/plugin contracts
If you are unsure whether a change belongs in core, theme, plugin, SDK, or docs:
- choose the narrowest layer that can own the behavior cleanly
- document the contract if the change crosses boundaries
- ask in an issue or draft PR before going broad