AGENTS.md - Guidelines for AI Agents

This file contains critical guidelines, learnings, and best practices for AI agents working on the seedsigner-luckfox-pico repository.


⚠️ CRITICAL RULES - READ FIRST ⚠️

These rules must NEVER be violated unless explicitly instructed by the user:

1. NEVER Remove Buildroot Packages

DO NOT:

  • Remove packages from buildroot/configs/luckfox_pico_defconfig to fix size issues
  • Disable packages to make builds fit
  • Suggest removing packages as a solution to build problems
  • Delete package configurations from build scripts

WHY:

  • This is a development image with intentionally included packages
  • Size issues should be solved by partition layout optimization, not package removal
  • Packages are carefully selected and may have dependencies
  • Removing packages can break functionality

INSTEAD:

  • Optimize partition layouts
  • Analyze actual space usage
  • Suggest specific packages IF user asks what could be removed
  • Never make the decision to remove packages yourself

2. NEVER Change Upstream Repositories or Branches

DO NOT change these repositories or branches unless explicitly instructed:

  • seedsigner repository: https://github.com/3rdIteration/seedsigner
    • Branch: dev
    • This is a carefully selected version with specific patches
  • seedsigner-os repository: https://github.com/3rdIteration/seedsigner-os
    • Contains “known good” external package configurations
    • Reference point for all package integrations
  • luckfox-pico SDK repository: https://github.com/3rdIteration/luckfox-pico
    • This fork contains necessary modifications
    • Don’t switch to upstream LuckFox repository

WHY:

  • These are specifically chosen versions with required modifications
  • Changing repos can break builds completely
  • Branches contain specific patches not in main branches
  • User has tested these specific combinations

3. ALWAYS Keep Build Scripts in Sync

CRITICAL: This repository has THREE different build methods that must be kept in sync:

  1. buildroot/os-build.sh - Docker/container builds
  2. buildroot/build-local.sh - Native/local builds
  3. .github/workflows/build.yml - GitHub Actions CI builds

DO NOT:

  • Make changes to only one build script
  • Assume GitHub Actions uses os-build.sh (it doesn’t!)
  • Forget to update all three when modifying the build process

ALWAYS:

  • Apply the same changes to all three build methods
  • Test that modifications work in all three contexts
  • Verify GitHub Actions workflow matches the shell scripts

WHY:

  • GitHub Actions has its own custom build steps (doesn’t call os-build.sh)
  • Changes to os-build.sh will NOT affect CI builds
  • Inconsistent builds lead to “works locally but fails in CI” issues
  • Users need all three methods to work identically

EXAMPLE: If you add a partition modification or package installation:

# 1. Add to buildroot/os-build.sh
# 2. Add to buildroot/build-local.sh  
# 3. Add to .github/workflows/build.yml (same logic, different context)

VERIFICATION:

  • Check GitHub Actions logs to confirm changes took effect
  • Compare all three files side-by-side for critical build steps
  • Watch for “file not found” or “step skipped” in CI logs

External Package Integration - KEY LEARNING

This was the major lesson from the python-pyscard/pysatochip integration:

The Problem

LuckFox SDK ≠ Standard Buildroot

The LuckFox Pico SDK uses a custom build system that wraps standard buildroot. This means:

  1. BR2_EXTERNAL doesn’t work like in standard buildroot
  2. Variables don’t expand in Config.in context
  3. Packages must be copied to SDK’s package directory
  4. Standard paths must be used (no BR2EXTERNAL* variables)

The Wrong Approach (DON’T DO THIS)

# ❌ WRONG - This doesn't work in LuckFox SDK
source "$BR2_EXTERNAL_SEEDSIGNER_PATH/package/python-pyscard/Config.in"

Why it fails:

  • LuckFox SDK doesn’t set up BR2_EXTERNAL_SEEDSIGNER_PATH
  • Variables aren’t expanded when buildroot reads Config.in
  • Results in “can’t open file” errors

The Correct Approach (DO THIS)

Step 1: Place package in this repository

buildroot/external-packages/python-yourpackage/
├── Config.in
├── python-yourpackage.mk
├── python-yourpackage.hash
└── patches/ (if needed)

Step 2: Copy to SDK during build

In all build scripts (os-build.sh, build-local.sh, build.yml):

# Copy this repo's external packages to SDK
if [ -d "buildroot/external-packages" ]; then
    echo "📦 Copying local external packages to SDK..."
    cp -rv buildroot/external-packages/* "$PACKAGE_DIR/" || true
fi

Step 3: Reference as standard buildroot package

# ✅ CORRECT - Standard buildroot path
source "package/python-yourpackage/Config.in"

Step 4: Enable in defconfig

BR2_PACKAGE_PYTHON_YOURPACKAGE=y

Integration Checklist

When adding a new external package:

  • Check if package exists in seedsigner-os (use their version if available)
  • Place package files in buildroot/external-packages/packagename/
  • Update all 3 build scripts to copy external packages to SDK
  • Add menu entry using source "package/packagename/Config.in"
  • Enable in buildroot/configs/luckfox_pico_defconfig
  • Test build on all hardware variants
  • Document in buildroot/external-packages/README.md or similar

Build System Architecture

LuckFox SDK Structure

luckfox-pico/                          # SDK repository
├── sysdrv/
│   └── source/
│       └── buildroot/
│           └── buildroot-*/           # Standard buildroot
│               └── package/           # Where packages must be
│                   ├── python-urtypes/
│                   ├── python-pyscard/    # Copied here during build
│                   └── python-pysatochip/ # Copied here during build
└── project/
    └── cfg/
        └── BoardConfig_IPC/
            ├── BoardConfig-SPI_NAND-*-Mini-*.mk
            └── BoardConfig-SPI_NAND-*-Max-*.mk

Package Source Locations

This Repository:

buildroot/external-packages/
├── python-pyscard/
└── python-pysatochip/

seedsigner-os Repository:

opt/external-packages/
├── python-embit/
├── python-mnemonic/
├── python-urtypes/
├── python-pyzbar/
└── ... (many more)

During Build:

  1. Copy from seedsigner-os → SDK package/
  2. Copy from this repo → SDK package/
  3. Add menu entries to SDK’s package/Config.in
  4. Build proceeds with standard buildroot

Common Pitfalls

❌ Pitfall 1: Assuming BR2_EXTERNAL Works

Mistake:

source "$BR2_EXTERNAL_SEEDSIGNER_PATH/package/mypackage/Config.in"

Why it fails:

  • LuckFox SDK doesn’t use BR2_EXTERNAL system
  • Variable isn’t set or expanded

Solution: Copy packages to SDK and use standard paths

❌ Pitfall 2: Not Copying Packages to SDK

Mistake: Placing packages in buildroot/external-packages/ but not copying them during build.

Why it fails: Buildroot can’t find the package files.

Solution: Add copy step in all build scripts (see External Package Integration section)

❌ Pitfall 3: Removing Packages to Fix Size Issues

Mistake: “The build is too big, let me remove git, pip, wget to save space.”

Why it’s wrong:

  • This is explicitly forbidden (see CRITICAL RULES)
  • It’s a development image, packages are intentional
  • User wants all tools available

Solution: Optimize partition layouts, don’t remove packages

❌ Pitfall 4: Not Comparing with seedsigner-os

Mistake: Creating packages from scratch without checking seedsigner-os.

Why it’s suboptimal:

  • seedsigner-os has “known good” configurations
  • Packages are already tested and working
  • No need to reinvent the wheel

Solution: Always check seedsigner-os first, copy their package configurations


Best Practices

1. Always Compare with seedsigner-os

When adding packages or debugging:

  1. Check if package exists in seedsigner-os repository
  2. Review their implementation
  3. Copy their approach (adapted for LuckFox SDK)
  4. Use their version numbers and patches

2. Test Thoroughly

Before committing package changes:

  • Test SD card build (Mini and Max)
  • Test SPI-NAND build (Mini and Max)
  • Verify packages install to rootfs
  • Check for dependency issues
  • Review build logs for warnings

3. Document Everything

When making changes:

  • Update buildroot/configs/enabled_packages_analysis.txt
  • Create/update documentation in buildroot/configs/
  • Add comments in build scripts explaining why
  • Update AGENTS.md if new patterns emerge

4. Use Existing Patterns

Look at how existing packages are handled:

  • python-urtypes
  • python-embit
  • python-pyzbar
  • python-mnemonic

Follow the same pattern for consistency.

5. Add Comprehensive Error Handling

In build scripts:

# Check if source exists
if [ ! -d "buildroot/external-packages" ]; then
    echo "⚠️  No external packages directory"
fi

# Copy with error handling
cp -rv buildroot/external-packages/* "$PACKAGE_DIR/" || {
    echo "❌ Failed to copy external packages"
    exit 1
}

# Verify copy succeeded
if [ -d "$PACKAGE_DIR/python-pyscard" ]; then
    echo "✅ python-pyscard copied successfully"
fi

Partition Optimization Lessons

Key Principles

  1. Check actual device usage before assuming sizes
    • Example: OEM partition shows 16.4MB used, don’t allocate just 8MB
  2. Account for UBIFS overhead (15-20%)
    • Raw partition size ≠ usable space
    • Formula: Usable = Raw × 0.82 (approximate)
  3. Verify patches actually apply
    • Don’t trust “success” status without verification
    • Check actual partition sizes in build output
    • Add post-patch verification steps
  4. Add debugging output
    • Show what’s being patched
    • Display partition tables after patching
    • Warn if verification fails
  5. Test verification logic
    • Grep for expected values
    • Show warnings if not found
    • Don’t silently fail

Example: Mini SPI-NAND Partition Optimization

Problem: Rootfs needed 93MB, only had 85MB

Wrong approach: Remove packages to fit in 85MB

Correct approach:

  1. Analyze actual OEM usage (16.4MB)
  2. Remove unused userdata partition (6MB)
  3. Reduce oversized OEM from 30MB to 24MB
  4. Expand rootfs to 99MB
  5. Verify with device df output
  6. Create patches to automate the change

Quick Reference

External Package Directory

buildroot/external-packages/

SDK Package Directory (destination during build)

$SDK_DIR/sysdrv/source/buildroot/buildroot-*/package/

Build Scripts

  • GitHub Actions: .github/workflows/build.yml
  • Docker build: buildroot/os-build.sh
  • Native build: buildroot/build-local.sh

Configuration

  • Main defconfig: buildroot/configs/luckfox_pico_defconfig
  • Package analysis: buildroot/configs/enabled_packages_analysis.txt

Rust Toolchain Cache

  • Cache directory: buildroot/cache/
  • GitHub Actions: uses actions/cache keyed on defconfig hash
  • Local builds (build-local.sh): saves/restores buildroot/cache/rust-toolchain.tar.zst (git-ignored)
  • Docker builds (os-build.sh): always builds from source (no caching)
  • Force rebuild flags:
    • GitHub Actions: build_rust_from_source: true (workflow_dispatch input)
    • build-local.sh: --build-rust-from-source

Common Commands

Check what’s enabled:

grep "BR2_PACKAGE_.*=y" buildroot/configs/luckfox_pico_defconfig

Analyze package sizes:

./buildroot/scripts/analyze_packages.sh

Verify external packages:

ls -l buildroot/external-packages/

Additional Resources

Flashing, recovery and secure boot

  • soctoolkit-cli.md: run upgrade_tool (SocToolkit’s CLI) directly to flash, read back, and diagnose a board. SocToolkit’s own log (<SocToolKit>\Log) records every command it ran; read it rather than inferring what was flashed. db is RAM-only. wl/el/ef/ul/uf change flash, so confirm with the user before running them.
  • A board that only prints RKUART is BootROM rejecting the NAND idblock, not necessarily a dead board. Power-cycle between download attempts. On a fused board, compare the loader’s OTP hash (rk_sign_tool otp --loader --hash, or rkloader.py inspect) with what the SPL burned.
  • Before arming an OTP burn, rkloader.py verify and luckfox_release.py check must pass on the exact files being flashed. They catch the two defects an unfused board cannot show (stale header PKA constant; 1970 releaseTime), see airgapped-signing.md.
  • Never commit key material: no private keys, no mnemonics, and no fingerprints of a user’s real keys. For BIP85 examples and tests use the public test mnemonic (abandon ×11 + about) or the committed dev keys.

GPIO Configuration Reference

For any task related to GPIO pin configuration on the RV1106, consult:

  • docs/Rockchip_RV1106_User_Manual_GPIO.pdf — The authoritative register-level reference for all RV1106 GPIO pins. Contains exact register addresses, bit positions, and ready-to-use io commands for IOMUX, pull-up/down, input enable, direction, drive strength, and Schmitt trigger for every GPIO pin. (Original source)

  • buildroot/files/configure-gpio.sh — Startup script that uses the io command to configure all button GPIO pins (IOMUX → GPIO, pull-up, input, input-buffer enable) for each LuckFox Pico variant. Auto-detects the variant from /proc/device-tree/model.

  • Seedsigner io_config.json — Pin-to-button mapping for each hardware profile (FOX_22, FOX_40, FOX_PI). Located at src/seedsigner/hardware/io_config.json in the seedsigner repo.

Key facts about RV1106 GPIO:

  • All IOC and GPIO registers use Rockchip write-with-mask format: bits[31:16]=mask, bits[15:0]=value.
  • python-periphery pull_up bias is silently ignored on RV1106 — use io command writes instead.
  • GPIO4 (VCCIO6 domain) uses a different pull encoding: 0=normal, 1=pull-down, 3=pull-up.
  • The io (busybox raw memory I/O utility) is the correct tool for register writes.

Detailed Documentation

All detailed documentation is in buildroot/configs/:

  • SMARTCARD_BUILD_FIX.md - External package integration fix
  • SMARTCARD_PACKAGES.md - Smartcard package details
  • PATCH_FIX_SUMMARY.md - Partition patch debugging
  • NAND_INVESTIGATION_REPORT.md - SPI-NAND size analysis
  • OEM_SPACE_REQUIREMENTS.md - OEM partition sizing
  • MINI_NAND_FIX.md - Mini SPI-NAND partition fix
  • MINI_NAND_BUILD_FAILURE_ANALYSIS.md - Build failure investigation
  • IMPLEMENTATION_SUMMARY.md - Patch system overview
  • enabled_packages_analysis.txt - Current package list with sizes

External Package Examples

Look in buildroot/external-packages/ for examples:

  • python-pyscard/ - PC/SC smartcard wrapper
  • python-pysatochip/ - Satochip hardware wallet API
  • seedsigner: https://github.com/3rdIteration/seedsigner/tree/dev
  • seedsigner-os: https://github.com/3rdIteration/seedsigner-os
  • luckfox-pico: https://github.com/3rdIteration/luckfox-pico

Summary for AI Agents

Before Starting Work

  1. Read this file (AGENTS.md) completely
  2. Check the CRITICAL RULES section
  3. Review relevant detailed documentation
  4. Compare with seedsigner-os if adding packages

When Adding Packages

  1. Check if it exists in seedsigner-os ✓
  2. Copy to buildroot/external-packages/ ✓
  3. Update all 3 build scripts to copy to SDK ✓
  4. Use standard package/…/Config.in paths ✓
  5. Enable in defconfig ✓
  6. Test thoroughly ✓
  7. Document the addition ✓

When Debugging

  1. Never remove packages as a first resort ✓
  2. Never change upstream repos/branches ✓
  3. Compare with seedsigner-os for patterns ✓
  4. Check detailed documentation in buildroot/configs/ ✓
  5. Add comprehensive debugging output ✓
  6. Test verification logic ✓

Remember

  • LuckFox SDK ≠ Standard Buildroot
  • Copy packages, don’t use BR2_EXTERNAL
  • Standard paths only: package/…/Config.in
  • seedsigner-os has “known good” configs
  • Never remove packages
  • Never change repos
  • Test thoroughly
  • Document everything

This file was created from learnings during extensive work on external package integration, partition optimization, and build system debugging. It represents real-world solutions to real problems encountered.

Last updated: 2026-02-17


Released under the MIT License. The SeedSigner OS section is mirrored from the seedsigner-os repository at the pinned release commit.

This site uses Just the Docs, a documentation theme for Jekyll.