# AGENTS.md ## Purpose This repo is a small Python Flask service that converts subscription links (`vmess`, `vless`, `trojan`, `ss`) into local SOCKS5 proxies via `xray-core`. Almost all backend logic, API routes, and the inline web UI live in `main.py`. Agents should prefer minimal, in-place changes over architectural rewrites. ## Repository Layout - `main.py`: app entrypoint, dataclasses, parsers, proxy manager, schedulers, Flask routes, and embedded HTML/CSS/JS. - `requirements.txt`: runtime dependencies. - `start.sh`: local bootstrap script. - `Dockerfile`: image build. - `docker-compose.yml`: recommended container run path. - `config.yaml.example`: optional config sample. - `config/`: persisted JSON state. - `data/`: runtime files such as generated xray configs. - `bin/`: xray binary/assets. ## Extra Agent Rules I checked for repo-specific agent instruction files: - `.cursor/rules/`: not present. - `.cursorrules`: not present. - `.github/copilot-instructions.md`: not present. There are no Cursor or Copilot rules to merge into this file right now. ## Environment - Python: README says `3.10+`. - Docker image: `python:3.13-slim`. - Default web port: `8080`. - App downloads `xray-core` on startup if `bin/xray` is missing. - Runtime state is persisted under `config/` and `data/`. ## Setup Commands ### Local environment ```bash python3 -m venv venv source venv/bin/activate pip install -r requirements.txt ``` ### Run locally ```bash python3 main.py ``` ### Run via helper script ```bash chmod +x start.sh ./start.sh ``` ### Build Docker image ```bash docker build -t airtosocks . ``` ### Run with Docker Compose ```bash docker-compose up -d docker-compose logs -f docker-compose down ``` ## Build, Lint, And Test Reality This repository currently has no formal lint or test setup. - No `tests/` directory was found. - No `pytest` or `unittest` test files were found. - No `ruff`, `black`, `isort`, `flake8`, `pylint`, `mypy`, `tox`, or `nox` config was found. Agents should say this explicitly instead of pretending a missing command exists. ## Verification Commands That Work Today ### Syntax check ```bash python3 -m py_compile main.py ``` ### Compile Python files ```bash python3 -m compileall . ``` ### Manual app run ```bash python3 main.py ``` ### HTTP smoke checks ```bash curl http://127.0.0.1:8080/api/links curl http://127.0.0.1:8080/api/subscriptions curl http://127.0.0.1:8080/api/random ``` ### Container smoke checks ```bash docker-compose up -d curl http://127.0.0.1:8080/api/links docker-compose logs --tail=200 docker-compose down ``` ## Single-Test Guidance There is no real single-test command yet because there is no test suite. If tests are added later, prefer `pytest` and document commands like: ```bash pytest pytest tests/test_parser.py pytest tests/test_parser.py::test_parse_vmess ``` Until then, a “single test” means a targeted manual verification of the exact parser, route, or runtime behavior touched by the change. ## Config Notes Optional runtime config lives in `config.yaml` and currently supports: ```yaml port: 8080 check_interval: 600 ``` When changing config behavior: - Preserve compatibility for missing keys. - Keep defaults aligned across code, `README.md`, and `config.yaml.example`. - Do not silently rename config fields. ## Code Style The repo does not use an autoformatter today. Match the existing style unless the user asks for cleanup. ### Imports - Keep standard library imports before third-party imports. - Do not reorder the whole import block for cosmetic reasons. - Add new imports near related imports. - Prefer explicit imports over wildcard imports. ### Formatting - Follow normal Python/PEP 8 conventions without broad reformatting. - Use 4-space indentation. - Preserve surrounding quote style; Python code here mostly uses single quotes. - Avoid reflowing large inline HTML, CSS, or JS unless required. - Keep diffs small and local. ### Types - Continue the existing `typing` style: `Optional`, `List`, `Dict`, `Tuple`, `Any`. - Add type hints for new helpers when practical. - Use `@dataclass` for record-like state models. - Do not introduce a new validation or typing framework without a concrete need. ### Naming - `snake_case` for variables, functions, and methods. - `PascalCase` for classes. - `UPPER_SNAKE_CASE` for module constants. - Use descriptive domain names like `subscription_id`, `socks_port`, `last_check`, `available_count`. ### Data Modeling And Persistence - Persist structured state through dataclasses and `asdict(...)`. - New persisted fields need safe defaults so old JSON continues to load. - Consider compatibility with existing files in `config/`. - Do not casually rename persisted fields. ### Error Handling - Follow the existing pattern: catch failures near parsing, file I/O, network calls, and subprocess operations. - Use `logger.error(...)` or `logger.warning(...)`, then return a safe fallback or JSON error. - Avoid crashing daemon threads for recoverable problems. - Prefer specific exceptions when obvious, but broad `except Exception as e` is already common here. - API handlers should return meaningful JSON error payloads with sensible HTTP status codes. ### Logging - Use the module-level `logger`, not `print`. - Keep log messages short and operational. - Include useful identifiers such as node name, subscription name, or port. - Do not log secrets or full credentials from proxy links unless absolutely necessary. ### Concurrency And Shared State - `ProxyManager` protects mutable state with `threading.RLock`; preserve that discipline. - Be careful when changing `nodes`, `subscriptions`, `pools`, `used_ports`, or `xray_processes`. - Keep background threads daemonized when matching the current pattern. - Do not introduce async or heavier concurrency models for small tasks. ### Files, Processes, And Runtime Data - Runtime files belong under `config/` or `data/`. - Keep xray config generation deterministic and JSON-serializable. - Follow the existing `subprocess.Popen(...)` pattern for xray processes. - Release ports and clean up subprocess state on failure paths. ### Flask And API Conventions - Keep Flask route handlers thin. - Put behavior in `ProxyManager` or small helpers rather than in the route body. - Return `jsonify(...)` for API responses. - Validate request JSON defensively. - Keep API response shapes stable unless a breaking change is explicitly requested. ### Frontend Conventions - The frontend is intentionally inline inside the `/` route. - For small UI changes, edit the embedded HTML/JS directly instead of adding a frontend build system. - Preserve the current fetch-based interaction pattern. - Keep the existing visual language unless the task asks for redesign work. ### Comments And Docs - Existing comments/docstrings are short and often Chinese; match the surrounding language in touched code. - Add comments only when behavior is not obvious from the code. - Update `README.md`, `config.yaml.example`, and this file when commands or behavior change. ## Change Strategy For Agents - Prefer surgical edits. - Avoid splitting `main.py` into modules unless explicitly requested. - Respect persisted data compatibility. - Ignore unrelated runtime files unless the task specifically involves them. - If you add tests or lint tooling, immediately document the new commands here. ## Recommended Post-Change Checks For most Python-only changes: ```bash python3 -m py_compile main.py ``` For API behavior changes: 1. Start the app with `python3 main.py`. 2. Hit the affected endpoint with `curl`. 3. Confirm there is no traceback and the response shape is correct. For Docker-related changes: ```bash docker build -t airtosocks . docker-compose up -d curl http://127.0.0.1:8080/api/links docker-compose down ```