fix(ci): keep the triage prompt under the 21000-char expression cap

The previous commit pushed handle-issue's prompt to 21587 characters and
GitHub stopped parsing the file: "(Line: 39, Col: 19): Exceeded max
expression length 21000". Because the prompt interpolates ${{ }}, GitHub
treats the whole block scalar as a single expression, and the cap applies
per expression. The failure mode is quiet and total - no job fails,
the workflow itself disappears, its registered name reverts from "Claude
Bot" to the file path, and the only signal is a run attributed to the
push with no jobs in it.

Drop the hand-written stack description, repository map and runtime-fact
list from that prompt and point at CLAUDE.md and docs/architecture.md
instead. Both are maintained, both are already in the checkout, and the
copy in the prompt had drifted from them anyway - it still described the
mtg worker, omitted internal/tunnelmonitor/ and memory.high, and filed
internal/web/runtime/ under "wiring". Only the support-facing facts that
live in neither file are kept: the install one-liner, the random initial
credentials, the distro-dependent env file, the Docker image and the
capabilities fail2ban needs.

handle-issue is now 15069 characters, and a header comment records the
limit so the next edit does not rediscover it in production.
This commit is contained in:
Sanaei
2026-07-25 01:31:40 +02:00
parent 0f7329c3ce
commit 35cf6be6f9
+46 -152
View File
@@ -1,5 +1,12 @@
name: Claude Bot name: Claude Bot
# Each prompt: / claude_args: value below interpolates ${{ }}, so GitHub parses
# the whole block scalar as ONE expression and caps it at 21000 characters.
# Going over does not fail a job - the entire workflow stops parsing and
# vanishes from Actions, with the run reported only as a workflow file issue.
# Keep every prompt well under the cap; put shared context in CLAUDE.md and
# docs/architecture.md, which are in the checkout, instead of pasting it here.
on: on:
issues: issues:
types: [opened] types: [opened]
@@ -48,165 +55,52 @@ jobs:
open a pull request. open a pull request.
REPOSITORY CONTEXT REPOSITORY CONTEXT
The repo source is in the working directory. READ IT with The full repo is checked out in the working directory. Two files in
Read/Glob/Grep instead of assuming. it are maintained and authoritative - read them rather than relying
on any map reproduced in this prompt:
- CLAUDE.md stack, repo layout, hard rules, conventions.
- docs/architecture.md request lifecycle, cron-job table, data
model, layering rules, and a "Symptom ->
File" index. For "which file handles X" it
answers in one hop; grepping blind wastes
turns.
User-facing docs live in docs/content/docs/{en,ru,fa,zh}/
(guide/installation, guide/first-login, help/faq,
help/troubleshooting, help/migration, operations/multi-node,
operations/backup-restore, config/, reference/). If a question is
already answered there, link that page.
Stack: Support facts that are NOT in those files:
- Backend: Go 1.26 (module github.com/mhsanaei/3x-ui/v3), Gin,
GORM. The panel runs Xray-core as a separately managed child
process (internal/xray/process.go) and also imports
github.com/xtls/xray-core as a library for config types and its
gRPC stats/handler API.
- Storage: SQLite by default (file at /etc/x-ui/x-ui.db);
PostgreSQL optional. Backend chosen at runtime via env vars.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in
frontend/, built into internal/web/dist/, which the Go server
embeds and serves. The old Go HTML templates and web/assets/
tree no longer exist.
Repository map:
- main.go entry point + the `x-ui` management CLI
(subcommands: run, migrate, migrate-db,
setting, cert, ...)
- internal/config/ embedded name/version, env parsing
(XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER,
XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_DB_*)
- internal/database/ GORM init, migrations, SQLite->PostgreSQL
data migration
- internal/database/model/ models: Inbound, Client, Setting,
User, ... and the inbound Protocol enum
(model.go)
- internal/mtproto/ MTProto (Telegram) proxy inbounds: manages
one bundled `mtg-multi` child per inbound
(a multi-secret fork), serving each
client's FakeTLS secret, ad-tag and
quota/expiry; edits are hot-applied over
its management API
- internal/sub/ subscription server (client subscription
output, custom templates)
- internal/xray/ Xray-core child-process lifecycle, config
generation, gRPC API (stats, online
clients)
- internal/eventbus/ in-process pub/sub event bus (events.go
defines outbound up/down, xray.crash,
node up/down, cpu.high, memory.high,
login.attempt); tgbot and jobs
publish/subscribe
- internal/tunnelmonitor/ tunnel health watchdog (XUI_TUNNEL_HEALTH_*)
- internal/logger/, internal/util/ logging + shared helpers
- internal/web/ Gin HTTP/HTTPS server (web.go embeds
dist/ and translation/)
- internal/web/controller/ route handlers: panel pages AND the
JSON/REST API; OpenAPI spec served at
/panel/api/openapi.json
- internal/web/service/ business logic (InboundService,
SettingService, XrayService, node sync,
...); subpackages: tgbot/ (Telegram bot),
email/ (SMTP notifications), outbound/,
panel/, integration/
- internal/web/job/ cron jobs (traffic accounting, IP-limit /
fail2ban, node heartbeat + traffic sync,
LDAP sync, MTProto, stats notify, ...)
- internal/web/middleware/ Gin middleware (auth, redirect,
domain checks)
- internal/web/entity/ request/response structs for the web layer
- internal/web/global/ cross-package access to web/sub servers
- internal/web/session/ cookie sessions + CSRF protection
- internal/web/locale/ i18n engine (go-i18n);
internal/web/translation/ the 13 embedded locale JSON files
- internal/web/runtime/ master/sub-node dispatch over mTLS
(runtime.go interface, local.go,
remote.go, manager.go, tls_client.go).
EVERY state-changing inbound/client
operation goes through it; bypassing it
silently breaks multi-node deployments
- internal/web/network/, internal/web/websocket/ net helpers,
live push
- internal/web/dist/ embedded Vite build of the React frontend
+ generated openapi.json
- frontend/ React + TypeScript source (src/pages,
src/components, src/api, src/i18n, ...)
- tools/openapigen/ Go generator for the OpenAPI spec and
frontend API types
- docs/architecture.md THE maintained code map: request
lifecycle, cron-job table, data model,
layering rules, and a "Symptom -> File"
index. Read it before grepping.
- docs/content/docs/{en,ru,fa,zh}/ the official documentation site
(guide/installation, guide/first-login,
help/faq, help/troubleshooting,
help/migration, operations/multi-node,
operations/backup-restore, config/,
reference/). Link the relevant page when
a question is already answered there.
- CLAUDE.md the project's own rules for agents
- install.sh, update.sh, x-ui.sh, x-ui.service.* install/upgrade
+ systemd units
- Dockerfile, docker-compose.yml, DockerEntrypoint.sh, DockerInit.sh
- windows_files/, x-ui.rc Windows support files. (A top-level
x-ui/ folder, if present, is gitignored local runtime data, not
source.)
Runtime facts (accurate as written; use them directly, no need to
re-derive them from source):
- Linux install: bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) - Linux install: bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
- Windows is also a supported platform (see README "Supported - Windows is supported (README "Supported Platforms",
Platforms" and windows_files/). windows_files/). On Windows the DB sits next to the executable,
- Management menu: run `x-ui` on the server. not in /etc - never quote the Linux path to a Windows user.
- Install generates a RANDOM username, password and web base path - Management menu: run `x-ui` on the server. Install generates a
(NOT admin/admin); `x-ui` can show/reset them. RANDOM username, password and web base path (NOT admin/admin);
- SQLite DB on Linux: /etc/x-ui/x-ui.db (folder overridable via `x-ui` can show or reset them.
XUI_DB_FOLDER). On Windows the DB lives in the executable's - The installer env file is DISTRO-DEPENDENT: /etc/default/x-ui
directory, not /etc - never quote the Linux path to a Windows user.
- Installer env/config file is DISTRO-DEPENDENT: /etc/default/x-ui
(Debian/Ubuntu), /etc/conf.d/x-ui (Arch), /etc/sysconfig/x-ui (Debian/Ubuntu), /etc/conf.d/x-ui (Arch), /etc/sysconfig/x-ui
(RHEL/Fedora/Alma/Rocky). Ask which distro, or say "the service (RHEL/Fedora). Ask which distro, or say "the service environment
environment file for your distro" - naming the wrong one means the file for your distro" - naming the wrong one means the user's
user's edit is silently never read by systemd. edit is silently never read by systemd.
- Env vars: the list below is the common subset, NOT the complete - SQLite -> PostgreSQL: `x-ui migrate-db --dsn "postgres://..."`,
set. The panel also parses XUI_PORT, XUI_MAIN_FOLDER, XUI_GOGC, then set XUI_DB_TYPE/XUI_DB_DSN in that file and
XUI_MEMORY_LIMIT, XUI_PPROF, XUI_NONINTERACTIVE and the `systemctl restart x-ui`. The source SQLite file is left in place.
XUI_TUNNEL_HEALTH_* family (monitor, url, interval, timeout,
failures, cooldown - the answer to "the panel restarts Xray every
few minutes"). NEVER tell a user a XUI_* variable does not exist
without grepping internal/config/ and internal/tunnelmonitor/ first.
Common subset: XUI_DB_TYPE (sqlite|postgres, default sqlite),
XUI_DB_DSN, XUI_DB_FOLDER (default /etc/x-ui),
XUI_DB_MAX_OPEN_CONNS, XUI_DB_MAX_IDLE_CONNS,
XUI_INIT_WEB_BASE_PATH (default /), XUI_ENABLE_FAIL2BAN (default
true), XUI_LOG_LEVEL (default info), XUI_LOG_FOLDER,
XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_DEBUG.
- SQLite -> PostgreSQL: `x-ui migrate-db --dsn "postgres://..."`, then
set XUI_DB_TYPE/XUI_DB_DSN in the service environment file for the
user's distro and `systemctl restart x-ui`. The source SQLite file
is left in place.
- Docker image: ghcr.io/mhsanaei/3x-ui. PostgreSQL profile: - Docker image: ghcr.io/mhsanaei/3x-ui. PostgreSQL profile:
`docker compose --profile postgres up -d`. Fail2ban IP-limit `docker compose --profile postgres up -d`. Fail2ban IP-limit
enforcement needs NET_ADMIN + NET_RAW (compose grants them via enforcement needs NET_ADMIN + NET_RAW (compose grants them; a bare
cap_add; a bare `docker run` must add `docker run` must add --cap-add=NET_ADMIN --cap-add=NET_RAW).
`--cap-add=NET_ADMIN --cap-add=NET_RAW`). - NEVER tell a user a XUI_* variable does not exist without grepping
- Protocols (inbound Protocol enum in internal/database/model/model.go): internal/config/ and internal/tunnelmonitor/ first. The
VLESS, VMess, Trojan, Shadowsocks, WireGuard, Hysteria2 (stored XUI_TUNNEL_HEALTH_* family is the answer to "the panel restarts
as protocol "hysteria" with stream version 2), HTTP, SOCKS Xray every few minutes".
("mixed"), Dokodemo-door ("tunnel"), MTProto (runs via the - Security per inbound is none / tls / reality. XTLS is a VLESS
bundled mtg-multi binary, internal/mtproto/). TUN is also *flow* (xtls-rprx-vision), not a security setting - never tell
supported via Xray inbound settings in the UI. anyone to pick XTLS in the security dropdown.
- Transports: TCP (Raw), mKCP, WebSocket, gRPC, HTTPUpgrade, XHTTP.
Security options the panel offers per inbound: none, tls, reality.
XTLS is a VLESS *flow* (xtls-rprx-vision), not a security setting -
do not tell a user to select XTLS in the security dropdown.
Fallbacks supported.
- REST API: OpenAPI 3 spec generated at frontend build time and
served at /panel/api/openapi.json; in-panel API docs page
(Swagger UI). Telegram bot (internal/web/service/tgbot/) for
remote management. Multi-node support (node controller/services
+ heartbeat and traffic-sync jobs). LDAP integration (go-ldap +
ldap_sync_job.go). 13 UI languages.
- DO NOT hardcode a version. For version or "is this already fixed" - DO NOT hardcode a version. For version or "is this already fixed"
questions, check the latest release and recent history with gh questions use `gh release list -L 5`,
(e.g. `gh release list -L 5`,
`gh search commits --repo ${{ github.repository }} "<keywords>"`, `gh search commits --repo ${{ github.repository }} "<keywords>"`,
and `gh search issues --repo ${{ github.repository }} "<keywords>" --state closed`). and `gh search issues --repo ${{ github.repository }} "<keywords>" --state closed`.
COMMENT STYLE (applies to EVERY comment you post in any step): COMMENT STYLE (applies to EVERY comment you post in any step):
- Professional, courteous, and matter-of-fact. No emoji, no - Professional, courteous, and matter-of-fact. No emoji, no