SKILL.md
Initialize BSP Customization Workspace
Overview
This skill bootstraps the source-side workspace that customize-* / build skills depend on: the LinuxforTegra overlay tracker (git repo for pristine + customization commits), the bspsources/ mono-tree (kernel, OOT, nvgpu, display, hwpm, hardware DTs), and a working NVIDIA Crosstool-NG cross-compile prefix. It owns only the source: block in the active profile and the on-disk source workspace under <source.rootpath> (default: <workspace>/Source).
Responsibilities:
- Optionally record a non-default
source.root_path. - Create or mount the
LinuxforTegraoverlay tracker. - Materialize
bsp_sourcesusing the precedence in the "Materialize the BSP-sources baseline" step. - Resolve and record
source.toolchain. - Clone extra user-defined repos from
source.repos:.
When to invoke
- The user asks to bootstrap, init, or sync the BSP customization
workspace.
- A downstream customization skill refused with "no workspace
tracker at <source.rootpath>/Linuxfor_Tegra/".
- After
jetson-init-image(Setup's next step on a fresh target).
Procedure
Quick-start prefill mapping
Follow the shared [quickstartprefill contract](../../context/bsp-customization-workflow.md#quickstartprefill-contract). This skill has source-specific mappings:
quickstartprefill.source.publicsourcesarchivemaps to the
Branch-A archive candidate.
quickstartprefill.source.reposmaps to proposedsource.repos:
entries; validate reserved keys and url: / archive: mutual exclusion before writing.
quickstartprefill.source.toolchainmay be a cross-compile prefix,
a gcc path, a containing bin/ directory, an x-tools.tbz2 archive path, or skip.
This skill remains the only owner of source.root_path, source.repos:, and source.toolchain profile writes.
Resolve the active target + paths
Resolve the active profile + workspace defaults per the contract in [../../context/target-platform-contract.md](../../context/target-platform-contract.md).
- Refuse if
<bspimage.rootpath>does not contain
LinuxforTegra/ (BSP not extracted — route to /jetson-init-image).
- If the profile has
source.root_path:, use it. Otherwise
<source.rootpath> defaults to <workspace>/Source; use that default silently and do not write source.rootpath: to the profile. Ask only for an explicit custom path, unrelated content at the default path, or an unwritable parent.
Read source.repos: (if present) into a map keyed by entry name, each carrying optional url, ref, subdir, path. Reserved keys: LinuxforTegra (overlay tracker), bsp_sources (kernel-source repo). Every other key is an extra user-defined repo.
(Optional) prompt for source.root_path override
Only when source.root_path is absent from the profile and one of the override conditions above applies:
source.root_path: default =<workspace>/Source. Press Enter to
accept, or enter an absolute path to override.
- On Enter — keep the default; do not touch the profile.
- On override path — validate the closest existing parent is
writable; refuse and re-prompt if not. Edit target-platform/<active>.yaml in place to add/update source.root_path:. Preserve all other blocks, comments, and quoting — use a round-tripping YAML loader (e.g. ruamel.yaml).
Fires at most once per profile. Otherwise create <workspace>/Source as needed and continue without prompting.
Materialize LinuxforTegra
Mount path is canonical: <source.rootpath>/Linuxfor_Tegra/.
Default (no source.repos.LinuxforTegra entry):
LFT="<source.root_path>/Linux_for_Tegra"
mkdir -p "$LFT"
[ -d "$LFT/.git" ] || git -C "$LFT" init
Empty tracker. Do not commit anything here — pristine imports happen file-by-file when customization skills run.
Override (url, ref, optional subdir):
# Clone the user's repo to a side location, then mount the
# expected tree (subdir or repo root) at the canonical path.
CLONE="<source.root_path>/.repos/Linux_for_Tegra"
git clone <url> -b <ref> "$CLONE"
ln -s "$CLONE/<subdir or .>" "<source.root_path>/Linux_for_Tegra"
If the mount already exists with valid git state, skip; refuse if it exists with unrelated content.
Materialize the BSP-sources baseline
Three branches, dispatched in precedence order against the profile entry source.repos.bsp_sources:
| Order | Profile state | Branch |
|---|---|---|
| 1 | url: set |
C. Customer git clone (explicit override always wins) |
| 2 | archive: set, OR entry absent AND <workspace>/Downloads/public_sources.tbz2 exists |
A. Local archive extraction (default) |
| 3 | Entry absent AND no local archive | B. source_sync.sh (fallback) |
url: and archive: are mutually exclusive — refuse if both are set in the same entry.
Branch A is the preferred default because it sidesteps NVIDIA git egress entirely (the most common Setup failure mode). Branch B exists for fresh workspaces with no pre-downloaded tarball. Branch C is for customer forks of the whole BSP layout.
Branch A — Local archive extraction (default)
Default branch: extract a pre-downloaded publicsources.tbz2 into <source.rootpath>/bsp_sources/ as a single mono-repo (git init + pristine commit). See [references/branch-a-extraction.md](references/branch-a-extraction.md) for the full archive shape, path-resolution rules, and the extraction script (including the Tegra OOT Makefile force-replace workaround for R36.x).
Branches B and C may produce per-component repos instead; downstream build logic still walks the canonical sub-paths under <source.rootpath>/bspsources/.
Branch B — source_sync.sh (fallback)
Runs only when no local archive is found and no url: is set. Create the bspsources/ mount directory under <source.rootpath> and run source_sync.sh from the extracted BSP with two flags:
mkdir -p "<source.root_path>/bsp_sources"
bash "<bsp_image.root_path>/Linux_for_Tegra/source/source_sync.sh" \
-d "<source.root_path>/bsp_sources" \
-t "jetson_<major.minor>"
-d <source.rootpath>/bspsources— write clones into the
bsp_sources/ subdir of the workspace, so the on-disk folder matches the schema key. Without -d, the script writes under its own directory (the BSP itself) — wrong for the overlay model.
-t jetson_<major.minor>— pin the tag to the BSP release line.
Derive from bspimage.version by truncating to the first two dotted components: "38.4.0" → jetson38.4. Tag-format fallback: if rejected, try jetson<bspimage.version> (older L4T sometimes uses the full form). If that also fails, surface the error and stop — never fall back to "latest" silently.
Refuse if sourcesync.sh does not exist: re-run /jetson-init-image to repopulate Linuxfor_Tegra/source/.
sourcesync.sh exits 0 even when every clone failed — verify by counting Failed to clone lines in its output and refuse if non-zero. The most likely cause of universal failure is blocked git egress to gitlab.com/nvidia/nv-tegra / nv-tegra.nvidia.com; surface that explicitly and route the user to download publicsources.tbz2 via /quick-start for Branch A.
Branch C — Customer git clone (url: override)
Triggered by an explicit url: field. Clone the customer repo once and expose its canonical kernel-side sub-paths under <source.rootpath>/bspsources/. The canonical sub-path list is read from sourcesync.sh's SOURCEINFO at runtime — do not hard-code it, so future NVIDIA additions/removals propagate automatically:
# Parse canonical sub-paths from source_sync.sh's SOURCE_INFO
# (only the kernel-side entries marked `k:` in the second field).
SUBPATHS=$(grep -oP '^\s*k:[^:]+:' \
"<bsp_image.root_path>/Linux_for_Tegra/source/source_sync.sh" \
| sed 's/^\s*k://; s/:$//')
mkdir -p "<source.root_path>/bsp_sources"
CLONE="<source.root_path>/.repos/bsp_sources"
git clone <url> -b <ref> "$CLONE"
ROOT="$CLONE/<subdir or .>"
for SUB in $SUBPATHS; do
[ -d "$ROOT/$SUB" ] && \
ln -s "$ROOT/$SUB" "<source.root_path>/bsp_sources/$SUB"
done
Report any canonical sub-path expected for the active chip family but not present inside the customer repo (warn, don't refuse — customer may legitimately not have all repos).
Resolve cross-compile toolchain
The downstream jetson-build-source reads source.toolchain from this profile and exports it as CROSS_COMPILE. This step must land a valid prefix before init-source returns, or any subsequent kernel / OOT / DT build will refuse.
NVIDIA's official Crosstool-NG Toolchain gcc is the canonical toolchain for L4T. jetson-download-bsp owns any network fetch of x-tools.tbz2; this skill only discovers, extracts, validates, and writes the resolved prefix. Resolution follows a three-step ladder:
Auto-discover
Look under <workspace>/toolchain/x-tools/ for the Crosstool-NG layout — typically one of:
<workspace>/toolchain/x-tools/aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc
<workspace>/toolchain/x-tools/aarch64-buildroot-linux-gnu/bin/aarch64-buildroot-linux-gnu-gcc
Glob: <workspace>/toolchain/x-tools/aarch64--linux-gnu/bin/aarch64--linux-gnu-gcc. If exactly one match, bind:
TC_PREFIX=<absolute path to that .../bin/<triple>-> # trailing dash mandatory
Skip to "Write to profile" below. If zero matches, fall through to "Auto-extract from Downloads/x-tools.tbz2" below. If multiple, refuse with the list and ask the user to remove the unwanted ones (we never pick one silently among ambiguous installs — different Crosstool-NG flavors produce ABI- incompatible binaries).
Auto-extract from Downloads/x-tools.tbz2
If <workspace>/Downloads/x-tools.tbz2 exists (mirrors the public_sources.tbz2 Branch-A pattern in the "Materialize the BSP-sources baseline" step — air-gapped / no-egress users drop archives there):
file -b "<workspace>/Downloads/x-tools.tbz2" | grep -q "bzip2 compressed" || \
refuse "<workspace>/Downloads/x-tools.tbz2 is not a bzip2 tarball"
mkdir -p "<workspace>/toolchain"
tar xjf "<workspace>/Downloads/x-tools.tbz2" -C "<workspace>/toolchain"
Then re-run the "Auto-discover" pass above. Refuse if extraction succeeds but no x-tools/aarch64-*-linux-gnu/bin/ is produced (archive content doesn't match the Crosstool-NG layout).
Prompt the user
If both Auto-discover and Auto-extract came up empty, ask:
No Crosstool-NG toolchain found at
<workspace>/toolchain/or in<workspace>/Downloads/x-tools.tbz2.
Reply with one of:
- absolute path to youraarch64-*-linux-gnu-gccbinary or its
containingbin/directory,
-cancelto abort.
To fetch the archive instead, cancel this run, run/jetson-download-bsp, then re-run/jetson-init-source.
For a path reply, validate via [ -f "${TC_PREFIX}gcc" ]. Refuse and re-prompt on failure.
Write to profile
Once $TCPREFIX resolves and ${TCPREFIX}gcc exists, write it into the active profile using a round-tripping YAML loader:
source:
toolchain: <TC_PREFIX> # absolute, with trailing dash
If source: is otherwise empty (no root_path override, no repos: entries), the source: block is now non-empty and stays in the profile. Future jetson-init-source runs skip the "Resolve cross-compile toolchain" step if source.toolchain is already set and points at a working gcc.
Clone extra user-defined repos
For each entry under source.repos: whose name is not LinuxforTegra or bsp_sources:
MOUNT="<source.root_path>/<entry.path or entry.name>"
if [ -n "<entry.subdir>" ]; then
CLONE="<source.root_path>/.repos/<entry.name>"
git clone <entry.url> -b <entry.ref> "$CLONE"
ln -s "$CLONE/<entry.subdir>" "$MOUNT"
else
git clone <entry.url> -b <entry.ref> "$MOUNT"
fi
Refuse if a mount path already exists with unrelated content.
Summary
Print:
- Resolved
<workspace>,<bspimage.rootpath>, and
<source.root_path>.
- For each materialized component: created, reused, skipped, or refused.
- For
bsp_sources: branch selected plus key evidence (archive path,
source_sync.sh failure count, or clone URL/ref).
- Toolchain prefix, resolution source, and
${TC_PREFIX}gcc --version
first line.
- Reminder that customize-* skills stage future BSP edits in
<source.rootpath>/LinuxforTegra/; promote is what later copies committed overlay changes into bspimage.
If a downstream skill triggered this run, tell the user to re-issue their original request.
Gotchas
LinuxforTegraandbsp_sourcesmount paths are canonical.
path: applies only to extra user-defined repos.
- The default
LinuxforTegratracker is intentionally empty; do not
pre-populate it.
bsp_sourcesprecedence isurl:→archive:→ auto-discovered
Downloads/publicsources.tbz2 → sourcesync.sh. url: and archive: are mutually exclusive.
- Branch A auto-discovery does not prompt and is not written back to the
profile. Persist it only with source.repos.bsp_sources.archive:.
- Branch A
$DEST/Makefilecollision. Inner tarballs in
publicsources.tbz2 ship two files named Makefile: the Tegra orchestrator (kernelootmodulessrc.tbz2) and the dGPU/OpenRM proprietary Makefile (nvidiakerneldisplaydriversourcewithout rootdir.tbz2). Alphabetical extraction order lets the dGPU one win on R36.x; downstream arm64 cross-builds then fail with '-mlittle-endian' unrecognized. Step 3a force-replaces from <bspimage>/LinuxforTegra/source/Makefile when the Tegra modules: hwpm nvidia-oot nvgpu nvidia-display signature is missing. R38+ extractions already match; the check is a no-op there.
- Branch C customer repos must expose the canonical
source_sync.sh
sub-path layout, optionally shifted by subdir:.
- Derive the
sourcesync.shtag frombspimage.versionas
jetson_<major.minor> first; never fall back to an unpinned latest.
jetson-download-bspowns network downloads ofpublic_sources.tbz2
and x-tools.tbz2; this skill consumes local archives only.
source.toolchainmust be an NVIDIA Crosstool-NG prefix with trailing
dash and a working ${prefix}gcc. Never silently use $PATH.
- Use a round-tripping YAML writer for profile edits.
Prerequisites
- Active target profile resolved per
../../context/target-platform-contract.md.
/jetson-init-imagealready run sobsp_image.versionis recorded
(Branch B source_sync.sh tag derives from it).
- For Branch A: a local
public_sources.tbz2(and optionally
x-tools.tbz2) staged under Downloads/.
- For Branch C: customer Git access to the override repo URL.
Limitations
- Owns only the
source:block; never editsbsp_image,
referencedevkit, customcarrier, or documents.
- Network egress only for Branch B (
source_sync.sh) and Branch C
(customer Git clone); Branch A is fully offline.
- Refuses to silently substitute a system toolchain — the NVIDIA
Crosstool-NG prefix must be present or extractable.
Troubleshooting
${toolchain}gccnot found — re-stagex-tools.tbz2under
Downloads/ and rerun, or pass a verified absolute prefix path.
sourcesync.shcannot resolvejetson<major.minor>tag — the
recorded bsp_image.version is wrong; re-run /jetson-init-image to refresh it.
LinuxforTegra/.gitshows uncommitted hand-edits — abort and
ask the user to commit or stash; this skill expects a clean tracker.
- Branch C clone missing canonical sub-paths — repo layout doesn't
match source_sync.sh; set subdir: to the right sub-root or fall back to multi-repo overrides under source.repos:.
References
- [
../../references/platformtemplate.yaml](../../references/platformtemplate.yaml) —source:schema, including therepos:map. - [
../../context/target-platform-contract.md](../../context/target-platform-contract.md) — target-platform contract. - [
../../context/bsp-customization-workflow.md](../../context/bsp-customization-workflow.md#workflow-invariants) — Workspace edit protocol. - [
../jetson-init-target/SKILL.md](../jetson-init-target/SKILL.md) — authors the profile this skill consumes. - [
../jetson-init-image/SKILL.md](../jetson-init-image/SKILL.md) — extracts the BSP and back-fillsbsp_image.version; run before this skill.