Skip to main content

Creating packages

Creating an Atomic Package

Add an app manifest to package.json or use conventional directories. The manifest key is the configured app name (atomic here, from atomicConfig.name; legacy piConfig.name is also read). The legacy pi key remains supported as a backwards-compatible shim. Include the atomic-package keyword for discoverability.
Paths are relative to the package root. Arrays support glob patterns and !exclusions.

MCP Servers

A package can contribute MCP servers with mcpServers. Point it at a JSON file in the standard { "mcpServers": { ... } } shape, relative to the package root, or declare the servers inline:
Entries use the same schema as mcp.json, including URL environment-variable interpolation, tool exposure, per-tool toolExposure, and request timeout in seconds. A relative cwd is resolved against the package root, so "cwd": "." lets a stdio server run files shipped in the package. MCP servers are only read from the manifest, never from a convention directory. Package manifests cannot select provider login credentials with auth.provider. Contributed servers have the lowest precedence: users can replace or disable one by name in their own MCP configuration, and filter them with mcpServers patterns in settings. Project packages contribute servers only in trusted projects. For a server whose configuration is computed at runtime, call pi.registerMcpServer() from an extension.

Storage Adapters

A package can provide storage adapters with storageAdapters, a list of adapter module paths relative to the package root. Put the database driver in dependencies so atomic install installs it with the package, and list @bastani/atomic in peerDependencies:
Users select the adapter with the package name, for example "storage": { "adapter": "@example/atomic-libsql" }, or with <package>/<name> when the package lists several adapters, where <name> is the adapter file’s name without its extension. Storage adapters are only read from the manifest, never from a convention directory, and only from packages in user settings. See Adapters from Atomic packages. The package gallery currently recognizes legacy pi-package metadata, while new Atomic packages should also include atomic-package. Add video or image fields to show a preview:
  • video: MP4 only. On desktop, autoplays on hover. Clicking opens a fullscreen player.
  • image: PNG, JPEG, GIF, or WebP. Displayed as a static preview.
If both are set, video takes precedence.

Package Structure

Convention Directories

If no app manifest (atomic, or legacy pi) is present, Atomic auto-discovers resources from these directories:
  • extensions/ loads .ts and .js files
  • skills/ recursively finds SKILL.md folders and loads top-level .md files as skills
  • prompts/ loads .md files
  • themes/ loads .json files
  • workflows/ loads workflow SDK files (.ts, .js, .mjs, .cjs); workflow/ is also accepted as a singular alias.
Workflow files import workflow from @bastani/atomic/workflows, import Type from typebox, and export the definition returned by workflow({ ... }). TypeScript resolves the published @bastani/atomic/workflows specifier through the @bastani/atomic package. Workflow files support typebox, typebox/compile, and typebox/value. Use these current imports even when an extension in the same package uses the host’s additional schema aliases. See Programmatic usage. When a package manifest exists, declared resource arrays normally define what loads. Workflows are the exception: if atomic.workflows / legacy pi.workflows is omitted, Atomic still checks conventional workflows/ and workflow/ directories.

Dependencies

Third-party runtime dependencies belong in dependencies in package.json. Dependencies that do not register extensions, skills, prompt templates, themes, or workflows also belong in dependencies. When Atomic installs a package from npm or git, it runs the configured npm-compatible install command, so those dependencies are installed automatically. Atomic bundles core packages for extensions and skills. If you import any of these, list them in peerDependencies with a "*" range and do not bundle them: @bastani/pi-ai, @earendil-works/pi-agent-core, @bastani/atomic, @earendil-works/pi-tui, typebox. Atomic does not install peer dependencies for npm packages or for git packages installed with npm, pnpm, or Bun. Local packages are not installed or modified, so their dependency tree is up to the package author. Do not list these host-provided packages in dependencies. An installed copy can bypass Atomic’s extension module mapping and create duplicate classes, registries, and startup work. Atomic shows an extension warning when a package’s dependencies include one of them. Workflow packages import workflow from @bastani/atomic/workflows, import Type from typebox, and export definitions returned by workflow({ ... }). List @bastani/atomic and typebox in peerDependencies so package consumers receive the workflow SDK and schema library. Package-authored workflows should follow the same guiding principles as project workflows. Other Atomic packages must be bundled in your tarball. Add them to dependencies and bundledDependencies, then reference their resources through node_modules/ paths. Atomic loads packages with separate module roots, so separate installs do not collide or share modules. Example: