feat(skills): CLI domain skills — forge, atlassian, aws, gcloud, azure, devops, edge, iot, embedded-linux

This commit is contained in:
fabiorafaelcoutada 2026-07-12 20:51:27 +01:00
parent b6f0baac7d
commit 21676efd68
9 changed files with 659 additions and 0 deletions

View file

@ -0,0 +1,58 @@
---
name: cli-atlassian
description: Atlassian operations via `acli` — Jira issues (create, transition, JQL search) and Confluence pages (read/write). Use when the task involves Jira tickets, sprint/backlog queries, or Confluence documentation.
---
# cli-atlassian — Jira & Confluence (acli)
## When to use
Working with Atlassian Cloud: creating/moving Jira issues, running JQL searches,
reading or updating Confluence pages.
## Prerequisites
- install + auth: see `docs/guides/cli/atlassian.md`
- `acli jira auth status` — OAuth/API-token login must be active
- API tokens stored in Vaultwarden
- Note: self-hosted-first policy does not cover Atlassian (no local emulator); this is a
third-party SaaS — only use on workspaces the user explicitly points at.
## Common workflows
1. **Create an issue**
```bash
acli jira workitem create --project PROJ --type "Task" \
--summary "Title" --description "Details"
```
2. **Transition an issue**
```bash
acli jira workitem transition --key PROJ-123 --status "In Progress"
acli jira workitem assign --key PROJ-123 --assignee "@me"
```
3. **Search with JQL**
```bash
acli jira workitem search --jql "project = PROJ AND status = 'To Do' ORDER BY updated DESC" --limit 20
acli jira workitem view PROJ-123
```
4. **Confluence — read a page**
```bash
acli confluence page view --page-id 12345678
acli confluence page search --query "architecture" --space DOCS
```
5. **Confluence — write/update a page**
```bash
acli confluence page create --space DOCS --title "Runbook" --body-file runbook.md
acli confluence page update --page-id 12345678 --body-file runbook.md
```
## Pitfalls
- JQL is case-sensitive for operators (`AND`, `ORDER BY`); quote status names with spaces.
- Page updates create new versions — confirm before overwriting collaboratively-edited pages.
- `acli` subcommand names changed across versions (`workitem` vs `issue`); run `acli jira --help` if a command is unknown.
- Output defaults to tables; add `--json` when piping to scripts.

View file

@ -0,0 +1,79 @@
---
name: cli-aws
description: AWS CLI operations — S3, IAM, SQS, Lambda, IoT Core. Use for cloud resource management, and ALWAYS default to the local emulators (LocalStack/MinIO) for dev work; touch production AWS only when the user explicitly asks.
---
# cli-aws — AWS Operations (aws)
## When to use
S3 object ops, IAM inspection, SQS queues, Lambda invocations, IoT Core thing
management.
**Policy — dev first.** Development and testing use the self-hosted emulators:
- LocalStack (AWS APIs): `http://192.168.0.40:4566` — profile `localstack`
- MinIO (S3): `http://192.168.0.40:9000`
Production AWS only when the user explicitly requests it.
## Prerequisites
- install + auth: see `docs/guides/cli/aws.md`
- Emulators up: check `.aurelio/connectors/registry.yaml` for LocalStack/MinIO status
- LocalStack profile example (`~/.aws/config`):
```ini
[profile localstack]
region = us-east-1
output = json
aws_access_key_id = test
aws_secret_access_key = test
```
- Prod credentials live in Vaultwarden, not in shell history
## Common workflows
1. **S3 sync against MinIO**
```bash
aws --endpoint-url http://192.168.0.40:9000 s3 sync ./dist s3://my-bucket/dist
aws --endpoint-url http://192.168.0.40:9000 s3 ls
```
2. **S3 ops against LocalStack**
```bash
aws --profile localstack --endpoint-url http://192.168.0.40:4566 s3 mb s3://test-bucket
aws --profile localstack --endpoint-url http://192.168.0.40:4566 s3 cp file.bin s3://test-bucket/
```
3. **SQS queues**
```bash
aws --profile localstack --endpoint-url http://192.168.0.40:4566 sqs list-queues
aws --profile localstack --endpoint-url http://192.168.0.40:4566 sqs send-message \
--queue-url <url> --message-body '{"hello":"world"}'
```
4. **IoT Core — list things** (also available on LocalStack)
```bash
aws iot list-things --max-results 50
aws iot describe-thing --thing-name my-device
aws iot list-thing-principals --thing-name my-device
```
5. **Lambda invoke (LocalStack)**
```bash
aws --profile localstack --endpoint-url http://192.168.0.40:4566 lambda invoke \
--function-name my-fn --payload '{}' out.json
```
## Self-hosted endpoints
| Service | URL | Purpose |
|---------|-----|---------|
| LocalStack | http://192.168.0.40:4566 | AWS API emulation |
| MinIO | http://192.168.0.40:9000 | S3-compatible storage |
## Pitfalls
- Always pass `--endpoint-url` (and `--profile localstack`) for emulators — forgetting it silently hits real AWS and can cost money.
- LocalStack endpoint is per-service-agnostic (one URL for all); MinIO is S3-only.
- Emulator credentials are `test`/`test`; never reuse them for real AWS.
- IoT Core thing/cert data in LocalStack is ephemeral — re-provision after container restarts.

View file

@ -0,0 +1,68 @@
---
name: cli-azure
description: Azure operations via `az` — storage accounts, resource groups, blobs/queues. Use for Azure resource management; prefer the Azurite emulator (http://192.168.0.40:10000) for development before touching real Azure subscriptions.
---
# cli-azure — Azure Operations (az)
## When to use
Managing Azure resources: resource groups, storage accounts, blob/queue/table ops.
**Policy — dev first.** Use Azurite (Azure Storage emulator) at
`http://192.168.0.40:10000` for development. Real Azure subscriptions only when the
user explicitly asks.
## Prerequisites
- install + auth: see `docs/guides/cli/azure.md`
- `az login` for real subscriptions; `az account set --subscription <id>`
- Azurite running (check `.aurelio/connectors/registry.yaml` for status)
- Secrets (connection strings, keys) in Vaultwarden
## Common workflows
1. **Resource groups**
```bash
az group list -o table
az group create --name rg-dev --location westeurope
az resource list --resource-group rg-dev -o table
```
2. **Storage account + containers (real Azure)**
```bash
az storage account list -o table
az storage container create --name mycontainer --account-name myaccount
az storage blob upload --account-name myaccount --container-name mycontainer \
--name file.bin --file ./file.bin
```
3. **Dev with Azurite**
```bash
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://192.168.0.40:10000/devstoreaccount1;QueueEndpoint=http://192.168.0.40:10001/devstoreaccount1;TableEndpoint=http://192.168.0.40:10002/devstoreaccount1;"
az storage container create --name devcontainer --connection-string "$AZURE_STORAGE_CONNECTION_STRING"
az storage blob upload --container-name devcontainer --name test.bin --file ./test.bin \
--connection-string "$AZURE_STORAGE_CONNECTION_STRING"
```
4. **Queues**
```bash
az storage queue create --name jobs --connection-string "$AZURE_STORAGE_CONNECTION_STRING"
az storage message put --queue-name jobs --content "hello" \
--connection-string "$AZURE_STORAGE_CONNECTION_STRING"
```
## Self-hosted endpoints
| Service | URL | Port |
|---------|-----|------|
| Azurite Blob | http://192.168.0.40:10000 | 10000 |
| Azurite Queue | http://192.168.0.40:10001 | 10001 |
| Azurite Table | http://192.168.0.40:10002 | 10002 |
## Pitfalls
- `az storage` commands resolve auth from `--connection-string`, `--account-key`, or env vars in that precedence — leftover env vars silently override your flags.
- Azurite account name is always `devstoreaccount1` with the well-known dev key — never use those values on real Azure.
- Azurite emulates Storage only; ARM operations (groups, VMs) have no local emulator.
- `az` writes warnings to stderr — use `-o json` + `jq`, and `--only-show-errors` in scripts.

View file

@ -0,0 +1,97 @@
---
name: cli-devops
description: Infrastructure operations — kubectl, helm, OpenTofu/Terraform, Ansible, docker compose. Use for Kubernetes deploys, infrastructure-as-code, and configuration management of the Proxmox fleet (asus, gigabyte, lattepanda).
---
# cli-devops — k8s, IaC & Fleet Configuration
## When to use
Deploying to Kubernetes, applying Helm charts, provisioning infrastructure with IaC,
configuring the Proxmox nodes, or running multi-service stacks with docker compose.
**Policy:** prefer **OpenTofu** over Terraform (open-source fork, drop-in compatible).
Self-hosted state backend on MinIO; secrets in Vaultwarden.
## Prerequisites
- install: see `docs/guides/cli/kubectl.md`, `docs/guides/cli/helm.md`,
`docs/guides/cli/opentofu.md`, `docs/guides/cli/ansible.md`, `docs/guides/cli/docker-compose.md`
- `kubectl config current-context` — verify you're on the right cluster before apply/delete
- SSH access to the fleet nodes for Ansible
## Common workflows
1. **kubectl basics**
```bash
kubectl get pods -A
kubectl apply -f manifests/
kubectl rollout status deployment/my-app -n my-ns
kubectl logs -f deploy/my-app -n my-ns
```
2. **helm**
```bash
helm repo add bitnami https://charts.bitnami.com/bitnami && helm repo update
helm upgrade --install my-release bitnami/postgresql -n db --create-namespace \
--values values.yaml
helm rollback my-release 1 -n db
```
3. **OpenTofu with MinIO S3 backend** (`backend.tf`):
```hcl
terraform {
backend "s3" {
bucket = "tfstate"
key = "fleet/terraform.tfstate"
endpoint = "http://192.168.0.40:9000"
access_key = "minioadmin" # from Vaultwarden
secret_key = "..."
region = "us-east-1"
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
force_path_style = true
}
}
```
```bash
tofu init && tofu plan && tofu apply
```
4. **Ansible against the Proxmox fleet** — sample inventory (`inventory.ini`):
```ini
[proxmox]
asus ansible_host=192.168.0.38
gigabyte ansible_host=192.168.0.104
lattepanda ansible_host=192.168.0.40
[proxmox:vars]
ansible_user=root
```
```bash
ansible -i inventory.ini proxmox -m ping
ansible-playbook -i inventory.ini site.yml --check --diff
```
5. **docker compose**
```bash
docker compose up -d
docker compose logs -f --tail 50
docker compose down
```
## Self-hosted endpoints
| Service | URL | Purpose |
|---------|-----|---------|
| MinIO | http://192.168.0.40:9000 | OpenTofu state backend (S3) |
| Forgejo | https://code.portugalfuturista.org | IaC repo hosting |
| Vaultwarden | — | backend creds, kubeconfigs |
## Pitfalls
- `tofu` reads Terraform `backend "s3"` blocks as-is, but MinIO needs `force_path_style` + the `skip_*` flags or init fails with region/endpoint errors.
- Never commit `terraform.tfstate` or secrets; state lives only in MinIO.
- `kubectl` context is global and sticky — a wrong context applies manifests to the wrong cluster. Always check first.
- Run Ansible with `--check --diff` before real runs against the fleet; `gigabyte` hosts the Docker media stack — don't restart it casually.

View file

@ -0,0 +1,80 @@
---
name: cli-edge
description: Edge and serverless operations — cloudflared tunnels, Cloudflare Workers (wrangler), Vercel, Netlify, Fly.io (flyctl), DigitalOcean (doctl). Use for tunnel management, edge deploys, and serverless hosting of *.portugalfuturista.org services.
---
# cli-edge — Tunnels, Edge Deploys & Serverless
## When to use
Managing Cloudflare tunnels that expose `*.portugalfuturista.org`, deploying Workers,
or shipping apps to Vercel/Netlify/Fly.io/DigitalOcean.
**Local context:** Cloudflare tunnel `pf-tunnel-v2` runs on the **asus** Proxmox host
(192.168.0.38), config at `/etc/cloudflared/config-v2.yml`. All public
`*.portugalfuturista.org` domains route through it.
## Prerequisites
- install: see `docs/guides/cli/cloudflared.md`, `docs/guides/cli/wrangler.md`,
`docs/guides/cli/vercel.md`, `docs/guides/cli/netlify.md`, `docs/guides/cli/flyctl.md`,
`docs/guides/cli/doctl.md`
- API tokens in Vaultwarden; `cloudflared` credentials JSON lives on asus
- SSH to asus for tunnel config changes
## Common workflows
1. **Inspect/manage the pf-tunnel-v2 tunnel**
```bash
cloudflared tunnel list
cloudflared tunnel info pf-tunnel-v2
cloudflared tunnel route dns pf-tunnel-v2 app.portugalfuturista.org
```
Ingress rules are edited in `/etc/cloudflared/config-v2.yml` on asus, then:
```bash
ssh root@192.168.0.38 'systemctl restart cloudflared'
```
2. **Cloudflare Workers**
```bash
wrangler login
wrangler dev # local dev server
wrangler deploy
wrangler tail # live logs
```
3. **Vercel / Netlify**
```bash
vercel --prod # or: vercel deploy --prod
netlify deploy --prod --dir=dist
```
4. **Fly.io**
```bash
flyctl apps list
flyctl deploy
flyctl logs
flyctl ssh console
```
5. **DigitalOcean**
```bash
doctl account get
doctl compute droplet list
doctl apps list
```
## Self-hosted endpoints
| Service | Location |
|---------|----------|
| pf-tunnel-v2 (cloudflared) | asus 192.168.0.38, `/etc/cloudflared/config-v2.yml` |
| Public domains | `*.portugalfuturista.org` via the tunnel |
| Vaultwarden | tokens for all edge providers |
## Pitfalls
- Tunnel ingress changes require editing the config file **and** a service restart on asus — `cloudflared tunnel` CLI commands alone don't hot-reload routes.
- DNS routes (`tunnel route dns`) create CNAMEs; conflicting existing records must be removed first.
- `wrangler deploy` publishes to production immediately — use `wrangler dev` / preview environments first.
- These are third-party clouds (exception to self-hosted-first): prefer the tunnel + local CTs when a service can run in-house; use edge providers only for public-facing/serverless needs.

View file

@ -0,0 +1,74 @@
---
name: cli-forge
description: Git hosting operations — repos, pull requests, issues, releases, CI runs — using `tea` (Forgejo/Gitea) and `gh` (GitHub). Use when you need to create or clone repos, open/review/merge PRs, manage issues or releases, inspect CI logs, or mirror a GitHub repo into Forgejo.
---
# cli-forge — Git Forge Operations (tea + gh)
## When to use
Any git hosting operation: repository CRUD, PR/issue/release workflows, checking CI run
status and logs, mirroring upstreams.
**Policy — Forgejo first.** The default forge is the self-hosted Forgejo at
`https://code.portugalfuturista.org` (LAN: `http://192.168.0.9:3001`). Use `tea` for all
day-to-day work. Use `gh` only for public GitHub mirrors, upstream contribution, or
fetching from third-party GitHub repos.
## Prerequisites
- install + auth: see `docs/guides/cli/forgejo.md` and `docs/guides/cli/gh.md`
- `tea` login configured: `tea login add --name pf --url https://code.portugalfuturista.org --token <token>`
- `gh auth login` for GitHub-only operations
- Tokens live in Vaultwarden — never hardcode them
## Common workflows
1. **Create a repo on Forgejo**
```bash
tea repo create --name my-repo --description "..." --private
git remote add origin ssh://git@code.portugalfuturista.org:2222/portugalfuturista/my-repo.git
```
2. **Open a PR (Forgejo)**
```bash
git push origin feature-branch
tea pr create --title "..." --body "..." --base main
tea pr list; tea pr review 12 approve
```
3. **Issues**
```bash
tea issue create --title "..." --body "..."
tea issue list --state open
```
4. **Review CI logs** (GitHub Actions mirrors / upstreams)
```bash
gh run list --repo owner/repo --limit 5
gh run view <run-id> --log-failed
gh pr checks 42
```
5. **Mirror a GitHub repo into Forgejo**
```bash
git clone --mirror https://github.com/owner/repo.git
cd repo.git && git remote set-url origin ssh://git@code.portugalfuturista.org:2222/portugalfuturista/repo.git
git push --mirror
```
(Or use Forgejo's built-in "New Migration" / push-mirror in repo settings.)
## Self-hosted endpoints
| Service | URL |
|---------|-----|
| Forgejo (HTTPS) | https://code.portugalfuturista.org |
| Forgejo (LAN) | http://192.168.0.9:3001 |
| Vaultwarden (tokens) | see `docs/vaultwarden-setup.md` |
## Pitfalls
- `tea` operates on the repo's remote — run commands inside a clone, or pass `--repo`.
- LAN and public URL both work, but SSH remote host/port differs from HTTPS — check the clone URL Forgejo shows.
- `gh` defaults to the origin remote's owner/repo; pass `--repo` explicitly when working with mirrors.
- Don't push GitHub-only workflows (`.github/workflows`) assumptions onto Forgejo — Forgejo uses `.forgejo/workflows` (act runner syntax is similar but not identical).

View file

@ -0,0 +1,68 @@
---
name: cli-gcloud
description: Google Cloud operations via `gcloud` — GCS, IAM, Cloud Run, Pub/Sub. Use for GCP resource management; prefer local emulators (firebase emulators, fake-gcs-server) for development before touching real GCP projects.
---
# cli-gcloud — GCP Operations (gcloud)
## When to use
Managing GCP resources: Cloud Storage objects, IAM bindings, Cloud Run services,
Pub/Sub topics/subscriptions.
**Policy — dev first.** Use emulators for development (Firebase emulators for
Auth/Firestore/Functions/Pub/Sub, fake-gcs-server for GCS). Real GCP projects only when
the user explicitly asks.
## Prerequisites
- install + auth: see `docs/guides/cli/gcloud.md`
- `gcloud auth login` and `gcloud config set project <project-id>`
- Service account keys stored in Vaultwarden (`GOOGLE_APPLICATION_CREDENTIALS`)
## Common workflows
1. **GCS objects**
```bash
gcloud storage ls gs://my-bucket/
gcloud storage cp ./file.bin gs://my-bucket/path/
gcloud storage rsync -r ./dist gs://my-bucket/dist
```
2. **IAM**
```bash
gcloud projects get-iam-policy my-project
gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:sa@my-project.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"
```
3. **Cloud Run**
```bash
gcloud run services list
gcloud run deploy my-service --image gcr.io/my-project/img:tag \
--region europe-west1 --allow-unauthenticated
gcloud run services logs read my-service --region europe-west1 --limit 50
```
4. **Pub/Sub**
```bash
gcloud pubsub topics list
gcloud pubsub topics create my-topic
gcloud pubsub subscriptions create my-sub --topic my-topic
gcloud pubsub topics publish my-topic --message "hello"
```
5. **Dev with emulators**
```bash
firebase emulators:start # Firestore/Auth/Functions/PubSub local suite
# fake-gcs-server as a GCS stand-in:
STORAGE_EMULATOR_HOST=http://localhost:4443 gcloud storage ls gs://dev-bucket/
```
## Pitfalls
- `gcloud config set project` is sticky — always verify with `gcloud config list` before mutations.
- Emulator env vars (`STORAGE_EMULATOR_HOST`, `PUBSUB_EMULATOR_HOST`) only affect client libs and some gcloud commands; unset them before real-GCP work.
- IAM changes take a few seconds to propagate; retry on transient 403s.
- Cloud Run deploys are regional — always pass `--region` explicitly.

View file

@ -0,0 +1,60 @@
---
name: cli-iot
description: IoT device workflows — MQTT debugging with mosquitto-clients, ESP32/ESP8266 flashing with esptool, Arduino/PlatformIO builds and serial monitoring. Use for MQTT topic inspection, firmware flashing, and embedded build/upload/monitor cycles.
---
# cli-iot — MQTT, ESP32 & Firmware Tooling
## When to use
Debugging MQTT traffic, flashing ESP32/Arduino firmware, building embedded projects,
and monitoring serial output from devices.
## Prerequisites
- install: see `docs/guides/cli/mosquitto.md`, `docs/guides/cli/esptool.md`,
`docs/guides/cli/arduino-cli.md`, `docs/guides/cli/platformio.md`
- Device connected over USB (`ls /dev/ttyUSB* /dev/ttyACM*`); user in `dialout` group
- MQTT broker address — check `.aurelio/connectors/registry.yaml` for the active broker
## Common workflows
1. **MQTT debugging**
```bash
# subscribe to everything (verbose)
mosquitto_sub -h 192.168.0.40 -t '#' -v
# one topic, with timestamps
mosquitto_sub -h 192.168.0.40 -t 'home/+/temperature' -T 'home/#' -v
# publish a test message
mosquitto_pub -h 192.168.0.40 -t 'test/ping' -m 'hello'
```
2. **esptool — flash an ESP32**
```bash
esptool.py --chip esp32 --port /dev/ttyUSB0 chip_id
esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 erase_flash
esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 firmware.bin
```
3. **arduino-cli**
```bash
arduino-cli board list
arduino-cli compile --fqbn esp32:esp32:esp32 sketch/
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32 sketch/
arduino-cli monitor -p /dev/ttyUSB0 -c baudrate=115200
```
4. **PlatformIO (preferred for multi-env projects)**
```bash
pio run # build all envs in platformio.ini
pio run -e esp32dev -t upload
pio device monitor -b 115200
pio device list
```
## Pitfalls
- Only one process can hold the serial port — close `pio device monitor`/`picocom` before flashing, or uploads fail with "port busy".
- Some ESP32 boards need the BOOT button held (or auto-reset circuitry) to enter download mode; if `chip_id` fails, retry with the button held.
- Wrong flash offset (`0x1000` vs `0x0`) bricks the boot flow on ESP32 vs ESP8266 — check the chip and the build's partition layout.
- `mosquitto_sub -t '#'` on a busy broker floods the terminal — narrow with topic filters and add `-C <n>` to exit after N messages.

View file

@ -0,0 +1,75 @@
---
name: embedded-linux
description: Embedded Linux engineering — Yocto/kas, Buildroot, U-Boot tooling, ARM cross-toolchains, Zephyr/west. Use for custom Linux image builds, bootloader work, and cross-compilation; heavy builds must run in crops/poky containers, never bare-metal on the laptop without asking.
---
# embedded-linux — Yocto, Buildroot, U-Boot & Cross-Compilation
## When to use
Building custom Linux images, working on bootloaders, cross-compiling for ARM targets,
or developing Zephyr RTOS firmware.
**Policy — heavy builds in containers.** Yocto builds need tens of GB of disk, many GB
of RAM, and hours of CPU. Run them inside the official `crops/poky` container (or a
dedicated build CT), **never** bare-metal on the laptop without asking the user first.
Warn about disk/RAM requirements before starting any full image build.
## Prerequisites
- install: see `docs/guides/cli/yocto.md`, `docs/guides/cli/buildroot.md`,
`docs/guides/cli/uboot-tools.md`, `docs/guides/cli/cross-toolchains.md`,
`docs/guides/cli/zephyr.md`
- Docker available for `crops/poky`; ≥ 100 GB free disk and ≥ 16 GB RAM recommended for Yocto
- Cross-toolchains (e.g. `gcc-arm-none-eabi`, `aarch64-linux-gnu-gcc`) installed or container-provided
## Common workflows
1. **Yocto via kas + crops/poky container**
```bash
# kas config pins layers/branches; run everything inside the container
docker run --rm -it -v "$PWD":/workdir crops/poky:ubuntu-22.04 \
--workdir=/workdir kas build project.yml
# or open an interactive shell and source the env manually:
docker run --rm -it -v "$PWD":/workdir crops/poky:ubuntu-22.04 --workdir=/workdir
# inside: source oe-init-build-env && bitbake core-image-minimal
```
2. **Buildroot (lighter alternative)**
```bash
make list-defconfigs
make raspberrypi4_64_defconfig
make menuconfig # optional customization
make -j$(nproc)
# images land in output/images/
```
3. **U-Boot tooling**
```bash
mkimage -l u-boot.imx # inspect an image header
mkimage -A arm -T script -C none -d boot.cmd boot.scr
fw_printenv # read U-Boot env (needs /etc/fw_env.config)
```
4. **Cross-compilation (bare-metal / kernel)**
```bash
aarch64-linux-gnu-gcc -o app app.c
arm-none-eabi-gcc -mcpu=cortex-m4 -o firmware.elf main.c
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) # kernel
```
5. **Zephyr with west**
```bash
west init -m https://github.com/zephyrproject-rtos/zephyr zephyrproject && cd zephyrproject
west update && west zephyr-export
west build -b nrf52840dk_nrf52840 samples/hello_world
west flash
```
## Pitfalls
- **Yocto disk/RAM:** a fresh build dir can exceed 50100 GB; `sstate-cache` reuse is essential. Check `df -h` and warn the user before kicking off `bitbake`.
- Never run `bitbake` as root, and don't run it bare-metal on the laptop without explicit permission — it will monopolize CPU for hours.
- Layer/branch mismatches (e.g. mixing `kirkstone` and `scarthgap` layers) cause obscure parse errors — let `kas` pin everything.
- `mkimage` needs the correct architecture/address flags matching the target SoC; a wrong load address silently hangs at boot.
- `fw_printenv`/`fw_setenv` require `/etc/fw_env.config` matching the device's env partition layout — wrong offsets corrupt the environment.