arduino-sketch-tool
v1.1.0
Published
Create, inspect, validate and update Arduino sketch.yaml profiles using published board and library catalogs.
Maintainers
Readme
Arduino Sketch Tool
A JavaScript library and CLI for creating, validating, and maintaining Arduino standard sketch.yaml files. Inspect recorded board settings and dependency pins, then change selected entries. Use it from a terminal, scripts, or CI, for one sketch or a repository of test sketches.
Create YAML, validate configuration, inspect and edit profile board options, compare dependencies, update pins, and set explicit versions. Arduino CLI handles compilation and upload; your test runner handles device tests.
Concept
Use native Arduino CLI capabilities to build and test recorded project conditions. This tool supports creating, understanding, and maintaining those conditions. Its target is each sketch's profiles rather than ordinary installed-resource lists.
It also provides sketch.yaml best practices: unversioned cores use ordinary installed versions and are discouraged outside core development; missing published-library versions are errors. There is no latest declaration, so adopting latest still requires recording a concrete version.
Preserve intentional unversioned local cores and library dir: references as valid development configuration. Distinguish configuration errors, environment warnings, and update eligibility; release conversion to published references is a separate operation.
Pinned-build CI, dependency maintenance jobs, and compatibility experiments serve different purposes. See Concept and project workflow design for responsibilities and pinned-build CI and latest-compatibility workflows.
Working with Arduino CLI
Ordinary IDE / Arduino CLI use shared core and library installations across projects. Updating that environment affects projects using it. Keeping an older project's tested versions while adopting newer versions elsewhere requires project-specific management.
Building a pinned sketch.yaml profile obtains dependencies in storage isolated from the ordinary environment. Both installations coexist; the same version can have separate copies in the two areas. Profiles can reuse cached identical dependencies, so this does not mean one copy per project. See the official profile specification.
Arduino CLI operations resolving a core by FQBN require ordinary core installation; isolated profile resources do not provide an equivalent ordinary lookup. The everyday target is therefore sketch YAML and a profile name. Inspect the used board, options, and dependency pins from that configuration regardless of whether the board is installed in the ordinary environment.
npx arduino-sketch-tool list ./tests/example
npx arduino-sketch-tool board ./tests/example --profile s3_test
npx arduino-sketch-tool check ./tests/example --profile s3_test
npx arduino-sketch-tool set ./tests/example --profile s3_test \
--board-option USBMode=default --dry-runboard separates YAML values from catalog choices/defaults and identifies differences between the pinned core version and metadata version. Catalog metadata is a reference; it cannot guarantee identical options for older pinned cores. Build, upload, and hardware tests use Arduino CLI / pytest with the selected profile.
Record additional core sources in the profile rather than relying only on global settings:
platforms:
- platform: esp32:esp32 (3.3.7)
platform_index_url: https://espressif.github.io/arduino-esp32/package_esp32_index.jsonShare version and URL together, reducing dependence on another computer's or CI's global settings. For a new board, use catalog boards/libraries searches and init --fqbn; then maintain the created profile through the same workflow. See the advanced comparison for Arduino CLI's own version-selection and profile-editing capabilities.
Usage guides
| Guide | Audience and contents | |---|---| | Beginner guide | Arduino CLI roles, profile pins, setup, current board inspection, editing, creation, and build checks | | Advanced guide | Installed resources vs. profiles vs. catalogs, batch maintenance, CI, AI reports, and shared APIs |
Start with the beginner guide for initial configuration and maintenance. For reproducible test maintenance and automation, use the advanced guide. This README is the concise command and behavior reference.
Requirements and execution
Node.js 18 or newer and npm are required. Run the published arduino-sketch-tool package with npx; no global installation or source checkout is required.
npx arduino-sketch-tool --help
npx arduino-sketch-tool --versionFollow npm's package-download prompt on first use. In CI, skip interactive confirmation and pin the tool version:
npm install --save-dev --save-exact arduino-sketch-tool
npm ci
npx --no-install arduino-sketch-tool --versionFor JavaScript APIs, run npm install arduino-sketch-tool in the consuming project. --offline controls this tool's catalog retrieval; prepare the npm package and dependencies beforehand to execute npx without networking.
CLI
npx arduino-sketch-tool list ./tests --recursive --json
npx arduino-sketch-tool board ./tests/example --profile s3_test
npx arduino-sketch-tool check ./tests/example --profile s3_test
npx arduino-sketch-tool update ./tests/example --profile s3_test --dry-run
npx arduino-sketch-tool update ./tests/example --profile s3_test
npx arduino-sketch-tool update ./tests --recursive --platform esp32:esp32
npx arduino-sketch-tool update ./tests --recursive --library EspUsbHost --profile s3_peer_host
npx arduino-sketch-tool set ./tests --recursive --platform esp32:esp32 --version 3.3.12
npx arduino-sketch-tool set ./tests --recursive --library EspUsbHost --version 2.10.0 --dry-runFor existing YAML commands, input paths may be sketch directories, YAML files or multiple paths. Without a path, use the current directory. A directory uses its own sketch.yaml; parent directories are not searched or copied. Recursive discovery includes peer sketches, skips hidden directories and build, .build, dist, node_modules, venv, __pycache__, output, and does not follow symlinks. Repeat --exclude NAME to skip additional directory names. Explicit file/directory inputs may override discovery exclusions; explicit symlink inputs are rejected. init treats paths as new destinations and does not discover files recursively.
Repeat --profile, --platform, or --library to select multiple names. Platform and library filters cannot be combined. Library matching is case-insensitive. A filter matching no dependencies across all inputs is an error; a profile need not exist in every file. list shows all dependencies of matching profiles, while check/update/dependency set operate only on matching entries.
Dependency set --version changes existing dependencies without catalogs or network access. It supports unpublished, older, and manually specified versions, but does not add dependencies or establish that a version can be installed or compiled. Pinning an unversioned core is rejected with PROTECTED_CORE; add --pin-unversioned only when intentionally switching to a published core. dir: remains preserved.
board and set --board-option choose explicit profiles, otherwise default_profile, otherwise a single profile. Ambiguous selection or explicitly missing names fail. Dependency batch operations cover all profiles unless filtered, so specify --profile for everyday maintenance.
npx arduino-sketch-tool set ./tests/example --profile s3_test \
--board-option USBMode=default --board-option CDCOnBoot=cdc --dry-runRemove --dry-run after review to edit those keys. Other options, dependency versions, and URLs are retained. Validation uses catalog choices; build validation under the pinned version is still required. --fqbn selects a board for init/edit and filters references for board/boards.
Validate configuration
validate separates configuration errors from environment warnings without loading catalogs. check compares published versions; it does not replace configuration validation.
npx arduino-sketch-tool validate ./tests/example --profile s3_test
npx arduino-sketch-tool validate ./tests --recursive --fail-on-warning --json| Severity | Examples | Default result |
|---|---|---|
| error | Missing published-library versions, latest, invalid YAML or board option syntax | Exit 1 |
| warning | Unversioned cores, missing additional core index URLs | Exit 0; exit 2 with --fail-on-warning |
| info | Local dir: references, explicitly declared local core development | Retained as valid development conditions |
For local core development, declare the intended platform with, for example, --allow-unversioned-core lang-ship:host; its omitted version becomes information rather than a warning. After environment setup, add --check-local-paths to verify that dir: paths exist and are directories. Core links and actual install/build availability are checked by Arduino CLI and the test environment. validate accepts profile filters only and validates all profiles by default. Explicitly requested profiles missing from any selected file are errors.
Edit existing profiles and dependencies
# Add a profile while retaining existing profiles
npx arduino-sketch-tool edit ./tests/example --add-profile uno_test \
--fqbn arduino:avr:uno --platform-version 1.8.6 --dry-run
# Switch board and matching core together
npx arduino-sketch-tool edit ./tests/example --profile s3_test \
--fqbn arduino:avr:uno --platform-version 1.8.6 --dry-run
# Explicitly switch a development reference to a published pin
npx arduino-sketch-tool edit ./tests/example --profile s3_test \
--remove-local-library ../../../ --add-library "MyLibrary (1.0.0)" --dry-run
# Correct an existing core index URL
npx arduino-sketch-tool edit ./tests/example --profile s3_test \
--platform-index-url https://espressif.github.io/arduino-esp32/package_esp32_index.json --dry-run
# Change the default / remove an unwanted profile
npx arduino-sketch-tool edit ./tests/example --default-profile s3_test --dry-run
npx arduino-sketch-tool edit ./tests/example --remove-profile uno_test --default-profile s3_test --dry-runRemove --dry-run after review. edit operates on existing YAML; use init for new files. Run the removal example only after adding that profile. Removing the last profile is refused.
--add-library resolves an unversioned name through the catalog or accepts Name (version). --remove-library uses the published name. --add-local-library / --remove-local-library use the exact dir: path string in YAML. All are repeatable. Combine removal and addition to explicitly switch between local and published references. Duplicate additions and removal of missing references are errors.
Merge a generated single profile with --profile-yaml generated.yaml (a profile body or YAML containing profiles:). Supplied fields are applied; omitted fields such as port/custom fields remain. Combine with --add-profile to add one. Board switches replace the old board's platform while retaining other platforms and libraries. For the same platform, retain the existing pin/URL; resolve a new platform using catalog data or explicit version/URL. Switching away from an unversioned local core requires --pin-unversioned.
Structural edits reformat the targeted profile while retaining comments and unknown fields. Other profiles retain their original text. Anchored/aliased targets and flow-style profiles are refused for structural editing.
Inspect available core versions
npx arduino-sketch-tool platform-versions ./tests/example --profile s3_test
npx arduino-sketch-tool platform-versions ./tests/example --profile s3_test \
--index-source ./catalog/package_esp32_index.json --offline --json
npx arduino-sketch-tool platform-versions --platform esp32:esp32 \
--index-source ./catalog/package_esp32_index.json --offline --jsonRead the used core ID/source from the profile and list releases in its package index, without ordinary core installation. Source precedence is --index-source, YAML URL, then the URL in explicit --boards-db data; standard Arduino cores can use the official index. Specify unknown third-party sources explicitly. --offline requires a saved package index, which differs from board catalog JSON. Releases are filtered by both vendor and architecture.
To include URL additions/changes in ordinary updates, use update --update-index-urls. This supports URL-only changes when pins are already current and protects unversioned cores. Integrations can use the same plan API.
Catalogs and offline use
Defaults:
- board_details.json: board versions grouped by platform ID.
- library_index.json: library acquisition refreshes CLI indexes internally and reads the downloaded file, falling back to the official URL if unavailable. Legacy library catalog arrays remain supported as explicit inputs.
Local core installation is not required. Latest means latest in the supplied catalog, not a guarantee about every upstream release. Missing dependencies are reported as unknown. Every check/update loads catalogs afresh; there is no persistent cache. sources.retrievedAt records retrieval time, not catalog generation time.
npx arduino-sketch-tool check ./tests --recursive --offline \
--boards-db ./catalog/board_details.json \
--libraries-db ./catalog/libraries.json --json
npx arduino-sketch-tool update ./tests --recursive --platform esp32:esp32 \
--offline --boards-db ./catalog/board_details.jsonSources may be local JSON files or HTTP(S) URLs. --offline requires saved JSON for the selected dependency kinds. Platform-only operations load only board data, and library-only operations load only library data. The default request timeout is 15000 ms (--timeout). Catalog retrieval or validation failures prevent updates.
Editing behavior
- Automatic updates change outdated pinned versions only. Unpinned, unknown, incomparable, and ahead versions are retained.
- Transitive
dependency:entries are supported; localdir:entries are retained. - Dependency version edits retain board options, defaults, ports, comments, unknown fields, and unrelated settings are retained. Source ranges allow editing values without reserializing the document.
- Platform index URL differences are reported, and retained by default;
--update-index-urlsexplicitly enables additions/changes for pinned cores. - Changed files use UTF-8 without BOM and LF. Unchanged files are not written.
- Invalid YAML, duplicate keys, nonexistent default profiles and malformed dependency entries fail explicitly. Managed aliases and updates to anchored values or their parent collections are unsupported in this release.
- All files are parsed and edits prepared before any writes. Preparation errors block the whole batch.
- Each write checks original content and replaces the file using a temporary file in the same directory. The batch is not a cross-file transaction. I/O failures and any partial application are recorded per file.
Testing workflow
Index refresh is part of acquisition
Ordinary library check, update and search operations run arduino-cli update internally, then read the downloaded index. No preliminary CLI update or data-directory argument is required. --dry-run refreshes indexes but does not write YAML.
CLI refresh updates core and library indexes; it differs from upgrade, which replaces installed dependencies. Keep additional core sources in YAML. Board names/options continue to use the measured catalog.
Explicit set --version, core-only operations, offline/explicit catalog inputs, and builds that do not use this tool do not trigger this refresh. When CI restores stale caches, build preparation may still require arduino-cli update, with YAML sources passed using --additional-urls for additional cores. A fallback warning also means CLI indexes were not successfully refreshed: inspect CLI acquisition errors before building.
npx arduino-sketch-tool validate tests/example --profile s3_test
npx arduino-sketch-tool board tests/example --profile s3_test
npx arduino-sketch-tool update tests/example --profile s3_test --dry-run
npx arduino-sketch-tool update tests/example --profile s3_test
git diff -- tests
cd tests
uv run --env-file .env pytest --run-mode=buildUse pytest --clean when appropriate. Configuration editing, compilation and hardware behavior are separate checks. This tool does not compile, upload or operate test devices. Local dependencies remain pointed at development code. Separate ordinary pinned-build CI from latest-compatibility CI in a disposable checkout. The no-commit batch build recipe retains diffs and every build result.
JSON, exit codes and language
--json writes one JSON document to stdout. Reports contain schemaVersion, sources, warnings, summary, results, errors. Fatal errors return schemaVersion and errors. board inspection uses results[].boards, including configured/catalog versions, values/defaults, and unknown options. Board option edits use kind: "board" and full FQBN from/to. Changes contain profile, kind, name, index, from, to. summary.changedFiles counts files requiring changes; writtenFiles counts successful writes.
validate returns results[].diagnostics with code/severity/profile/kind/name/message; summary.diagnostics counts error/warning/info findings. results[].valid indicates whether there are errors.
platform-versions returns profile/platform/configuredVersion/source/versions/latestVersion in results[].versions. edit returns structural changes in results[].changes and resulting YAML in results[].content. URL plans use kind: "index-url".
Version statuses: ok, outdated, ahead, unknown, unpinned, incomparable, local. Write statuses: planned, written, unchanged, blocked, error. Machine codes and technical details are locale-independent.
| Code | Meaning |
|---:|---|
| 0 | Success; ordinary checks may still report outdated or unknown dependencies |
| 1 | Input, parsing, catalog or write failure; no matching targets |
| 2 | Outdated dependencies with check --fail-on-outdated, or warnings with validate --fail-on-warning |
| 3 | Invalid command or arguments |
Use check --fail-on-outdated --json for a CI update gate. Inspect JSON if unknown or unpinned dependencies should also fail your gate.
Human output/help detect Japanese or English from the environment. Override with --lang ja or --lang en. JSON has the same structure in both languages.
Find boards and libraries
npx arduino-sketch-tool boards esp32s3
npx arduino-sketch-tool boards --platform esp32:esp32 --limit 10
npx arduino-sketch-tool boards --fqbn esp32:esp32:esp32s3 --details
npx arduino-sketch-tool libraries EspUsbHost --detailsFor new configurations, search catalog board names, FQBNs, and platforms independently of installed cores. --details shows board option keys, choices, and defaults, or available library versions. Search supports Japanese/English output, JSON, and saved catalogs.
Create a new sketch.yaml
npx arduino-sketch-tool init ./tests/new_sketch \
--fqbn esp32:esp32:esp32s3 --profile s3_test \
--library EspUsbHost --local-library ../../../ --dry-runReview the generated YAML, then remove --dry-run to create it. Core and published library versions are pinned from the catalog, including the core index URL when available. Existing files are never overwritten. See the beginner guide.
Add repeatable overrides such as --board-option USBMode=default. Values are checked against catalog choices and incorporated into the FQBN.
For local core development, use init ./tests/host --fqbn lang-ship:host:host --profile host --local-core --offline --dry-run. This creates an unversioned platform without catalogs. Prepare the local hardware link and declare that intent after creation.
JavaScript API
import {
loadVersionCatalog, processSketchFiles,
validateSketchConfiguration, checkSketchVersions, createVersionUpdatePlan, applyVersionUpdates,
} from 'arduino-sketch-tool';
const catalog = await loadVersionCatalog();
const report = await processSketchFiles(['./tests'], {
command: 'update', recursive: true, dryRun: true,
platforms: ['esp32:esp32'], catalog,
});
// Pure text operations also work with unsaved editor documents.
const validation = validateSketchConfiguration(yamlText);
const checked = checkSketchVersions(yamlText, catalog);
const updates = createVersionUpdatePlan(checked);
const { content, changed } = applyVersionUpdates(yamlText, updates);Use createSetVersionPlan(text, { libraries: ['EspUsbHost'], version: '2.10.0' }) for explicit versions. API filters are profiles, platforms, libraries arrays. createVersionCatalog(boards, libraries) accepts downloaded JSON directly. CLI and scripts can use the same API; CommonJS can use dynamic import().
Inspect a profile with inspectSketchBoards(text, catalog, { profiles: ['s3_test'] }). Create option edits with createBoardOptionPlan(text, catalog, { profiles: ['s3_test'], boardOptions: ['USBMode=default'] }), then apply with applySketchUpdates(text, plan).
parseSketchYaml is a low-level API containing YAML nodes and source ranges. Use listSketchProfiles or reports for JSON serialization. Unsafe anchor/alias edits are rejected.
Development
For development, check out this repository and execute unpublished changes directly, for example with node bin/arduino-sketch-tool.js --help.
npm ci
npm run check
npm pack --dry-runTests use fixed catalogs, temporary directories and a local HTTP server; no external data or devices are required. They exercise partial edits, idempotence, conflicts, dependency formats, CLI JSON/exit codes and Japanese/English output.
Release
Use the same npm version lifecycle as EmbedAssetToolJs. Record paired (EN) / (JA) entries under ## Unreleased in CHANGELOG.md. Commit implementation/documentation first and run release commands from a clean working tree.
npm ci
npm login
# Patch release example; use minor / major or an explicit version as appropriate
npm version patch
npm publish --access public
git push --follow-tagsFor subsequent releases use npm version patch, minor, major, or an explicit version. preversion runs all checks, verifies pending entries, and rejects self-dependencies. version moves pending entries into the selected version section and stages the changelog. npm updates package.json/lockfile and creates a version commit and Git tag. prepublishOnly also runs all checks.
GitHub Actions CI runs checks; npm publication uses the commands above. Follow npm prompts for one-time passwords or browser authentication.
Use from VS Code
The related Arduino CLI Wrapper extension uses the same Arduino CLI and sketch.yaml with GUI controls and conveniences including compilation, upload, IntelliSense, and debugging. Project YAML is the configuration shared between CLI and extension use. The standalone tool works without the extension.
Library index sources
Library acquisition internally runs arduino-cli update, then reads library_index.json under the configured CLI data directory. Users do not need to invoke CLI first, discover that directory, or pass an index file.
npx arduino-sketch-tool libraries --details
npx arduino-sketch-tool check ./tests --recursive
npx arduino-sketch-tool update ./tests --recursive --dry-run
npx arduino-sketch-tool update ./tests --recursiveIf CLI discovery, update or local reading fails, the tool downloads the official index directly and records a warning. It never selects stale local data after a failed refresh. JSON reports identify the actual source.
Use --arduino-cli PATH and --cli-config-file FILE when the build uses a different executable or configuration. Each CLI command has a default 120-second timeout. --no-cli-update bypasses CLI and downloads the official data directly.
--libraries-db FILE|URL is an optional input for offline use or fixed snapshots. Explicit sources bypass CLI. --offline requires saved inputs for the selected dependency kinds and makes no network requests. Legacy libraries.json remains supported. Ordinary operations omit these options and acquire data automatically.
Official entries are aggregated by name with all available versions; uncomparable historical entries are skipped with warnings. Board names/options still use the measured catalog and may lag new core releases.
The JavaScript APIs loadLibraryCatalog() and loadVersionCatalog() also refresh and read internally by default. Configure execution with cliPath, cliArgs, cliTimeoutMs and useArduinoCli: false. Explicit files/URLs are loaded and normalized in a worker. createVersionCatalog(boards, officialIndexObject) normalizes data already in memory. catalog.libraryDetails preserves latest dependency/repository metadata.
