> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pcb.new/llms.txt
> Use this file to discover all available pages before exploring further.

# Packages

> Package management, workspaces, and dependency resolution

Package versions identify immutable source snapshots. A dependency on
`component-lib@0.3.2` selects the same source for every build until the manifest
changes.

## Version policy

PCB packages use semantic versions with hardware-specific compatibility rules:

| Change                            | Allowed contents                                                                                   |
| --------------------------------- | -------------------------------------------------------------------------------------------------- |
| Patch, such as `0.3.1` to `0.3.2` | Documentation and metadata changes that do not alter connectivity, layout, or electrical behavior. |
| Minor, such as `0.3` to `0.4`     | New compatible behavior after `1.0`; a breaking compatibility lane before `1.0`.                   |
| Major, such as `1.x` to `2.0`     | Breaking changes such as changed pins, interfaces, or removed behavior.                            |

<Warning>
  Per the [Semantic Versioning specification](https://semver.org/#spec-item-4),
  pre-1.0 packages have no stable public API. PCB therefore treats `0.3.x` and
  `0.4.x` as separate compatibility families.
</Warning>

Versions within one family must remain compatible:

```
v0.3.x family: 0.3.0, 0.3.1, 0.3.2, ...  (compatible)
v0.4.x family: 0.4.0, 0.4.1, ...          (compatible)
v0.3.x and v0.4.x: different families     (potentially incompatible)
```

When a dependency graph requires several versions from one family, resolution
selects the highest required version in that family. Authors must not publish a
breaking change within a family.

PCB combines Minimal Version Selection (MVS) with hydrated `pcb.toml` manifests
for reproducible builds. `pcb sync` records the selected dependency graph,
including immutable pseudo-versions for branch and commit dependencies. Build
commands then reuse that recorded graph without selecting newly published
versions.

## Workspace package discovery

Starting at the workspace root, `pcb` searches at most eight directory levels
and treats each descendant directory containing `pcb.toml` as a package.

`[workspace].exclude` controls discovery:

```toml theme={null}
[workspace]
pcb-version = "0.4"
exclude = ["scratch/**", "experiments/old-board"]
```

`pcb` does not search inside an excluded directory. It also skips generated and
cache directories such as
`.git`, `.pcb`, `vendor`, `target`, `node_modules`, and `fork`.

## Coexisting versions

A build can contain multiple incompatible families of one package. For example:

```toml theme={null}
# Library X
[dependencies]
"github.com/acme/component-lib" = "0.3"

# Library Y
[dependencies]
"github.com/acme/component-lib" = "1.0"
```

The resolver retains separate copies of `component-lib@0.3.x` and
`component-lib@1.x` for their respective dependents. This permits incremental
migration and diamond dependencies. Values from the two families have distinct
types and cannot be passed across the compatibility boundary.

## Minimal Version Selection

PCB uses MVS, based on [Go modules](https://go.dev/ref/mod). For each package
family, MVS selects the lowest version that satisfies every explicit minimum in
the dependency graph. Newly published versions do not change the result unless a
manifest requires them.

### How MVS works

Consider this dependency graph:

```
Board
├── component-lib >= 0.3
└── regulator >= 1.0
    └── component-lib >= 0.3.2
```

The board requires `component-lib >= 0.3.0`, while `regulator` requires
`component-lib >= 0.3.2`. MVS therefore selects `0.3.2`, even if `0.3.9` exists.
Require a newer version explicitly when the project is ready to test it:

```toml theme={null}
[dependencies]
"github.com/acme/component-lib" = "0.3.9"
```

MVS is deterministic and does not backtrack. Within each compatibility family,
the selected version is the highest minimum requested by any dependent.

### Resolution algorithm

1. **Seed:** Collect direct dependencies from all workspace packages. Group by
   package path and compatibility family. Initialize each family to the highest version
   explicitly required.

2. **Discover:** Fetch manifests for selected versions. For each transitive
   dependency, if it requires a higher version within an existing family, upgrade.
   Repeat until the selected graph no longer changes.

3. **Build closure:** Trace the dependency graph from workspace roots using final
   versions. This filters out any versions that were superseded during discovery.

For multiple compatibility families:

```
WV0001: component-lib = 0.2.13
WV0002: component-lib = 0.3.2, regulator = 1.0
WV0003: component-lib = 0.3.1
regulator@1.0.0: component-lib = 0.3.0

Result:
  v0.2.x family → component-lib@0.2.13
  v0.3.x family → component-lib@0.3.2 (max of 0.3.2, 0.3.1, 0.3.0)
```

Both versions remain in the build because they belong to different families.

## Import paths as identity

Import paths serve as globally unique package identifiers:

```python theme={null}
load("@stdlib/units.zen", "Voltage")
load("github.com/myorg/components/capacitor.zen", "Capacitor")
```

The path identifies the package owner and source repository without a central
namespace. A file's imports also state which packages its source requires.

Import paths omit versions. The `pcb.toml` manifest declares which version of
each package to use:

```toml theme={null}
[dependencies]
"code.diode.computer/diode/registry/components/ti/tps54331" = "1.0"
```

This separation keeps import statements stable across upgrades and confines
version changes to manifests. The same source file can use different selected
versions in different workspaces.

## Hydrated manifests

Workspaces store resolved dependency state in `pcb.toml`. `pcb sync` updates:

* `[dependencies]`: direct dependencies the package imports or explicitly owns.
* `[dependencies.indirect]`: the tool-managed MVS closure needed to build it.

```toml theme={null}
[dependencies]
"code.diode.computer/diode/registry/modules/Regulator" = "1.0"

[dependencies.indirect]
"code.diode.computer/diode/registry/components/TPS54331@1" = "1.0.2"
"code.diode.computer/diode/registry/modules/Feedback@1" = "1.1.0"
```

The `@1` suffix is a compatibility lane. It allows multiple
incompatible versions of the same package path to coexist while keeping the
selected version exact.

Do not edit `[dependencies.indirect]` by hand. Commit hydrated `pcb.toml` files.

## Vendoring (`[workspace].vendor`)

Vendoring policy is controlled by the root workspace manifest:

```toml theme={null}
[workspace]
vendor = ["github.com/myorg/**"]
```

* `pcb publish` uses `[workspace].vendor` patterns when staging release sources.
* `pcb sync` vendors packages matched by `[workspace].vendor`.
* `pcb vendor` without `--all` uses `[workspace].vendor`.
* `pcb vendor --all` vendors everything.
* Read commands such as `pcb build`, `pcb layout`, `pcb test`, `pcb open`, and
  `pcb bom` do not change `vendor/` or rewrite dependency manifests.

## Workspace name (`[workspace].name`)

Workspace manifests can override the Diode workspace name used for board
release uploads:

```toml theme={null}
[workspace]
name = "my-workspace"
```

If `name` is omitted, `pcb publish` derives the workspace name from the first
path segment of `[workspace].repository`. For example,
`anything.com/XYZ/boards/MyBoard` uses `XYZ`.

## Endpoint (`[workspace].endpoint`)

Workspace manifests can override the Diode host suffix used by CLI commands
that access Diode services:

```toml theme={null}
[workspace]
endpoint = "diode.computer"
```

* `endpoint = "diode.computer"` resolves application and API URLs under
  `app.diode.computer` and `api.diode.computer`.
* The setting applies to workspace-aware commands such as `pcb auth`, `pcb bom`,
  `pcb publish`, and routing commands.
* Authentication is scoped to the resolved endpoint. Authentication for one
  endpoint does not overwrite tokens for another.

## BOM matching (`[workspace.bom]`)

`pcb bom` availability queries use strict BOM matching by default, requiring
exact MPN matches. Workspace manifests can opt out to use fuzzy matching:

```toml theme={null}
[workspace.bom]
strict = false
```

Normalized BOM matches are cached independently per sourcing group. Lines that
the planner can source together refresh and fall back atomically, preserving
their combined quantity and selected offer. `pcb bom` treats groups updated
within the last ten minutes as fresh and refreshes only stale or missing groups.
`pcb bom --offline` never contacts the API and uses each available cached group
regardless of age; cache misses retain the locally generated BOM data without
availability.

## Registry search scope

Registry-backed `pcb search` searches the public Diode registry and the
registries configured by `[workspace].repository`.

* `pcb search --registry code.diode.computer/diode/registry ...` overrides the default
  scope for that invocation.
* Repeat `--registry` to search more than one registry.

## Pseudo-versions

Pseudo-versions identify unreleased commits while preserving version ordering.

The format is `v<base>-0.<timestamp>-<commit>`.

```toml theme={null}
[dependencies]
# Branch reference - resolved to pseudo-version
"github.com/acme/component-lib" = { branch = "main" }

# Specific commit
"github.com/acme/component-lib" = { rev = "a1b2c3d4" }
```

Resolution produces a version such as:

```
v0.3.15-0.20251120004415-137e2dcabc28…   # commit hash shortened here for readability
```

`pcb sync` writes the resolved pseudo-version back to the package manifest with
the full 40-character commit hash.

The base version (0.3.15) is the next patch version after the most recent tag
reachable from that commit. This places the pseudo-version after its base tag and
before the next release.
If the package has never been tagged, pseudo-versions start in the `0.1.1`
family (for example `0.1.1-0.<timestamp>-<commit>`), one patch above the
initial unpublished release version `0.1.0`.

Pseudo-versions participate fully in MVS. If one package requires `component-lib@0.3.14`
and another requires the pseudo-version above, MVS selects the pseudo-version
(it is higher). This permits testing an unreleased change without retaining a
mutable branch reference in the hydrated graph.

Use a tagged release for production dependencies when one is available.

## Commands

### `pcb migrate`

Runs project migrations using the latest stable `pcbc` toolchain, regardless of
the workspace's current `pcb-version` lane. After all migrations succeed, the
command updates `[workspace].pcb-version` in `pcb.toml` to the target toolchain
lane.

```bash theme={null}
pcb migrate
pcb migrate ./path/to/workspace
```

### `pcb sync`

Reconciles imports and hydrates package manifests. Run this after adding or
removing imports or changing dependency versions.

```bash theme={null}
pcb sync                    # Sync packages under the current workspace/package
pcb sync --check            # CI guard: fail if pcb.toml or vendor/ is out of sync
pcb sync -v                 # Print changed manifests
```

The command also downloads selected packages into the cache and vendors packages
matched by `[workspace].vendor`.

`pcb sync --check` always verifies the whole workspace, regardless of the
current directory, and writes neither `pcb.toml` nor `vendor/`. It detects
missing or stale vendored package versions; it does not verify the contents of
vendored versions that are already present.

### `pcb add`

Adds or upgrades a direct dependency for the package in the current directory.

```bash theme={null}
pcb add github.com/acme/regulators/Buck@1.2.3
pcb add github.com/acme/regulators/Buck@latest
pcb add -u                              # Upgrade all direct remote dependencies
pcb add -u github.com/acme/regulators/Buck
```

`pcb add` rewrites the direct dependency entry and rehydrates the package's
dependency closure.

### `pcb build`

Builds a board or workspace package.

```bash theme={null}
pcb build                    # Build default board
pcb build WV0002.zen         # Build a specific board file
pcb build --offline          # Build using only cached/vendored packages
```

`pcb build` checks that the hydrated state is sufficient and does not rewrite
`pcb.toml` or `vendor/`. Use `pcb sync` or `pcb vendor` to update dependency
state.

### `pcb list`

Lists read-only package dependency information.

```bash theme={null}
pcb list -m -u                              # Show compatible updates for direct dependencies
pcb list -m -versions github.com/acme/foo   # Show published versions for a dependency
```

`pcb list -m -u` must be run from a package directory. It reports direct remote
dependencies only, showing the latest stable version in the same compatibility
lane and the latest newer breaking lane when available. It does not update manifests.

### `pcb update`

`pcb update` is disabled. Use `pcb add -u` instead.

```bash theme={null}
pcb add -u                   # Upgrade all direct remote dependencies
pcb add -u github.com/acme/regulators/Buck
```

### `pcb publish`

Publishes packages by creating annotated git tags. Discovers which packages
have changed since their last published version and tags them.

```bash theme={null}
pcb publish                  # Publish all changed packages
pcb publish --bump=infer     # Infer bumps from commit history and dependency waves
pcb publish --bump=infer -y  # Skip the final publish confirmation
pcb publish --force          # Skip preflight checks
```

A package requires publication when:

* No version tag exists.
* Its content hash differs from the published tag.
* Its `pcb.toml` hash differs from the published tag.

Versions are computed automatically:

* **Unpublished:** Start at `0.1.0`.
* **Published packages:** Apply the requested semantic-version bump: `patch`,
  `minor`, or `major`.
* **`--bump=infer`:** Infer each bump from conventional commits since the last
  tag, then raise dependent bumps to at least the highest bump among published
  internal dependencies.
* **`-y` / `--yes`:** Skip the final confirmation prompt.

Packages are published in dependency order. Packages with no changed
dependencies are published first; their dependents follow after manifest
updates.

### `pcb info`

Displays workspace and package information.

```bash theme={null}
pcb info                     # Show workspace summary
pcb info --format json       # Machine-readable output
```
