Adding a package
A checkout with just the tinycld shell (no feature packages) runs as a lean shell. To enable a feature - mail, contacts, calendar, drive, anything third-party - you bring its repository into the workspace as a member and run a single pnpm install at the root. “Linking” in this layout means being a present workspace member: pnpm creates the node_modules/@tinycld/* symlink on install, and the generator wires the package in on the postinstall hook.
Fresh-checkout default
Out of the box, the generator scans whichever member directories are present. With only the tinycld shell cloned, the app runs without any feature packages - you get authentication and an empty workspace, and that’s about it. You add exactly the features you want by re-running @tinycld/bootstrap --assemble-only with the slugs you need.
Add a feature with the bootstrap CLI
Run @tinycld/bootstrap in assemble-only mode from the workspace root. It clones the named feature (and the tinycld shell if it’s somehow missing), skipping any directory that already exists, and writes any missing workspace coordination files - so it’s safe to re-run as often as you like:
cd ~/code/tinycld
npx @tinycld/bootstrap@latest --assemble-only --with contacts
pnpm install # links the new member + reruns the generator
cd tinycld && pnpm run dev
Pass --with more than once to add several at a time:
npx @tinycld/bootstrap@latest --assemble-only --with contacts --with mail --with drive
pnpm install
Pin to a specific tag/branch by suffixing --with <name>@<ref>. The same syntax works for tinycld (the shell, with @tinycld/core nested) so you can pin the whole workspace to a known-good combination:
npx @tinycld/bootstrap@latest --assemble-only \
--with tinycld@v1.2.0 \
--with mail@v0.3.1 --with contacts@main
Honor a non-default git host with TINYCLD_REPO_BASE (CI uses https://github.com/tinycld because runners have no SSH key; the default is git@github.com:tinycld):
TINYCLD_REPO_BASE=https://github.com/tinycld npx @tinycld/bootstrap@latest --assemble-only --with mail
What the install does
The root pnpm install produces the same end state every time, whether you just bootstrapped or are reinstalling after pulling changes:
- Creates a symlink under
node_modules/@tinycld/<name>pointing at the member, so the canonical package name (read from the member’s ownpackage.json.name-@tinycld/contacts,@acme/custom, or a baremy-pkg) resolves everywhere. Third-party scopes are first-class; the tooling doesn’t favor@tinycld/. - Runs the code generator (
tinycld/scripts/generate.ts) on thepostinstallhook. It enumerates the present members (viatinycld.packages.ts), then materializes route re-exports, writestinycld/tinycld.config.ts(the typed installed-package source of truth), generates help and Tailwind source wiring, and symlinks the package’s PocketBase migrations and Go server module intotinycld/server/.
Remove a package
Delete the member directory and re-run pnpm install at the root:
cd ~/code/tinycld
rm -rf contacts
pnpm install # reruns the generator without contacts
The generator cleans up that package’s generated route re-exports and wiring on the next run. pnpm-workspace.yaml continues to list every possible member; pnpm tolerates members whose directories are absent, so you don’t need to edit the member list.
Typical workflow
cd ~/code/tinycld
npx @tinycld/bootstrap@latest --assemble-only --with contacts --with mail --with drive
pnpm install
cd tinycld && pnpm run dev
Those commands turn a lean shell into a working mail-contacts-drive app. The feature set is just “which member directories are present” - a CI job reproduces the same build by assembling the same members via bootstrap --assemble-only.
For the anatomy of what you just added, see Manifest. For scaffolding a new package of your own, see Creating a package.