Context
We need a tracked design/implementation issue for fbuild sync, a uv-like dependency sync command for PlatformIO projects.
fbuild sync should read platformio.ini, resolve dependency identities, install missing packages into the existing fbuild cache, and write a deterministic JSON platformio.lock next to platformio.ini.
This is primarily for testing, auditing, and reproducible dependency installation at first. Strict build/deploy consumption of the lockfile should be deferred until the lockfile path has enough coverage.
PlatformIO does not appear to have a shipped lockfile convention to mirror. Its docs define dependency declarations through lib_deps, including registry, VCS, archive, and local sources, and platformio-core has an open feature request for Cargo/npm-style exact direct/transitive dependency lockfiles with hashes:
platformio/platformio-core#4613
Repo design note:
tasks/fbuild-sync-design.md
Proposal
Add fbuild sync with these semantics:
- Default
fbuild sync resolves all [env:*] entries.
- If more than one env is selected, warn and prompt before proceeding.
fbuild sync -e <env> resolves one environment and does not prompt.
--yes accepts all-env sync scope for scripts/non-interactive use.
--locked requires a fresh lockfile, installs missing packages from it, and never rewrites it.
--check validates freshness/cache state without installing or writing.
--dry-run prints planned lock changes and missing installs.
--upgrade and --upgrade-package <name> allow controlled repinning.
The lockfile should be JSON, stable, sorted, and written as:
<project-dir>/platformio.lock
Lock everything that affects dependency identity where fbuild can resolve it:
- Toolchains.
- Platform/framework packages.
- Direct and transitive
lib_deps.
- Remote
.lnk blobs.
- GitHub/VCS deps resolved to immutable commit SHAs; tag specs should record both tag and resolved SHA.
- Remote/user-overridden board package metadata where applicable.
Represent local deps, but do not pretend they are reproducible:
symlink://
file://
- relative paths
- absolute paths
These should be included as local/unlocked entries.
Decisions
- JSON v1 should duplicate package records under each env rather than hoisting shared package records to a top-level table.
--check should skip the multi-env prompt, including in non-interactive mode, because it does not install or write.
- Registry metadata should include as much as necessary for reproducible installation, auditing, and future lockfile consumption; avoid copying decorative fields with no consumer.
Implementation touch points
crates/fbuild-cli/src/cli/args.rs: add Commands::Sync and include it in KNOWN_SUBCOMMANDS.
crates/fbuild-cli/src/cli/dispatch.rs: route sync command.
crates/fbuild-daemon/src/main.rs: add POST /api/sync.
crates/fbuild-daemon/src/handlers/operations/: add sync handler mirroring /api/install-deps.
crates/fbuild-build/src/lib.rs: split dependency identity resolution from immediate installation in PlatformSupport.
crates/fbuild-packages/src/library/: make registry/GitHub resolution observable without download side effects.
crates/fbuild-packages/src/downloader.rs: expose archive SHA256 capture for lockfile entries.
crates/fbuild-config/src/ini_parser/: reuse resolved env and lib_deps parsing for dependency-relevant input hashing.
Acceptance criteria
fbuild sync writes deterministic JSON platformio.lock next to platformio.ini.
- Default sync covers all envs and prompts when more than one env is selected.
fbuild sync -e <env> syncs only that env and does not prompt.
--yes allows non-interactive all-env sync.
--check validates all selected envs without prompting, installing, or writing.
--locked installs missing packages from an existing fresh lockfile and does not rewrite it.
--check fails on stale/missing required lock entries without installing or writing.
- GitHub branch dependencies are pinned to immutable commit SHAs in the lockfile.
- GitHub tag dependencies record tag plus resolved commit SHA.
- Local dependencies are represented as
status: "unlocked".
- Package records are duplicated under each env in JSON v1.
- Lockfile writes are atomic and serialized by the existing per-project daemon lock.
- Shared package installs reuse existing per-package install locks.
- Build/deploy strict consumption is not required for this issue.
Context
We need a tracked design/implementation issue for
fbuild sync, a uv-like dependency sync command for PlatformIO projects.fbuild syncshould readplatformio.ini, resolve dependency identities, install missing packages into the existing fbuild cache, and write a deterministic JSONplatformio.locknext toplatformio.ini.This is primarily for testing, auditing, and reproducible dependency installation at first. Strict build/deploy consumption of the lockfile should be deferred until the lockfile path has enough coverage.
PlatformIO does not appear to have a shipped lockfile convention to mirror. Its docs define dependency declarations through
lib_deps, including registry, VCS, archive, and local sources, and platformio-core has an open feature request for Cargo/npm-style exact direct/transitive dependency lockfiles with hashes:platformio/platformio-core#4613
Repo design note:
tasks/fbuild-sync-design.mdProposal
Add
fbuild syncwith these semantics:fbuild syncresolves all[env:*]entries.fbuild sync -e <env>resolves one environment and does not prompt.--yesaccepts all-env sync scope for scripts/non-interactive use.--lockedrequires a fresh lockfile, installs missing packages from it, and never rewrites it.--checkvalidates freshness/cache state without installing or writing.--dry-runprints planned lock changes and missing installs.--upgradeand--upgrade-package <name>allow controlled repinning.The lockfile should be JSON, stable, sorted, and written as:
Lock everything that affects dependency identity where fbuild can resolve it:
lib_deps..lnkblobs.Represent local deps, but do not pretend they are reproducible:
symlink://file://These should be included as local/unlocked entries.
Decisions
--checkshould skip the multi-env prompt, including in non-interactive mode, because it does not install or write.Implementation touch points
crates/fbuild-cli/src/cli/args.rs: addCommands::Syncand include it inKNOWN_SUBCOMMANDS.crates/fbuild-cli/src/cli/dispatch.rs: route sync command.crates/fbuild-daemon/src/main.rs: addPOST /api/sync.crates/fbuild-daemon/src/handlers/operations/: add sync handler mirroring/api/install-deps.crates/fbuild-build/src/lib.rs: split dependency identity resolution from immediate installation inPlatformSupport.crates/fbuild-packages/src/library/: make registry/GitHub resolution observable without download side effects.crates/fbuild-packages/src/downloader.rs: expose archive SHA256 capture for lockfile entries.crates/fbuild-config/src/ini_parser/: reuse resolved env andlib_depsparsing for dependency-relevant input hashing.Acceptance criteria
fbuild syncwrites deterministic JSONplatformio.locknext toplatformio.ini.fbuild sync -e <env>syncs only that env and does not prompt.--yesallows non-interactive all-env sync.--checkvalidates all selected envs without prompting, installing, or writing.--lockedinstalls missing packages from an existing fresh lockfile and does not rewrite it.--checkfails on stale/missing required lock entries without installing or writing.status: "unlocked".