This is a monorepo managed with bun workspaces and Turborepo:
packages/env-spec-parser— parser for the @env-spec language (PEG.js grammar ingrammar.peggy)packages/varlock— the main package: CLI + library for loading/validating.envfilespackages/varlock-website— docs site (Astro); docs content lives insrc/content/docs/packages/vscode-plugin— VSCode extension for @env-spec language supportpackages/integrations/*— framework integrations (nextjs, vite, astro, ...)packages/native-helpers/*— per-platform npm publishing shells for the native helper binaries (published as@varlock/native-helper-*, versioned in lockstep withvarlock); the binaries themselves are built frompackages/encryption-binary-swift(darwin) andpackages/encryption-binary-rust(linux/win32)packages/utils,packages/plugins— shared internalspackages/varlock-docs-mcp— docs MCP server for external varlock users; do not use it to look things up while working on this repo — read the docs source directly
- This repo uses Bun as the package manager (
bun install,bun run, etc.) - Workspace deps use
workspace:*protocol - Use catalog for any potentially common dependencies
- CI workflows use
bun runto execute scripts andbunxfor one-off commands
bun run buildat the repo root builds all packages via Turborepo, in dependency order- To build a single package, go through turbo so its workspace deps build first:
bunx turbo run buildfrom the package directory, orbunx turbo run build --filter=<pkg>from the root - Do not build a package with
bun run --filter <pkg> build: bun's filter does not build the package's workspace dependencies, and some builds require their dist output to exist (e.g. varlock's d.ts bundling inlines the emitted declarations frompackages/utils, so it fails if that package was never built)
- Write any scripts which may end up being saved in TypeScript (
.ts), not JavaScript- throwaway/one-off code is fine in JS
- Execute scripts using
bun run, notnode- e.g.
bun run scripts/release-preview.ts - Bun runs
.tsfiles natively — no compile step needed
- e.g.
- Scripts in
scripts/at the repo root are monorepo-level utilities, while specific packages may have their ownscriptsfolder
- The varlock CLI binary is built using
bun build --compile(not Node SEA or pkg) bun run --filter varlock build:binarybuilds a local dev binary for the current platform atpackages/varlock/dist-sea/varlockpackages/varlock/scripts/build-binaries.tsbuilds cross-platform release binaries (or use--current-platformfor a single local binary)bun run --filter varlock test:binary:localbuilds the local binary and runs a smokeloadcheck (WSL-aware helper copy)bun run --filter varlock pack:localbuilds + packs a local tarball and prints a ready-to-pastefile:dependency
- Unit/integration tests use Vitest
- Smoke tests live in
smoke-tests/and test the CLI end-to-end - Binary-specific tests in
smoke-tests/tests/binary.test.tsrequire the SEA binary to be built first
- This monorepo uses bumpy (
@varlock/bumpy) for version management - Changeset files live in
.bumpy/and are created withbunx @varlock/bumpy add(orbun run bumpy:add) - Standard bump types:
major,minor,patch - Non-interactive changeset creation (for CI/AI):
bumpy add --packages "pkg:minor" --message "description" --name "changeset-name" - Bump files are only required when publishable packages have changed (based on
changedFilePatternsin.bumpy/_config.json). Changes to CI workflows, root config files, scripts, docs, etc. do not require a bump file — bumpy's pre-push hook will not block in that case. - Write changeset descriptions for end users, and keep them short
- One bump file per package per PR is usually enough. Before adding a new one, check whether the branch already has a bump file for that package and extend its description instead. In particular, when the PR introduces a brand-new (never-published) package, keep a single entry describing the whole feature: its first changelog entry should read as one coherent release, not a series of additions and fixes to something that never shipped
- Branch names must be meaningful — a short kebab-case description of the change (e.g.
fix-cf-fifo-secret-concat,vite-plugin-hmr). Never push an auto-generated session/worktree branch name (e.g.claude/dreamy-jones-a79c22); rename it first withgit branch -m <meaningful-name> - Do not push after every commit. Pushes to open PRs trigger automated reviews that cost money. Commit locally as you go, and only push when the work is complete (or the user asks for feedback on work in progress). When in doubt, ask before pushing
- Do not add AI attribution to PRs or commits — no "Authored by Claude" / "Generated with Claude Code" lines in PR descriptions, and no
Co-Authored-By: Claudecommit trailers - Keep PR descriptions concise: what changed and why. Don't mention linting passing or bump files being added — those are enforced by hooks and expected, not news
- When pushing new commits to an open PR, update the PR description if the changes alter what it says
- If a change affects user-facing behavior, update the docs in
packages/varlock-website/src/content/docs/(guides and/or reference) in the same PR
Docs content lives in packages/varlock-website/src/content/docs/ (.mdx). When writing or editing docs prose, keep the tone plain and direct, like an engineer wrote it:
- No em dashes (
—). Rewrite into separate sentences, commas, colons, or parentheses instead. Do not swap in a spaced hyphen (-). (En dashes for genuine numeric ranges like15.0–15.4are fine.) - Avoid marketing and AI-flavored filler:
seamless,comprehensive,powerful,robust,leverage,out of the box,by design,effortless,unlock(metaphorical), "whether you need X, Y, or Z", "instead of wrestling with", and similar. Say what the thing does plainly. - Be concise, but never at the cost of completeness. Keep every flag, command, caveat, and link a user or their agent needs to stay unblocked.
- Never edit code fences,
ansi/diffblocks, generated fixtures, frontmatter structure, or MDX component markup for tone. Prose only. - Run
bun run --filter @varlock/website buildto confirm the docs still build after non-trivial edits (the package is named@varlock/website, notvarlock-website).
- Run
bun run lint:fixfrom the repo root after completing a significant chunk of work (new feature, refactor, bug fix, etc.) - The linter uses ESLint with
@stylisticand other plugins; auto-fix handles most formatting issues - Do not leave lint errors unresolved; fix any that
--fixcannot handle automatically
- Do not use em dashes (
—) or en dashes (–) in any prose you write: docs, code comments, commit messages, PR descriptions, changeset entries, or design notes. They read as an AI-writing tell. Rewrite with a colon, comma, semicolon, parentheses, two sentences, or a plain hyphen (-) where that reads naturally. Only the em/en dash characters are banned; a regular hyphen is fine.