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 reponame: 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:
-
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)
-
WiFi (auto-detect):
- Files:
set-wireless.shormac80211.uc - Set SSID (
$WRT_SSID) - Set password (
$WRT_WORD) - Set country: CN
- Set encryption: psk2+ccmp
- Files:
-
Network (via
config_generate):- Default IP (
$WRT_IP) - Hostname (
$WRT_NAME)
- Default IP (
-
General Config additions:
CONFIG_PACKAGE_luci=yCONFIG_LUCI_LANG_zh_Hans=y- Theme packages (via
$WRT_THEME)
-
Custom packages (via
$WRT_PACKAGE):- If non-empty, append line by line to .config
-
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:
- Upstream added conflicting config
- 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:
- Verify UPDATE_PACKAGE has correct repo URL
- Check if branch exists
- Look for error in Woodpecker git clone logs
- Verify package name matches expected directory
Issue: Handles.sh not applying fix
Symptoms: Expected modifications not present
Checklist:
- Verify
$PKG_PATHis set correctly - Check glob pattern matches:
if [ -d *"packagename"* ] - 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
- Enable debug: Add
V=sto make command (already present) - Identify failure: Check Woodpecker logs step by step
- Pin version: Set
UPSTREAM_GENERAL_REFto last known good commit - Report issue: Document in this AGENTS.md
- Create fix: Add override or modify scripts
Adding new package categories
- Group related packages in Packages.sh with comments
- Document in this file under "Current Packages"
- Update README.md if user-facing
Updating this document
When making changes that affect this doc:
- Update relevant sections
- Increment Last Updated date at top
- 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