Manifest
Every package exports a default manifest.ts at its root. The generator reads this file to decide what to wire into the app shell - routes, collections, settings panels, migrations, Go server modules. Fields other than the four base identifiers are all optional; a package contributes only what it declares.
Required fields
Four fields are mandatory:
name- human-readable name used in navigation and the package picker.slug- URL segment and collection-name prefix. Must match the last segment of the npm package name (@tinycld/mail→mail).version- informational only right now; keep it in sync withpackage.json.description- one-line summary shown in the package registry.
Full example
const manifest = {
name: 'Example',
slug: 'example',
version: '0.1.0',
description: 'An example package',
routes: { directory: 'screens' },
publicRoutes: { directory: 'public-screens' },
nav: {
label: 'Example',
icon: 'box',
order: 20,
shortcut: 'e',
},
migrations: { directory: 'pb-migrations' },
hooks: { directory: 'pb-hooks' },
collections: {
register: 'collections',
types: 'types',
},
settings: [
{
slug: 'example',
component: 'settings/example',
label: 'Example settings',
},
],
sidebar: { component: 'sidebar' },
provider: { component: 'provider' },
seed: { script: 'seed' },
tests: { directory: 'tests' },
server: { package: 'server', module: 'tinycld.org/packages/example' },
build: { script: 'build' },
// dependencies: ['other-package-slug'],
}
export default manifest
What each optional field does
routes.directory points to the folder of org-scoped screens the generator re-exports under app/a/[orgSlug]/<slug>/. See Screens.
publicRoutes.directory points to a folder whose files become public top-level routes at app/<path>. Use this for pre-auth entry points such as public share links.
nav adds a rail entry in the org workspace. icon is a lucide-react-native name, order controls sort priority (lower comes first), and shortcut registers a single-letter keyboard shortcut. Omit nav entirely for packages that don’t belong in the sidebar - a settings-only package has no nav, no routes, no publicRoutes.
migrations.directory and hooks.directory are PocketBase concerns. The generator symlinks their contents into the app shell’s server/pb_migrations/ and server/pb_hooks/ so PocketBase discovers them on boot.
collections.register and collections.types are subpaths (without extension) to the registerCollections function and schema-type module, respectively. See Collections.
settings is an array of panel contributions to Personal Settings. Each entry needs slug, label, and component (a subpath to the .tsx panel). See Settings.
sidebar.component is a subpath to a component rendered in the secondary sidebar when the package is active. Omit sidebar entirely (as @tinycld/calc does) and the workspace renders no sidebar container at all - the package’s screens get the full viewport width next to the nav rail. provider.component wraps the package’s routes with a custom provider - use it when a package needs its own context (e.g. Drive’s upload state).
seed.script is a subpath to a module that default-exports an async seed function. tests.directory tells the test runners where to find Playwright specs. See Seed and Tests.
server.package is the subdirectory containing a Go module; server.module is the module path it declares. The generator appends matching require/replace directives to the app shell’s server/go.mod. See Server.
build.script is a subpath (resolved through the package’s exports map) to a TS module the generator runs whenever it generates - before route re-exports land. Use it when the package ships an artifact the bundler can’t produce on its own (for example, a self-contained webview bundle compiled with esbuild). The script runs from the package directory with these env vars: TINYCLD_PACKAGE_DIR, TINYCLD_PACKAGE_NAME, TINYCLD_PACKAGE_SLUG, TINYCLD_APP_ROOT, TINYCLD_BUILD_MODE (build for one-shot, dev for the dev launcher), TINYCLD_BUILD_WATCH (1 when the dev launcher started it in watch mode). One-shot builds gate packages:generate and build:web; the dev launcher spawns watch-mode builds in the background and tears them down on shutdown. Scripts are executed via the app shell’s tsx, so they can import dependencies declared in the app shell - the sibling package itself has no node_modules.
dependencies is an array of slugs this package expects to be installed. The generator does not enforce these at build time - it’s metadata for humans and for runtime feature gating.
For the exact TypeScript interface, see Manifest schema.