Workspaces, Packages & Modules
Relevant source files
The following files were used as context for generating this wiki page:
Pop Lang uses a precise, hierarchical ownership model to manage code organization, visibility, and compilation boundaries. This system is designed to provide strong static guarantees and predictable native runtimes, moving away from the table-centered dynamic semantics of Lua while preserving its lightweight syntax.
The hierarchy follows a strict progression: Item → Module → Bubble → Package → Workspace. Each level serves a specific role in the development lifecycle, from local file scoping (Modules) to independent compilation and linking units (Bubbles), up to publishable versioned units (Packages) and multi-package management roots (Workspaces).
Sources: architecture/21-cli-tooling-and-code-units.md:3-9, AGENTS.md:374-380, README.md:143-150
The Ownership Hierarchy
Pop Lang enforces a fixed ownership structure that defines how code is identified, compiled, and shared. This hierarchy ensures that visibility and dependency boundaries are strictly maintained.
Summary of Units
| Unit | Meaning | Identity Boundary |
|---|---|---|
| Item | A declaration (function, type, constant, attribute, etc.). | Stable SymbolId within a Bubble. |
| Module | A single .pop source file. | Private visibility and initialization owner. |
| Bubble | Independently compiled unit (analogous to a Rust crate). | internal visibility and linking boundary. |
| Package | A versioned, publishable directory with a bubble.toml. | Dependency version and distribution identity. |
| Workspace | A group of Packages managed together. | Shared bubble.lock, cache, and policy root. |
Sources: architecture/21-cli-tooling-and-code-units.md:11-20, architecture/14-libraries-namespaces-and-loading.md:52-60
Structural Relationship Diagram
The following diagram illustrates the containment relationship between the different units of code in the Pop Lang ecosystem.
The diagram shows how a Workspace acts as the root for multiple Packages, which in turn contain Bubbles, Modules, and finally atomic Items.
Sources: architecture/21-cli-tooling-and-code-units.md:5-9, AGENTS.md:382-392
Modules and Namespaces
Modules
A Module corresponds to exactly one .pop file. It is the boundary for private visibility and is responsible for managing its own initialization. Unlike Lua, Modules in Pop are not tables and do not return values; they are compile-time concepts resolved statically through namespaces.
Sources: architecture/21-cli-tooling-and-code-units.md:36-40, architecture/14-libraries-namespaces-and-loading.md:65-72
Namespaces
Every Module must declare exactly one file-scoped namespace (e.g., namespace Studio.Gameplay). Namespaces are orthogonal to the ownership hierarchy; they organize symbols but do not represent files, Bubbles, or runtime objects. A namespace can span multiple Modules within a single Bubble, but it cannot span across different Bubbles.
Sources: architecture/21-cli-tooling-and-code-units.md:22-25, architecture/14-libraries-namespaces-and-loading.md:12-20
Bubbles: The Unit of Compilation
A Bubble is the smallest independently compiled program unit in Pop Lang, serving as the equivalent of a Rust crate. It defines the boundary for internal visibility.
Bubble Characteristics
- Compilation Boundary: A Bubble is the unit for reference metadata, code generation, and linking.
- Visibility: Items marked
internalare accessible to all Modules within the same Bubble but are hidden from external Bubbles. - Types of Bubbles:
library: Emits.poplibartifacts containing reference metadata.binary: An executable entry point (requires amainfunction).test,example,benchmark: Specialized executable units.
Sources: architecture/21-cli-tooling-and-code-units.md:46-60, architecture/decisions/0017-bubbles-packages-workspaces-and-cli.md:20-25
Visibility Levels
| Modifier | Visibility Scope |
|---|---|
public | Visible to dependent Bubbles (emitted in reference metadata). |
internal | Visible across Modules within the same Bubble only. |
private | Visible only within the declaring Module file. |
Note: Omitted visibility defaults to internal (except for the binary entry main function, which defaults to private).
Sources: architecture/14-libraries-namespaces-and-loading.md:34-40, AGENTS.md:345-351
Packages and Workspaces
Packages
A Package is defined by the presence of a bubble.toml file containing a [package] section. It manages versioning and distribution. All Bubbles within a Package share the same version.
Conventional Layout:
gameplay/
├── bubble.toml
├── src/
│ ├── lib.pop (Default Library Root)
│ ├── main.pop (Default Binary Root)
│ └── bin/ (Additional Binaries)
└── tests/ (Integration Tests)
Sources: architecture/21-cli-tooling-and-code-units.md:66-88, README.md:154-162
Workspaces
Workspaces allow multiple Packages to be developed together. A Workspace is identified by a bubble.toml containing a [workspace] section. It centralizes dependency resolution through a single bubble.lock file and uses a shared target/ directory for incremental build reuse.
Sources: architecture/21-cli-tooling-and-code-units.md:120-135, architecture/decisions/0017-bubbles-packages-workspaces-and-cli.md:16-18
Dependency Resolution and Linking
Pop Lang uses a locked resolution strategy. The bubble.lock file records exact package versions, content hashes, and Bubble edges to ensure reproducibility.
Resolution Flow
The following sequence diagram describes how the compiler resolves dependencies between Bubbles.
The diagram represents the flow from manifest reading to the loading of reference metadata, which is used for static analysis without initializing runtime code.
Sources: architecture/14-libraries-namespaces-and-loading.md:144-155, architecture/21-cli-tooling-and-code-units.md:168-175
Bubble Artifacts (.poplib)
Library Bubbles emit .poplib artifacts. These contain:
bubble.manifest: Identifies the Bubble and its platform targets.reference.metadata: Contains public signatures, constants, and layout info needed for dependent Bubbles.documentation.xml: Structured API documentation (separate from binary implementation).
Sources: architecture/14-libraries-namespaces-and-loading.md:95-105, architecture/14-libraries-namespaces-and-loading.md:124-135
Conclusion
The hierarchy of Workspaces, Packages, and Bubbles provides a structured foundation for Pop Lang. By strictly separating compilation units (Bubbles) from distribution units (Packages) and name scopes (Namespaces), Pop Lang ensures that code remains statically analyzable and secure, while providing developers with modern tooling for both small projects and large-scale monorepos.
Sources: README.md:204-210, architecture/21-cli-tooling-and-code-units.md:230-235