Skip to content
Agentmart
Submit a tool

CLAUDE.md · MHSanaei/3x-ui

CLAUDE.md from MHSanaei/3x-ui: 210 lines covering Stack, Repo map, Hard rules (non-negotiable), Tests: TDD, and only tests that can fail (Go and frontend) and…

Template by MHSanaei

IndexedGPL-3.0★ 48,503
Write a review

Chalk Labs

Need help deploying CLAUDE.md · MHSanaei/3x-ui?

Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.

Book a call

Install

Works with Claude Code. Read the repository before you give any tool access to your data.

curl -fsSL https://raw.githubusercontent.com/MHSanaei/3x-ui/main/CLAUDE.md -o CLAUDE.md

Read it and adapt it to your project before use.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

The CLAUDE.md file that MHSanaei/3x-ui (48,501 stars) keeps for coding agents. It has 210 lines in 8 sections: Stack; Repo map; Hard rules (non-negotiable); Tests: TDD, and only tests that can fail (Go and frontend); Go conventions; Frontend conventions (summary; full version in frontend/CLAUDE.md); Build, test, verify; Definition of done (before opening a PR). Use it as a model for your own project's instructions.

Use cases: prompt-engineering

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

What's in it

A CLAUDE.md file: project memory Claude Code loads at the start of every session.

For
Claude Code
Length
210 lines
File
CLAUDE.md

Sections

  1. Stack
  2. Repo map
  3. Hard rules (non-negotiable)
  4. Tests: TDD, and only tests that can fail (Go and frontend)
  5. Go conventions
  6. Frontend conventions (summary; full version in frontend/CLAUDE.md)
  7. Build, test, verify
  8. Definition of done (before opening a PR)

First lines (shown under the repo's GPL-3.0 license)

# CLAUDE.md

Operational guide for AI agents working in this repo. Long-form human docs:
`CONTRIBUTING.md` (setup, testing philosophy) and `frontend/README.md`.
Read those before large changes. This file is the short, must-follow version.
For a deep navigation map (request lifecycle, cron-job table, symptom → file
index, layering rules), read `docs/architecture.md` on demand — do not guess
file locations when it can answer in one hop.

## Stack
- Backend: Go 1.27 (`module github.com/mhsanaei/3x-ui/v3`), Gin, GORM.
  Runs Xray-core as a managed child process (`internal/xray/process.go`) and
  imports `github.com/xtls/xray-core` for config types + gRPC stats/handler/router
  API. MTProto inbounds run a second managed child — the `mtg-multi` binary
  (a multi-secret mtg fork — NOT a Go dependency; its prebuilt release binary is
  fetched at image/release build time by `DockerInit.sh` + `release.yml`,
  panel-side code in `internal/mtproto/`) — outside Xray, one process per inbound
  serving each
  client's FakeTLS secret via the fork's `[secrets]` section (plus per-client
  ad-tags via `[secret-ad-tags]` and per-client data quota / expiry via
  `[secret-limits]`, mapped from the client's `totalGB`/`expiryTime`). Client,
  ad-tag and quota/expiry edits are hot-applied through the fork's management API
  (`PUT /secrets`, bearer-token guarded) so connections survive; the manager
  falls back to a process restart on older binaries. A client's panel-side
  traffic reset also calls `POST /secrets/{name}/reset-quota` so a renewed client
  is not re-blocked by the sidecar's quota counter.
- Storage: SQLite by default (`/etc/x-ui/x-ui.db` on Linux; the executable dir on
  Windows), PostgreSQL optional (`XUI_DB_TYPE` / `XUI_DB_DSN`). The CGo SQLite
  driver (`mattn/go-sqlite3`) needs a C compiler — `CGO_ENABLED=0` builds fail.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`,
  built into `internal/web/dist/` (gitignored) and embedded via `embed.FS`.

## Repo map
- `main.go` — entry point + `x-ui` CLI (run, migrate, migrate-db, encrypt-tokens, setting, cert).
- `internal/config/` — env parsing (XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER,
  XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_PORT, XUI_DB_*).
- `internal/database/` + `internal/database/model/` — GORM schema (~24 models;
  Inbound, Client, Setting, User are the core), inbound Protocol enum,
  AutoMigrate + hand-written migrations in `db.go`.
- `internal/xray/` — Xray child-process lifecycle, config generation, gRPC API.
- `internal/xray/geodata/` — streaming geosite/geoip `.dat` reader (cached
  category index + paged entries) and `geosite:`/`geoip:`/`ext:` token parsing.
- `internal/mtproto/` — MTProto inbounds via the bundled `mtg-multi` binary.
- `internal/tuic/` — TUIC v5 inbounds: `tuic-server` sidecar supervisor, native Go UDP relay traffic metering.
- `internal/amneziawg/` — AmneziaWG protocol shape: instance/peer derivation
  from an inbound, 3.1 obfuscation param generation + validation, port-forward
  spec parsing.
- `internal/amneziawgnet/` — embedded AmneziaWG runtime: amneziawg-go device
  over a gVisor userspace netstack, per-inbound reconcile manager, TCP/UDP
  relay into a loopback per-peer-auth SOCKS5 Xray inbound, port-forward
  listeners, per-peer IPv6 egress aliases.
- `internal/pia/` — PIA WireGuard protocol client (auth, signed server list, `/addKey`).
- `internal/sub/` — subscription server (raw / JSON / Clash).
- `internal/eventbus/` — in-process pub/sub (outbound/node health, xray.crash,
  cpu.high, memory.high, login.attempt).
- `internal/logger/`, `internal/util/` (link, crypto, sys, ldap, …),
  `internal/tunnelmonitor/` — shared infrastructure.
- `internal/web/` — Gin server (embeds `dist/` + `translation/`).
  - `controller/` — panel + REST API handlers; OpenAPI at /panel/api/openapi.json.
  - `service/` — business logic (InboundService, SettingService, XrayService,
    node sync); subpackages tgbot/, discord/, email/, outbound/, panel/, integration/.
  - `job/` — 19 cron jobs (traffic, fail2ban IP-limit, node heartbeat/sync, LDAP,
    CPU/memory watchdogs, …); full table in `docs/architecture.md` §5.4.
  - `middleware/`, `entity/`, `global/`, `session/` (CSRF), `network/`,
    `runtime/` (master/sub-node over mTLS), `websocket/`.
  - `locale/` + `translation/` — i18n, 14 embedded locale JSON files.
- `frontend/` — React + TS source (see `frontend/CLAUDE.md`).
- `tools/openapigen/` — Go generator that emits frontend types + Zod/JSON schemas
  into `frontend/src/generated/` from Go structs. The OpenAPI doc itself
  (`frontend/public/openapi.json`) is assembled from those + `endpoints.ts` by
  `frontend/scripts/build-openapi.mjs`.
- `docs/` — separate Next.js/Fumadocs site (pnpm, own CI in `docs-ci.yml`,
  outside `make verify`). Holds a THIRD independent implementation of
  link/subscription generation in `docs/lib/xray/` — check it whenever
  share-link or install-command output changes.

## Hard rules (non-negotiable)
- Correct fix over small fix. Find the root cause and fix it the right way, however
  much code that takes. Size the change by what the correct fix needs, never by
  line count: when the right fix spans many files, or needs a migration, a shared
  helper or a new abstraction, write it. A guard that hides the symptom while the
  cause survives is the wrong fix, however small. Two limits remain:
  - Everything added must be something the correct fix needs. No speculative
    knobs, unused extension points or "while I was here" rewrites. Unrelated
    refactors and cleanups go in their own commit.
  - Stop and ask only when the right fix needs a decision the code cannot answer:
    a deliberate user-visible behaviour change, or two sound designs with a real
    trade-off. Ask with a recommendation. Size alone is never a reason to stop,
    defer or ship a smaller patch.
- Comments in committed Go/TS: 2 lines MAX per comment block. Make the name
  carry the meaning first and rename rather than annotate; spend the 2 lines on
  the *why* a name cannot hold — an invariant, an issue number, a non-obvious
  constraint. Exempt: `//go:build`, `//go:generate`, and other directives.
  HTML `<!-- -->` is fine. (A linter cannot enforce this — you must.)
- New `g.POST`/`g.GET` in `internal/web/controller/` REQUIRES a matching entry
  in `frontend/src/pages/api-docs/endpoints.ts`, then `make gen` (or
  `cd frontend && npm run gen`). Hand-maintained but pinned both ways by
  `TestRouteRegistryContract` (`internal/web/routes_contract_test.go`): a missing
  OR stale entry fails `make test-go`. Scope: `/panel/api/*` + a few session
  routes; sub-server routes are exempt.
- Response examples come from Go struct `example:` tags via `tools/openapigen` —
  never hand-write them. A new struct must be added to openapigen's `StructAllow`
  allowlist (`tools/openapigen/main.go`) or it is silently omitted from
  schemas/examples (and `build-openapi.mjs` then fails on the missing schema).
- A new or renamed endpoint has a FOURTH step: copy
  `frontend/public/openapi.json` → `docs/public/openapi.json`, then
  `cd docs && pnpm gen:api` to refresh the MDX under
  `docs/content/docs/en/reference/api/`. The `codegen` job and `make verify`
  fail on a stale copy, and `docs-ci.yml` fails on stale MDX.
- A new English i18n key goes in EVERY locale JSON in `internal/web/translation/`
  (14 files) AND must be referenced from `frontend/src` or Go in the SAME commit —
  `frontend/src/test/i18n-dead-keys.test.ts` fails both ways. It is a frontend
  test, so run `npm test`, not just `make test-go`. At runtime the frontend falls
  back to en-US; Go (`internal/web/locale/`) returns "" for an unknown key.
- DB / model changes require a migration in `internal/database/db.go`.
- Every state-changing inbound/client op dispatches through `runtime.Runtime`
  (`internal/web/runtime/`) — never straight to `internal/xray/api.go`, never from
  a controller or cron job. A direct call passes every local test and silently
  breaks every multi-node deployment. Other layering rules: `docs/architecture.md` §8.
- Conventional commits: `type(area): short imperative summary`, then a body
  explaining the why. Types in use: `fix`, `feat`, `chore`, `refactor`, `perf`,
  `docs`, `style`.

## Tests: TDD, and only tests that can fail (Go and frontend)
- Work red → green → refactor.
  - Bug: turn the reproduction into a test first, and watch it fail for the
    reported reason.
  - Feature: write the test for the first behaviour before writing its code.
  - Then write the code that makes it pass, and refactor with the suite green.

  If a test was written after the code, prove it anyway: revert the code, watch
  the test go red, then restore. A test that passes either way is worse than no
  test. It certifies nothing, and then gets cited as proof the fix works.
- Every test must name the failure it catches. When no test can reach a change
  (workflow YAML, pure wiring, layout), say so and name the command that
  demonstrates it. Never write a stand-in test.
- Fake tests are forbidden. Delete any you write or meet in the code you touch:
  - tests of a getter, a constant, a rename, a pure map lookup, or an input the
    function can never receive;
  - tests that restate the implementation, such as recomputing the expected
    value with the same formula or asserting that a mock was called exactly the
    way the code calls it;
  - mocking the unit under test, or mocking so much around it that the real
    code path never runs;
  - assertions too weak to fail: `err != nil`, `len > 0`, `toBeDefined()`, or
    `not.toThrow()` alone;
  - golden files or snapshots regenerated to match whatever the code now outputs;
  - extra cases that exercise no distinct branch, and tests written to raise
    coverage.

  One real test that drives the bug through the actual code path beats five
  that restate the code.

## Go conventions
- Stdlib `testing` only (no testify). Table-driven, `t.Run` subtests,
  `t.Helper()` on helpers. Assert the exact value / typed error / emitted
  string, never just `err != nil`. Prefer real deps over mocks: throwaway DB via
  `dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))`
  (`internal/database/dbtest`: copies a once-migrated template and registers
  `CloseDB` cleanup; a fresh `database.InitDB` costs ~7x more, ~850ms under

Signals

Stars
48,503
Forks
12,490
Open issues
183
Last commit (this folder)
Oct 24, 2026 (6 days ago)
Last release
Oct 14, 2026 (16 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
GPL-3.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

Done for you

Rather not set it up yourself?

Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.

See how we build AI agents →Read the case studies

Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.

launches shipped
50+
launches shipped
media placements
500+
media placements
founders on every account
2
founders on every account

Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block

Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.

Get CLAUDE.md · MHSanaei/3x-ui running in your business

Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.

Goes to the Chalk Labs founders, not the newsletter. Privacy

Need help deploying CLAUDE.md · MHSanaei/3x-ui?

CallGet help
Cite this page

CLAUDE.md · MHSanaei/3x-ui. Agent Mart. https://agentmart.dev/templates/mhsanaei-3x-ui-claude-md (last updated 2026-10-24)