Files
openwrt-ci-ipq60xx/docs/AGENTS.md

18 KiB

AGENTS.md - AI Agent Reference Guide for openwrt-ci-ipq60xx

This document is a comprehensive reference for AI agents working with this repository. Last updated: 2026-03-01


Project Overview

This is a build-orchestration repository for OpenWrt/ImmortalWrt IPQ60XX firmware using Woodpecker CI.

Key Characteristics

Aspect Description
Type CI pipeline configuration (NOT a source code repo)
Target Platform Qualcomm IPQ60XX routers
Firmware Source VIKINGYFY/immortalwrt.git (main branch)
CI System Woodpecker
Config Source VIKINGYFY/OpenWRT-CI + davidtall/OpenWRT-CI

Architecture: Three-Layer Model

┌─────────────────────────────────────────────────────────────────┐
│ Layer 1: SOURCE (Firmware Code)                                 │
├─────────────────────────────────────────────────────────────────┤
│ Repository: VIKINGYFY/immortalwrt                                │
│ Branch: main                                                      │
│ Cloned: During CI build (git clone)                              │
│ Purpose: Provides OpenWrt/ImmortalWrt source code                │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│ Layer 2: CI-TEMPLATE (Config Templates)                          │
├─────────────────────────────────────────────────────────────────┤
│ Device Sets (Fixed files in repo):                               │
│   - Config/IPQ60XX-WIFI-YES.txt (VIKINGYFY source)               │
│   - Config/IPQ60XX-WIFI.txt (davidtall source)                   │
│                                                                  │
│ General Config (Dynamic, fetched at build time):                 │
│   - Config/GENERAL.upstream.txt (from davidtall/OpenWRT-CI)     │
│     Downloaded by Scripts/sync_upstream_config.sh                │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│ Layer 3: YOUR-DELTA (Local Customizations)                      │
├─────────────────────────────────────────────────────────────────┤
│ Config/GENERAL.local.txt - Your package additions                │
│ Scripts/Packages.sh - Custom package cloning                     │
│ Scripts/Handles.sh - Package tweaks/fixes                        │
│ Scripts/Settings.sh - kconfig/custom settings                    │
│ files/ - Rootfs overlay files                                    │
│                                                                  │
│ IMPORTANT: Only edit files in this layer!                       │
└─────────────────────────────────────────────────────────────────┘

Woodpecker Build Flow

Build Steps (.woodpecker/ipq60xx.yml)

1. init-env
   └─> Install build dependencies
   └─> Run ImmortalWrt init script

2. sync-configs
   └─> Execute Scripts/sync_upstream_config.sh
   └─> Download Config/GENERAL.upstream.txt

3. build-ipq60xx-wifi-yes
   ├─> Clone firmware source (VIKINGYFY/immortalwrt)
   ├─> feeds update -a && feeds install -a
   ├─> Execute Scripts/Packages.sh Handles.sh
   ├─> Merge configs: IPQ60XX-WIFI-YES.txt + GENERAL.upstream.txt + GENERAL.local.txt
   ├─> Execute Scripts/Settings.sh
   ├─> make defconfig -> make download -> make
   └─> Copy output to artifacts/ipq60xx-wifi-yes/

4. build-ipq60xx-wifi
   └─> Same as above, using IPQ60XX-WIFI.txt
   └─> Copy output to artifacts/ipq60xx-wifi/

Config Merging Order

During build, .config is assembled by concatenating in this order:

cat Config/IPQ60XX-WIFI-*.txt \
    Config/GENERAL.upstream.txt \
    Config/GENERAL.local.txt > .config

Rule: Later entries override earlier ones.

  • Device config settings have lowest priority
  • Upstream GENERAL can override device config
  • Your LOCAL overrides have highest priority

File Structure Reference

openwrt-ci-ipq60xx/
│
├── .woodpecker/
│   └── ipq60xx.yml              # Woodpecker pipeline definition
│
├── Config/
│   ├── IPQ60XX-WIFI-YES.txt    # Device set A (static, 21 devices)
│   ├── IPQ60XX-WIFI.txt        # Device set B (static, 9 devices)
│   ├── GENERAL.upstream.txt    # Fetched at build time (DO NOT EDIT)
│   └── GENERAL.local.txt       # YOUR package additions (EDIT THIS)
│
├── Scripts/
│   ├── sync_upstream_config.sh  # Fetch GENERAL.txt from upstream
│   ├── Packages.sh              # Clone custom GitHub packages
│   ├── Handles.sh               # Apply fixes to packages
│   └── Settings.sh               # kconfig and customization
│
├── files/                      # Rootfs overlay (optional)
├── artifacts/                  # Build outputs (gitignored)
├── docs/
│   ├── SKILLS.md               # User-facing documentation
│   └── AGENTS.md               # THIS FILE - Agent reference
│
├── README.md                   # Project README
└── .gitignore

Scripts Detailed Reference

Scripts/sync_upstream_config.sh

Purpose: Download GENERAL.txt from upstream davidtall/OpenWRT-CI

Functions:

# Variable: COMMIT to pin to specific version (optional, defaults to 'main')
UPSTREAM_GENERAL_REF="${UPSTREAM_GENERAL_REF:-main}"

# Download target
https://raw.githubusercontent.com/davidtall/OpenWRT-CI/${UPSTREAM_GENERAL_REF}/Config/GENERAL.txt

When to modify:

  • If upstream repository changes
  • If you want to change default branch

Scripts/Packages.sh

Purpose: Clone custom GitHub packages to override feed packages

Key Function: UPDATE_PACKAGE

UPDATE_PACKAGE "PKG_NAME" "USER/REPO" "BRANCH" ["MODE"] ["ALIAS_LIST"]

Parameters:

Parameter Description Example
PKG_NAME Package name to find/delete "argon"
USER/REPO GitHub repo "sbwml/luci-theme-argon"
BRANCH Git branch "openwrt-25.12"
MODE Optional: "pkg" or "name" "pkg"
ALIAS_LIST Optional: space-separated aliases "appfilter oaf"

Modes:

  • pkg: Extract package from multi-package repo
  • name: Rename cloned directory to PKG_NAME
  • (empty): Use repo name as-is

Current Packages (lines 48-76):

  • Themes: argon, aurora, kucat (+ configs)
  • Proxy: homeproxy, momo, nikki, openclash, passwall, passwall2
  • Network: tailscale, easytier, vnt
  • Tools: ddns-go, diskman, fancontrol, partexp, quickfile
  • Storage: qbittorrent, gecoosac
  • DNS: mosdns, openlist2
  • Misc: qmodem, viking (timewol, wolplus)
  • Speedtest: netspeedtest (+ homebox, speedtest)

Function: UPDATE_VERSION (lines 79-117)

Updates package version from GitHub releases:

UPDATE_VERSION "PKG_NAME" [false]  # false=stable only, true=includes prerelease

Currently updates: sing-box


Scripts/Handles.sh

Purpose: Apply various fixes and customizations to packages

Handles (in order):

Handle Target Action
homeproxy $PKG_PATH/homeproxy Clone surge-rules, generate IP lists
luci-theme-argon Theme colors Set primary color, font weight
luci-app-aurora-config Menu style Set nav_submenu_type to boxed-dropdown
qca-nss-drv Init script Set START=85
qca-nss-pbuf Init script Set START=86
tailscale Makefile Remove /files to avoid config conflict
rust Makefile Disable ci-llvm (fix compile fail)
diskman Makefile Remove ntfs-3g-utils dependency
netspeedtest Defaults/speedttest Add exit 0, fix cert bundle

Variable Dependency: Uses $PKG_PATH (expected to be $GITHUB_WORKSPACE/wrt/package/)

Note: Some handles check directory presence with if [ -d *"name"* ] glob pattern


Scripts/Settings.sh

Purpose: Apply kconfig settings and custom modifications

Areas Modified:

  1. LuCI:

    • Remove luci-app-attendedsysupgrade
    • Change default theme (via $WRT_THEME)
    • Set immortalwrt.lan IP (via $WRT_IP)
    • Add build date marker (via $WRT_MARK, $WRT_DATE)
  2. WiFi (auto-detect):

    • Files: set-wireless.sh or mac80211.uc
    • Set SSID ($WRT_SSID)
    • Set password ($WRT_WORD)
    • Set country: CN
    • Set encryption: psk2+ccmp
  3. Network (via config_generate):

    • Default IP ($WRT_IP)
    • Hostname ($WRT_NAME)
  4. General Config additions:

    • CONFIG_PACKAGE_luci=y
    • CONFIG_LUCI_LANG_zh_Hans=y
    • Theme packages (via $WRT_THEME)
  5. Custom packages (via $WRT_PACKAGE):

    • If non-empty, append line by line to .config
  6. Qualcomm IPQ60XX specific (via $WRT_TARGET, $WRT_CONFIG):

    • Disable NSS feeds
    • Enable sqm-nss
    • Set NSS firmware version (11.4=n, 12.2 for IPQ50xx, 12.5 for others)
    • Handle "nowifi" variants by modifying DTS includes
    • Enable kmod-usb-serial-qualcomm

Environment Variables Expected:

  • $WRT_THEME, $WRT_IP, $WRT_MARK, $WRT_DATE
  • $WRT_SSID, $WRT_WORD, $WRT_NAME
  • $WRT_PACKAGE, $WRT_TARGET, $WRT_CONFIG

Important: This script does NOT declare these variables - they must be set before calling.


How to Modify Packages

Step 1: Check if package exists in feeds

If yes → Add to Config/GENERAL.local.txt:

CONFIG_PACKAGE_luci-app-mypackage=y

If no or needs specific version → Edit Scripts/Packages.sh

Step 2: Add package in Scripts/Packages.sh

Basic clone:

UPDATE_PACKAGE "mypackage" "username/mypackage-repo" "main"

With aliases (to delete conflicting packages):

UPDATE_PACKAGE "open-app-filter" "destan19/OpenAppFilter" "master" "" "luci-app-appfilter oaf"

Extract from multi-package repo:

UPDATE_PACKAGE "openclash" "vernesong/OpenClash" "dev" "pkg"

Rename cloned directory:

UPDATE_PACKAGE "custom-name" "user/repo" "branch" "name"

Step 3: Add fixes in Scripts/Handles.sh (if needed)

Create a handle block:

if [ -d *"mypackage"* ]; then
    echo " "
    cd ./mypackage/
    # Apply fixes here with sed/cp/mv
    cd $PKG_PATH && echo "mypackage has been fixed!"
fi

Step 4: Add config in Settings.sh (optional)

If package needs kconfig flags, add after custom packages section:

# My package specific settings
echo "CONFIG_PACKAGE_kmod-mymodule=y" >> ./.config

Common Tasks for Agents

Task: Add a new LuCI app from feeds

# 1. Edit Config/GENERAL.local.txt
echo "CONFIG_PACKAGE_luci-app-newapp=y" >> Config/GENERAL.local.txt

# 2. Commit changes
git add Config/GENERAL.local.txt
git commit -m "add: luci-app-newapp"
git push

Task: Add a custom package from GitHub

# 1. Edit Scripts/Packages.sh (Add line 48-76 area)
# Add:
# UPDATE_PACKAGE "newpackage" "user/newpackage-repo" "main"

# 2. If needed, add fix to Scripts/Handles.sh
# 3. Commit and push

Task: Update an existing package version

# 1. Edit Scripts/Settings.sh if version needs kconfig change
# 2. Edit Scripts/Packages.sh UPDATE_VERSION call
# 3. OR add new UPDATE_VERSION call:
#    UPDATE_VERSION "newpackage"
# 4. Commit and push

Task: Pin GENERAL.txt to specific commit

# Option A: Add to Woodpecker CI variables
# Variable: UPSTREAM_GENERAL_REF = <commit-hash>

# Option B: Modify sync_upstream_config.sh default
# Edit line 6: UPSTREAM_GENERAL_REF="${UPSTREAM_GENERAL_REF:-main}"
# Change 'main' to commit hash

Task: Add a specific device configuration

# 1. Find the device target from openwrt menuconfig
# 2. Add to appropriate config file (IPQ60XX-WIFI-YES.txt or IPQ60XX-WIFI.txt):
#    CONFIG_TARGET_DEVICE_qualcommax_ipq60xx_DEVICE_<device_name>=y
# 3. Commit and push

Task: Debug build failure

# 1. Check Woodpecker logs
# 2. Identify failing step
# 3. Review error messages in CI log
# 4. Check if upstream GENERAL.upstream.txt has breaking changes
# 5. Try pinning to previous commit with UPSTREAM_GENERAL_REF
# 6. Add custom override in GENERAL.local.txt

Build Targets Reference

IPQ60XX-WIFI-YES (21 devices)

Source: VIKINGYFY/OpenWRT-CI

Devices:

  • anysafe_e1, cmiot_ax18, glinet_gl-ax1800, glinet_gl-axt1800
  • jdcloud_re-cs-02, jdcloud_re-ss-01
  • link_nn6000-v1, link_nn6000-v2, linksys_mr7350, linksys_mr7500
  • philips_ly1800, qihoo_360v6
  • redmi_ax5, redmi_ax5-jdcloud
  • sy_y6010, xiaomi_ax1800
  • zn_m2

IPQ60XX-WIFI (9 devices)

Source: davidtall/OpenWRT-CI

Devices:

  • cmiot_ax18, jdcloud_re-ss-01, jdcloud_re-cs-02
  • qihoo_360v6, redmi_ax5-jdcloud, redmi_ax5
  • xiaomi_ax1800, zn_m2

Includes:

  • Kernel cgroup configs
  • NSS configurations (disabled feeds, sqm-nss enabled)
  • Memory profiles (512MB)

Environment Variables Reference

Woodpecker Pipeline Variables

Variable Default Description
WRT_REPO https://github.com/VIKINGYFY/immortalwrt.git Firmware source repo
WRT_BRANCH main Firmware source branch
UPSTREAM_GENERAL_REF main GENERAL.txt version

Scripts Settings.sh Variables

Variable Purpose Example
WRT_THEME LuCI theme name argon
WRT_IP Default IP 192.168.1.1
WRT_MARK Build marker Custom
WRT_DATE Build date Date string
WRT_SSID WiFi SSID MyRouter
WRT_WORD WiFi password password123
WRT_NAME Hostname OpenWrt
WRT_PACKAGE Custom packages Multi-line string
WRT_TARGET Target platform QUALCOMMAX
WRT_CONFIG Config variant ipq60xx

Scripts Handles.sh Variables

Variable Purpose Expected
PKG_PATH Package path $GITHUB_WORKSPACE/wrt/package/
GITHUB_WORKSPACE CI workspace Set by Woodpecker

Troubleshooting Guide

Issue: Build fails after upstream GENERAL.txt update

Symptoms: New errors appeared without local changes

Causes:

  1. Upstream added conflicting config
  2. Upstream removed a package you depended on

Solutions:

# Fast fix - Pin to previous working commit
UPSTREAM_GENERAL_REF=<previous-commit-hash>

# Permanent fix - Override in GENERAL.local.txt
# Add the conflicting option with your desired value

Issue: $4: unbound variable error

Symptoms: Packages.sh fails with unbound variable

Cause: UPDATE_PACKAGE called without 4th/5th parameter using set -u

Solution: Already fixed in current version using ${4:-} default

Issue: Package not found despite being in Packages.sh

Symptoms: Package missing in final firmware

Checklist:

  1. Verify UPDATE_PACKAGE has correct repo URL
  2. Check if branch exists
  3. Look for error in Woodpecker git clone logs
  4. Verify package name matches expected directory

Issue: Handles.sh not applying fix

Symptoms: Expected modifications not present

Checklist:

  1. Verify $PKG_PATH is set correctly
  2. Check glob pattern matches: if [ -d *"packagename"* ]
  3. Verify handle is in correct directory after cd

CI/CD Operations

Triggering Builds

Trigger Command/UI
Manual Woodpecker UI > Run Pipeline
Push git push to main branch
Cron Woodpecker UI > Schedules (configured separately)

Artifact Locations

After successful build:

  • artifacts/ipq60xx-wifi-yes/targets/qualcommax/ipq60xx/
  • artifacts/ipq60xx-wifi/targets/qualcommax/ipq60xx/

Contains:

  • *-sysupgrade.bin - Main firmware image
  • *-factory.bin - Factory flash image (if available)
  • Other device-specific files

Maintenance Guidelines

When upstream changes break builds

  1. Enable debug: Add V=s to make command (already present)
  2. Identify failure: Check Woodpecker logs step by step
  3. Pin version: Set UPSTREAM_GENERAL_REF to last known good commit
  4. Report issue: Document in this AGENTS.md
  5. Create fix: Add override or modify scripts

Adding new package categories

  1. Group related packages in Packages.sh with comments
  2. Document in this file under "Current Packages"
  3. Update README.md if user-facing

Updating this document

When making changes that affect this doc:

  1. Update relevant sections
  2. Increment Last Updated date at top
  3. Commit with message: docs: update AGENTS.md

Version History

Date Change
2026-03-01 Initial document created with full project reference

Quick Command Reference

# Sync upstream config locally (test)
cd Scripts && ./sync_upstream_config.sh

# Test config merge
cat Config/IPQ60XX-WIFI-YES.txt Config/GENERAL.upstream.txt Config/GENERAL.local.txt > test.config

# Fix a package in Handles.sh pattern
if [ -d *"packagename"* ]; then
    echo " "
    cd ./packagename/
    # Your fix here
    cd $PKG_PATH && echo "fixed!"
fi

# Add package in Packages.sh format
UPDATE_PACKAGE "name" "user/repo" "branch" ["mode"] ["alias1 alias2"]

# Add feed package to config
echo "CONFIG_PACKAGE_luci-app-pkgname=y" >> Config/GENERAL.local.txt

External References