# Agent Instructions MoShiro is a self-hosted network path quality monitor. Agents on home broadband, NAT networks, or public VPS hosts run active measurements and record raw per-packet and per-event data. The Backend stores it, derives metrics, scores lines per service model, and serves a REST/SSE API to two web apps. Documentation is in Chinese under [`docs/`](docs/); source comments are mostly Chinese too. [`README.md`](README.md) is the entry point. ## Mental model | Term | Meaning | | --- | --- | | Agent | Unified collector process (NativeAOT, BCL only), listening and dialing by default. Each Agent connects to the Backend over `wss` and reports outgoing link health and incoming sessions. | | Line | One directed (dialer, listener) Agent pair, per IP family. Id `~`, IPv6 adds `~ipv6`; series key `line:` | | Kind | A declared measurement method (`udp_echo`, `tcp_echo`, `connect`, ...) composed from building blocks. Defined once in `MoShiro.Protocol/Catalog/Kinds` | | RawChunk | Self-describing columnar block, cut every 10 s, appended to segment files. The Backend never trusts node-reported statistics | | Metric, Model | `MetricDef` is a one-line declaration over accumulators; models score metrics at query time. Both are recomputable from raw data | | Plan | A sequence of on-demand test phases (for example `hy2_ladder`). Exists only in the Backend (`Application/Tests/Plans.cs`) | | Fleet | Product-agnostic node framework under `backend/fleet/` (identity, enrollment, RPC, link, outbox, state sync) | | Operator set | Passkey-signed trust root. Nodes pin its genesis fingerprint and owner at install time and verify the chain themselves | ## Invariants (violations fail the build or review) - Node processes are kept to measurement and reporting by build-time restrictions: process start, dynamic loading, `HttpClient`, and file writes outside `Fleet.Hosting.ConfigStore` are banned (`backend/BannedSymbols.Node.txt`). Capabilities such as updates or command execution are not part of the core; adding or changing one needs a design review against `docs/security/security.md`. - `backend/fleet/**` must not reference `MoShiro.*` (`ArchitectureTests`). `MoShiro.Measurement` contains no service concepts such as REALITY or Hysteria2. - Every RPC method is declared in a method table (`FleetMethodTable`, `MoShiroMethodTable`) with direction, type and roles. Add the declaration before the handler. - `Backend.Api` must not reference `Storage`. Error-code to HTTP mapping happens once, in the Api layer. - Server-sent parameters pass `ParamSpec` validation and then the node-local hard limits (`BudgetGuard`). Never bypass either. - Public API responses contain no IP, city or ASN. - Code style is enforced at build time (`.editorconfig`, `BannedSymbols.txt`, warnings as errors). Details in [`docs/dev/coding-style.md`](docs/dev/coding-style.md). ## Where to change what | Task | Location | | --- | --- | | New measurement method | Kind declaration in `backend/shared/MoShiro.Protocol/Catalog/Kinds`; new building block only if needed in `MoShiro.Measurement/Blocks` plus `BlockCatalog` | | New metric | `MetricDef` in `backend/src/MoShiro.Backend.Analysis/Metrics`, add to `MetricRegistry.All` and a preset if shown | | New service model | `Analysis/Models` | | New RPC method | `MoShiro.Protocol/Rpc` (params, `MoShiroMethodTable`), then `router.On(...)` in `AgentApp`; Backend-side handlers register in `Backend.Gateway` (`FleetGateway`) | | New REST endpoint | `Backend.Api/Public` or `Admin` (typed results, operationId, capability), contract DTO in `Api/Contracts`, then regenerate `backend/openapi/v1.json` and web types | | New capability | `Capability` constants in `Backend.Application/Auth/Capabilities.cs`; every `/api/admin` endpoint must declare one | | Schema change | Append a migration in `Storage.Sqlite/Schema.cs` and bump `CurrentVersion` | | Agent-to-Agent connection states, retry cadence, health reporting | `backend/agent/src/MoShiro.Agent/Dial` (`DialConnection` control layer, `TaskLink` QUIC channel, `LinkStatus`), `LinkHealth` in `MoShiro.Protocol/Rpc`, [`docs/design/architecture.md`](docs/design/architecture.md) §4.3 | | Install or update behaviour | `packaging/` (install scripts, Quadlet, compose, updater) and `docs/ops/deployment.md` | | Web UI | `web/display` (anonymous read-only), `web/admin`, shared code in `web/shared`. Colors only in `web/shared/theme/tokens.css` | ## Documentation Index: [`README.md`](README.md#文档). Prefer the code and `backend/openapi/v1.json` when they disagree with a document, and fix the document. Update docs in the same change as behaviour: `docs/design` (architecture, protocol, measurement, analysis, storage, query), `docs/security`, `docs/api`, `docs/ops`, `docs/dev`, and `docs/roadmap.md` for unimplemented work. Do not record dates or change history in docs. Writing style for docs, READMEs, comments and commit messages (the `stop-slop` skill lists the patterns in detail; it is written for English, the same rules apply to Chinese): - State the fact directly. Drop "not X but Y" contrasts, negation lists, rhetorical setups, and aphorisms that read like pull-quotes. - Name the actor. Prefer "the Agent rejects the task" over "the task is rejected". - No filler openers ("it is worth noting"), no closing summaries, no adverbs doing emphasis. Avoid bold for emphasis. - Do not claim absolutes ("never", "always", "cannot") unless the code or a build-time check enforces it. Describe current behaviour and mark planned work as planned. - Give concrete names, paths, values and commands instead of general statements. ## Workspace safety - Inspect `git status` before editing. Preserve existing uncommitted changes; do not reset, clean, stash, or commit unrelated files. - `main` is the only working branch. Commit to it directly; use a pull request when review is required. - Never commit credentials, API keys, registry passwords, or generated runtime data. CI credentials are Woodpecker secrets (`zot_secret`, `gitea_token`, `release_signing_key`). - The release signing private key must not enter the repository or the panel. Only the public key under `packaging/update/` is versioned. ## Build and test Requirements: .NET SDK 10 (pinned by `global.json`) and Node.js with npm. NuGet versions are centralized in `Directory.Packages.props`. | Task | Command | | --- | --- | | Build all .NET projects | `dotnet build MoShiro.slnx -c Release` | | Backend tests | `cd backend && dotnet test --solution MoShiro.slnx -c Release` | | Run Backend | `cd backend && dotnet run --project src/MoShiro.Backend -- --urls http://localhost:5000` | | Web dependencies and build | `npm ci --prefix web && npm run build --prefix web` | | Web dev servers | `npm run dev --prefix web` (ports are set in the Vite configs) | | Style check | `npm run lint:css --prefix web` | | Regenerate API types | `npm run gen:api --prefix web` | First run of the Backend prints a claim code in its log; the admin UI asks for it. Slow end-to-end tests carry `[Trait("Category", "Slow")]`. After changing API contracts, update `backend/openapi/v1.json` and regenerate the web types. Run only the validation the task requires; do not start a full tag or release build unless requested. ## CI and releases Triggers, tags and image paths are defined in `.woodpecker/*.yml` and [`docs/ops/deployment.md`](docs/ops/deployment.md). Verify them there before changing or describing them. The rules below are the stable contract. - Every push to `main` runs the fast Backend tests and the web build. Both must pass before images are published. - A commit message containing `[CI]` builds and pushes development images. `[CI SKIP]` skips the pipeline; `[SKIP TESTS]` skips only the Backend tests. Slow end-to-end tests run after image publication and do not block it. - A tag `vMAJOR.MINOR.PATCH` runs the full cross-platform release pipeline. No version-bump commit is needed. - Versions are produced by `ci/version.sh`. The `` in `backend/Directory.Build.props` and the `version` in `web` `package.json` files are placeholders (`0.0.0-dev`) and must not be edited. - Linux Agent builds use `ci/build-linux-agent.sh` for glibc on amd64/arm64 and musl on arm64 in both dev and tag workflows. OCI and OpenWrt installers reuse these native outputs; Windows runners build only Windows/macOS. - Build stores keep NuGet cache mounts, retain image layers for 7 days, and clean temporary outputs under store locks (shared for native builds, exclusive for cleanup). Do not use `buildah prune` on these stores: it removes restore caches too. - Development images use the `moshiro-dev/` repository path and release images use `moshiro/`. A development build must never overwrite a release tag such as `latest`. - Release manifests are registered at `/api/release/offer`, which requires no token because the panel verifies the signature.