# AGENTS.md ## Project `github.com/fatedier/frp` — fast reverse proxy. Go 1.25. Two binaries: - **frps** (server): `cmd/frps/main.go` → `server/` - **frpc** (client): `cmd/frpc/main.go` → `client/` ## Build & Dev Commands | Command | What | |---------|------| | `make build` | Build both binaries to `bin/` | | `make frps` / `make frpc` | Single binary | | `make all` | `fmt → web → build` | | `make web` | Build web dashboards (`web/frps/`, `web/frpc/`) | | `make clean` | Remove `bin/`, `lastversion/`, `.cache/`, `.compat/` | Build tags: `frps`, `frpc`, and `noweb` (auto-added when web assets missing). CGO disabled, `-trimpath`, stripped symbols. ## Test | Command | What | |---------|------| | `make test` / `make gotest` | Unit tests with `--cover` per package | | `make e2e` | E2E via ginkgo (parallel, 16 nodes) | | `make e2e-trace` | Same with `LOG_LEVEL=trace` | | `make alltest` | `vet → gotest → e2e` (CI pipeline) | - E2E uses Ginkgo/Gomega. Requires `ginkgo` binary (auto-installed by `hack/run-e2e.sh`). - Binary paths: `FRPC_PATH` / `FRPS_PATH` env vars (default `bin/frpc`, `bin/frps`). - E2E mock servers in `test/e2e/mock/`. - Compatibility e2e: `make e2e-compatibility`, `make e2e-compatibility-smoke`, `make e2e-compatibility-floor`. Controls: `FRP_COMPAT_BASELINE_COUNT` (default 8), `FRP_COMPAT_FLOOR_VERSION` (default 0.61.0). - CI: CircleCI runs `make alltest` after building web assets. ## Code Quality | Command | What | |---------|------| | `make fmt` | `go fmt ./...` | | `make fmt-more` | `gofumpt` | | `make gci` | Import organizer: standard → default → `github.com/fatedier/frp/` | | `make vet` | `go vet` with `noweb` build tag | | `golangci-lint run` | Full lint (v2 config, `.golangci.yml`) | ## Architecture - **Config**: TOML, YAML, or JSON. INI format is **deprecated** (v0.52.0+). Default: `./frpc.ini`. - **DB-first config**: frps stores config in SQLite by default. Config file is optional (`-c` flag bypasses DB). - **First-run flow**: No config file + no DB config → auto-saves defaults (bind 0.0.0.0:7000, web 0.0.0.0:7500) and redirects admin UI to setup wizard. - **Flags**: `--config` / `-c`, `--strict_config` (default true), `--allow-unsafe`. - **Feature gates**: Enabled via `featureGates = { VirtualNet = true }`. - **Store**: `store.path` enables dynamic proxy CRUD at runtime (persisted to disk, takes precedence over static config on name conflict). - **Config aggregation**: Static file + includes + store. `start` acts as global allowlist (not recommended for new configs; prefer per-proxy `enabled`). - **frpc subcommands**: `frpc reload`, `frpc verify`, `frpc status`, `frpc tcp` (direct CLI proxy creation). - **Multi-client mode**: `--config_dir` runs one frpc per config file (testing only, not stable). - **Admin DB**: SQLite via `ent` ORM at `pkg/db/`. Schema: User, FrpcClient, Proxy, ServerConfig. Auto-creates `admin.db` and seeds default admin user (`admin`/`admin123`). - **Admin UI**: htmx-based dashboard at `/admin/` on frps web server port. Login required, session cookie auth. Pages: Dashboard, Clients, Proxies, Settings. - **Server Config via UI**: All frps settings editable from Settings page. First-run redirects to setup wizard. Save triggers restart prompt. ## Release See `doc/agents/release.md` for the full process. Key steps: - Bump version in `pkg/util/version/version.go` - `make e2e` + compatibility tests - Merge `dev` → `master` with merge commit (not squash) - Tag `vX.Y.Z` and trigger `goreleaser` workflow manually via `gh`