Agent Probe Development (apps/agent)
The agent is a Go binary deployed on routers/servers. It polls the local gateway (mihomo/Surge) and reports to the collector over HTTP (gzip JSON POST to /api/agent/report|heartbeat|config|policy-state) — not WebSocket.
Layout
main.go— entrypoint, flag parsinginternal/agent/runner.go— main loop: report/heartbeat/config-sync tickers, pending queue, retry batchinternal/gateway/— mihomo & Surge API clientsinternal/config/config.go— flags,AgentProtocolVersionnekoagent— POSIX-sh service manager wrapper (install/upgrade/systemd/procd/launchd)install.sh— curl-pipe installer
Verify
cd apps/agent
go vet ./... && go build ./... && go test ./...
sh -n nekoagent && sh -n install.sh # shell syntax gate — both scripts must parse with POSIX sh
Hard rules
- Protocol versioning. Payload shape changes require bumping
AgentProtocolVersion(Go) AND the collector's minimum accepted version (agent auth inapps/collector/src/modules/app/app.ts); the collector rejects too-old agents with HTTP 426 + structured error. The Go structs and the collector's TS payload types are mirrored by hand — change both sides in one commit. - Data-loss protections are contracts: single in-flight retry batch,
requestIdidempotency dedup, counter-regression handling (gateway restart counts current value as new traffic), bounded pending queue withdroppedaccounting. Don't weaken these when refactoring the loop. - Router constraints. Target environments include OpenWrt/BusyBox:
nekoagentmust stay POSIX sh (no bashisms),/tmpis tmpfs (RAM) — clean up temp dirs (accumulate EXIT traps, don't overwrite them), and network calls in shell must carry timeouts + retries (curl --connect-timeout 10 --max-time 120 --retry 3). - Self-replacement. Never overwrite a running script/binary in place — download to a sibling
.tmp/.newpath andmv(same-filesystem rename) so the running inode survives. - Service management. systemd unit:
StartLimitIntervalSec/Burstbelong in[Unit], not[Service]. procd (OpenWrt) respawn has a finite retry budget — treat "cannot start" as exit non-zero so supervisors behave correctly.
Release
Tag-driven, independent from the main product: git tag agent-vX.Y.Z && git push origin agent-vX.Y.Z → .github/workflows/agent-release.yml publishes multi-arch binaries (~1 min). The binary version comes from the tag via ldflags — no version file. Full flow: docs/agent/release.en.md.
Known deferred issues and their context live in docs/dev/deep-review-2026-07.md (agent P0/P1 section) — check it before starting a fix batch so related items ship together.