Creating a package

@tinycld/create-package is the interactive scaffolder for new packages. One command produces a sibling repo that matches the conventions every first-party package follows - manifest, CI workflow, tsconfig, sample screens or a settings panel, and (optionally) a Go server stub. (Lint config lives in the app shell’s biome.json and applies to every linked package — no biome.json ships in the new repo.) It’s the fastest way to go from idea to “linked into core and typechecking.”

One-shot

npx @tinycld/create-package my-feature

The positional argument is the slug - kebab-case, 3–40 chars. It becomes the npm package name (my-feature), the URL segment (/a/[orgSlug]/my-feature/), and the Go module path (tinycld.org/packages/my-feature). Omit it to be asked.

Where the scaffolder puts things

The default target directory depends on whether you’re already in a TinyCld workspace:

The detection looks for a tinycld/ directory whose package.json declares "name": "tinycld" — a coincidentally-named directory won’t false-match.

You can always override the auto-detection with --target ./somewhere-else.

Prompts

The scaffolder walks you through a short interactive session:

Every prompt has a matching flag, so the scaffolder can run fully non-interactively (handy for CI, scripted setups, and autonomous coding agents):

npx @tinycld/create-package my-feature \
    --yes \
    --preset full \
    --icon check-square \
    --no-server \
    --no-link

See the create-package CLI reference for the full flag list.

Presets

full - data package

Matches @tinycld/contacts, @tinycld/mail, @tinycld/calendar, @tinycld/drive. You get:

settings-only - service package

Matches @tinycld/google-takeout-import. No routes, no nav entry, no collections, no server - just a settings panel:

Use this for integrations (import/export tools), admin surfaces, or anything that lives entirely under /a/<orgSlug>/settings/.

After scaffolding

If you accepted the Link into the app shell now? prompt, the scaffolder has already cloned the tinycld app shell (shallow, into ../tinycld), run npm install, and linked your package in. Only git and GitHub remain manual:

cd my-feature
git init
git add .
git commit -m 'chore: initial scaffold'
gh repo create tinycld/my-feature --public --source=. --push

If you declined the link prompt, or if you want to re-link later, do it yourself:

# from your workspace root, alongside the new package
git clone git@github.com:tinycld/tinycld.git
cd tinycld
npm install
npm run packages:link ../my-feature
npm run checks

The link command’s argument is a sibling-directory locator - a bare slug (my-feature) means ../my-feature, or you can pass a relative or absolute path. The package name itself comes from the sibling’s package.json, so there’s nothing to rewrite if your scope isn’t @tinycld.

npm run checks runs the app shell’s typecheck with your package linked. If it’s green, your scaffolded package is ready to develop in.

Then start the app:

npm run start         # alias of `npm run dev`

This builds and runs the Go PocketBase server, the Expo dev server, and a single-port HTTP proxy that fronts both. Open the URL it prints (default http://localhost:7100, or https:// if a localhost cert is present). For the full preset, your package’s nav entry shows up in the sidebar; for settings-only, your panel appears under the org settings.

What the templates assume

Scaffolded code imports core via the scoped path:

import { useOrgLiveQuery } from '@tinycld/core/lib/use-org-live-query'
import { Modal } from '@tinycld/core/ui/modal'

Intra-package imports use relative paths. ~/tinycld/<slug>/* is also aliased to the package’s own nested source.

@tinycld/core isn’t a separate npm package or git repo — it’s bundled inside the app shell at tinycld/packages/@tinycld/core/. Don’t try to install it as a dependency or clone it separately; resolution works because the sibling compiles inside the app shell’s tsconfig context once linked. See Screens for the full story.

For what each generated file means, walk through Anatomy. For linking the new package once it’s pushed, see Adding a package.