--- id: PX-SPEC-DZLVGRW4 type: spec title: Pi Extension Architecture --- ## Intent Make each Pi extension independently developable, testable, installable, releasable, and upgradable without sacrificing fast local work or complete collection use. Keep runtime behavior close to Pi's Node execution model and reduce startup and reload work through built artifacts. ## Source and package boundaries The repository root is a development workspace, not a Pi package. Each extension owns its source, metadata, tests, runtime resources, and generated package. Extensions neither import sibling extensions nor depend on sibling output paths. Shared development tooling is allowed; shared runtime files outside an extension package are not. Every extension emits a complete package under `dist/`. Pi settings list each generated extension package explicitly. The same package boundary is used for local development, verification, npm distribution, and Git distribution. Extension and shipped runtime code is authored in TypeScript. Generated JavaScript is allowed. Bootstrap automation may remain JavaScript when TypeScript would introduce a build-before-build cycle. ## Runtime dependencies A generated package runs without repository source, workspace links, ancestor `node_modules`, or undeclared ambient files. Node built-ins, Pi-provided modules, TypeBox modules supplied by Pi, and explicitly declared system executables may remain external. Portable third-party JavaScript is bundled by default. An external runtime dependency requires demonstrated bundling incompatibility or a clearly superior explicit integration. Workers, browser code, templates, filters, executable helpers, and other runtime assets remain inside their owning package. Pi extensions, skills, prompts, and themes are exposed only when explicitly declared. Generated manifests map declared resources to generated paths and never expose internal guidance accidentally. Packages preserve intentional lazy-loading boundaries through package-private generated chunks where useful. Package loading must not depend on removing or replacing Pi's jiti importer. ## Build behavior On-demand builds are the primary development interface. A watcher may invoke the same development build but has no protocol with Pi. After a successful build, the developer invokes Pi reload explicitly. Development and release builds emit to the same canonical package directory and intentionally replace one another. They preserve the same module boundaries, dependency policy, manifest shape, resources, and observable behavior. They may differ only in debugging information and behavior-neutral optimization. A failed or interrupted build leaves the last complete package usable. A successful build publishes the new entrypoint only after its required chunks and resources are complete. Content-addressed chunks may coexist temporarily so an already loaded extension can finish lazy imports during replacement. Release verification snapshots the exact generated bytes. Publication uses that verified snapshot or rejects a digest mismatch. ## Tool ownership Mise is the stable public automation API and a thin delegation layer. Mise manages runtimes and tools that the JavaScript package system does not own. It does not contain the extension build system. npm owns dependency installation, workspaces, the lockfile, and JavaScript task delegation. Rolldown owns extension bundling and is a direct development dependency. Vitest runs source tests on Node. Playwright owns browser acceptance. Pi on Node owns generated-package and compatibility verification. Bun is not part of the toolchain. Root package scripts and tooling own repository automation. Extension package scripts remain absent. ## Test architecture Tests are separated by the guarantee they provide. Unit and component tests exercise pure source behavior with deterministic inputs and no real Pi session unless necessary. Property tests belong to this layer and use reproducible seeds, shrinking, and retained regression cases. Small inline snapshots and readable file snapshots may protect stable rendered output after volatile data is normalized. Pi contract tests load extension entrypoints through Pi's real loader and exercise registration, lifecycle, dispatch, and provider routing through public APIs. Every extension has a path-loaded contract and fails on unexpected extension errors. Native integration tests exercise Node, filesystem, subprocess, Git, HTTP, cancellation, and platform behavior using owned temporary resources and controlled real processes. Tests requiring distinct process environments run in distinct processes. Generated-package tests execute immutable package snapshots outside the checkout with independently installed Pi versions. They verify relocation, manifests, resources, lazy first use, workers, allowed externals, and absence of workspace dependency leakage. Each extension is tested independently, and the complete configured collection is tested for composition conflicts. UI acceptance tests exercise generated browser or terminal artifacts through the real UI runner. ## Test fixture constraints The shared Pi fixture uses public, strongly typed Pi APIs and deterministic scripted providers. It owns environment, temporary paths, sockets, processes, timers, shutdown, and cleanup explicitly. Unexpected asynchronous and extension errors fail the test. Concurrent sessions never pretend to own distinct environments inside one process. Test correctness does not depend on text-patching installed dependencies or private Pi properties. An upstream harness is acceptable only when it satisfies the same contract; otherwise the repository owns the narrow fixture it needs. All maintained TypeScript is checked, including runtime code, tests, fixtures, configuration, workers, browser entrypoints, and TypeScript automation. Focused checking covers one extension and shared inputs without repeating repository-wide checking. Root checking covers the union once. ## Verification cadence Commit hooks contain only quick, deterministic, network-independent checks over the changed scope. Push hooks may add complete static checking and deterministic source tests. Hooks exclude browser installation, compatibility matrices, package publication, coverage instrumentation, mutation campaigns, and fuzz campaigns. Normal CI runs complete static checks, one coordinated source-test run, release builds, current-Pi package verification, and applicable native and UI integration. Release verification runs the immutable artifacts across the declared Pi, Node, and operating-system matrix. Current configured Pi compatibility is mandatory. The minimum supported Pi version is established empirically from an initially broad matrix. ## Test-quality techniques Coverage reports include unimported owned production files and report line, branch, and function coverage per extension. Coverage guides investigation and is not initially a percentage gate. The V8 and Istanbul providers are selected by measured suite behavior. Property testing is preferred for parsers, normalization, path safety, bounded rendering, serialization, and state machines. Failures record replay information and yield permanent minimal regression cases. Mutation testing is selective, incremental, and author-driven while test context is fresh. It targets pure unit-testable code by file or line range, retains a correctly invalidated per-extension cache, and is not a commit, push, or CI gate. Occasional full mutation runs may report repository health without imposing a score target. Snapshot testing protects concise, reviewable output contracts and never replaces semantic assertions. Snapshots exclude volatile paths, timestamps, identifiers, dependency diagnostics, and generated bundles. Snapshot updates are explicit and reviewed. Coverage-guided fuzzing is reserved for narrow hostile-input or security boundaries where property testing is insufficient. Long fuzz campaigns run manually or on a schedule. Minimized corpus findings become normal deterministic regression tests. ## Distribution and compatibility Public distribution uses Pi's normal npm and Git package channels. Consumers receive built packages and never need the source workspace or build toolchain. Generated packages contain no lifecycle installation scripts. Extensions remain independently releasable. Publication eligibility is independent from local loading, and releases publish only explicitly selected extensions. Versioning and compatibility metadata have one authoritative source and generated manifests do not become a second source of truth. The architecture supports Windows, macOS, and Linux. Platform tools are detected through normal extension behavior and unsupported optional capabilities degrade explicitly. ## Acceptance criteria - The repository root is not discoverable as a Pi package. - Pi loads the configured collection from one explicit local package entry per extension. - A focused development build updates only the selected extension package and leaves a complete reloadable result. - A release build overwrites the same package location without changing observable behavior. - Every generated package loads independently outside the checkout with zero unexpected diagnostics. - No generated package resolves sibling output, repository source, workspace links, or ancestor dependencies. - Declared resources and lazy first-use paths work after relocation. - The complete generated collection loads without identity, tool, command, flag, or resource conflicts. - Current configured Pi passes generated-package verification. - Compatibility results identify an explicit minimum supported Pi version before public release. - Focused tests and checking avoid unrelated extension work. - Root tests use one Vitest coordinator while retaining required worker and process isolation. - Maintained TypeScript is completely typechecked. - Release publication consumes the exact verified artifact bytes. - npm and Git consumers can install selected extensions without compiling source.