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- what Settings → Packages shows for the installed package. Keep it in sync withpackage.json; the release tooling bumps both.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' },
cli: {
package: 'cli',
module: 'tinycld.org/packages/example/cli',
},
help: { directory: 'help' },
search: { adapter: 'search-adapter' },
automation: { definitions: 'automation' },
quota: [{ collection: 'example_files', sizeField: 'size', ownerField: 'owner' }],
build: { script: 'build' },
peerVersions: { '@tinycld/core': '>=0.0.6 <0.1.0' },
// dependencies: ['other-package-slug'],
}
export default manifest
What each optional field does
routes.directory points to the folder of app screens the generator re-exports under tinycld/app/a/(app)/<slug>/, served at /a/<slug>/. See Screens.
publicRoutes.directory points to a folder whose files become public routes at tinycld/app/p/<slug>/<path>. Use this for pre-auth entry points such as public share links. The per-slug namespace means two packages never collide on the same path.
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 tinycld/server/pb_migrations/ and tinycld/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 lists each present feature’s server module in a generated tinycld/server/go.work (no per-package replace directive is needed). See Server.
cli.package and cli.module mirror server: the subdirectory holding a Go module, and the module path it declares. That module exposes Register(root *cobra.Command, c *client.Client), and the generator wires it into the tinycld binary. There is deliberately no command list - Cobra owns the command tree and --help, and a hand-maintained copy would only drift - and no scope list: the package’s Go server registers its OAuth scopes with core via oauth.RegisterPackage, naming the collections and routes each scope governs. See tinycld CLI reference and Go server extensions.
help.directory is the folder of markdown help topics the app indexes. A user-facing feature is not done until it has one; see In-app help.
search.adapter puts the package in the cross-app search palette. Rows come from core’s federated /api/search, which the package’s Go server feeds with search.RegisterSources; the adapter module only decides what selecting a row does. search.label overrides the chip label (default nav.label).
quota lists the collections that hold file bytes. Core enforces the per-user and deployment storage ceilings from it as record hooks, so no write path can skip them.
carddav, caldav, and webdav are declarative protocol blocks: field maps from the protocol’s vocabulary onto the package’s collections. Core serves the protocol from the config alone, so a deployment that links no feature Go still gets it. Copy the block from contacts, calendar, or drive and rename the fields.
eventSources and eventSourceHost let one package show a read-only feed on another’s grid (Boards’ due dates on the Calendar). See Event sources.
systemSettings is like settings but for deployment-wide configuration the owner manages once (a mail provider’s credentials, a webhook signing secret). payloads.package names a Go package declaring the HTTP payload contract, from which the generator emits typed TypeScript. repository.url feeds “Report an issue”.
automation.definitions is a subpath to a module that default-exports the package’s workflow-rules catalog: the triggers users can build rules on and the actions rules can take, as pure data typed against the package’s schema. See Automation.
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; one-shot builds gate packages:generate and the web export, and the dev launcher can run them in watch mode. Scripts are executed via the workspace’s hoisted tsx, so they can import dependencies the app shell provides - the member 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, plus seed ordering.
peerVersions is the enforced counterpart: semver ranges keyed by slug or @tinycld/core. The compatibility solver in Settings → Packages refuses a staged change that would leave any declared range unsatisfied, and the server checks again before applying. Every shipping package pins the core range it was built against ({ '@tinycld/core': '>=0.0.6 <0.1.0' }), and a release that adopts a new core API raises the floor.
For the exact TypeScript interface, see Manifest schema.