# CLAUDE.md

This file provides guidance to Claude Code when working with this repository.

## Project Overview

The repository supports two independent operating modes:

- Server mode
  - Source: remote API
  - Main config: `config.server.json`
  - Main output: `runtime/`
  - Optional git automation: yes, via `runtime-state`
- Router mode
  - Source: local `cfst`
  - Python config: `config.router.json`
  - BusyBox shell config: `router_local.conf`
  - Main output: `cfip_runtime/`
  - Optional git automation: no

The old `config.json` and `config.example.json` are deprecated and should not be reintroduced.

## Common Commands

### Validate scripts

```bash
env PYTHONPYCACHEPREFIX=/tmp/pycache python3 -m py_compile scripts/domain_updater.py
env PYTHONPYCACHEPREFIX=/tmp/pycache python3 -m py_compile scripts/update_vmess_links.py
bash -n scripts/run_update_and_commit.sh
bash -n scripts/install_debian.sh
bash -n scripts/uninstall_debian.sh
sh -n scripts/router_local_update.sh
sh -n scripts/router_local_http.sh
```

### Run server mode once

```bash
python3 scripts/domain_updater.py --config config.server.json
```

### Run local cfst mode once

```bash
python3 scripts/domain_updater.py --config config.router.json
```

### Print resolved output paths

```bash
python3 scripts/domain_updater.py --config config.server.json --print-output-settings
python3 scripts/domain_updater.py --config config.router.json --print-output-settings
```

### Run server scheduler entrypoint

```bash
bash scripts/run_update_and_commit.sh config.server.json
```

### Force commit to runtime-state once

```bash
bash scripts/run_update_and_commit.sh --force-commit config.server.json
# or
GIT_FORCE_COMMIT=1 bash scripts/run_update_and_commit.sh config.server.json
```

### Update VMess links from selected value

Server mode:

```bash
python3 scripts/update_vmess_links.py \
  --input ./nodes.txt \
  --output ./nodes.updated.txt \
  --domain-file ./runtime/current_domain.txt
```

Router mode:

```bash
python3 scripts/update_vmess_links.py \
  --input ./nodes.txt \
  --output ./nodes.updated.txt \
  --domain-file ./cfip_runtime/current_ip.txt
```

### BusyBox router mode

```bash
sh scripts/router_local_update.sh ./router_local.conf
sh scripts/router_local_http.sh ./router_local.conf
```

### Debian systemd install/uninstall

```bash
sudo bash scripts/install_debian.sh --config config.server.json
sudo bash scripts/install_debian.sh --config config.server.json --interval 5min
sudo bash scripts/install_debian.sh --config config.server.json --git-push 0
sudo bash scripts/uninstall_debian.sh
sudo bash scripts/uninstall_debian.sh --keep-auth-files
```

## Testing and Verification

- There is no dedicated `tests/` directory yet.
- Primary verification is syntax checks plus manual script runs.
- `--print-output-settings` is the quickest way to verify output path resolution without performing a full update.

## Architecture

### 1) Unified Python updater

`scripts/domain_updater.py` is the shared core:

- Supports `source.type = "api"` and `source.type = "cfst_local"`
- Resolves output file paths from config instead of hardcoded runtime paths
- Writes four runtime artifacts:
  - selected value text file
  - selected value JSON file
  - state file
  - export vars file
- Supports fallback to the last good value from the configured state file

### 2) Server mode

`config.server.json` defines:

- API request settings
- parser / record mapping / record filter
- scoring and healthcheck behavior
- output paths under `runtime/`

`scripts/run_update_and_commit.sh`:

- Resolves output paths by calling `domain_updater.py --print-output-settings`
- Runs the updater
- Compares the selected value with `runtime-state`
- Syncs configured repo-local output files into the target worktree
- Commits and optionally pushes

### 3) Router mode

There are two router-side entry styles:

- Python local mode via `config.router.json`
  - still uses `domain_updater.py`
  - executes local `cfst`
  - parses CSV and writes `cfip_runtime/`
- BusyBox shell mode via `router_local.conf`
  - `scripts/router_local_update.sh`
  - `scripts/router_local_http.sh` prefers the configured full BusyBox binary (`BUSYBOX_BIN`, default `./busybox_armv7l`) and uses its `httpd` applet; ASUS/system `httpd` is not used automatically
  - intended for routers without Python

### 4) Sub-Store consumer

`substore/operator_template.js`:

- Fetches a JSON runtime endpoint
- Accepts either `domain` or `ip`
- Rewrites VMess `server` for matched nodes
- Uses `scriptResourceCache` with a short TTL

## Configuration Model

### `config.server.json`

Main blocks:

- `source`
- `api`
- `parser`
- `record_mapping`
- `record_filter`
- `domain_filter`
- `scoring`
- `healthcheck`
- `selection`
- `output`
- `v2ray`
- `notify`

### `config.router.json`

Main blocks:

- `source`
- `cfst_local`
- `domain_filter`
- `healthcheck`
- `selection`
- `output`
- `v2ray`
- `notify`

### `router_local.conf`

Main groups:

- `CFST_*`
- `TOP_N`
- `RUNTIME_DIR`
- `VALUE_*`
- `STATE_*`
- `EXPORT_*`
- `HTTP_PORT`

## Operational Notes

- Server mode is the only mode intended to update `runtime-state`.
- Router mode does not use git automation by default.
- `runtime/` and `cfip_runtime/` are ignored on `main`; runtime artifacts are meant to be ephemeral locally.
- Persistent `state.json` matters for fallback behavior in both modes.
- Avoid reintroducing hardcoded assumptions about `runtime/current_domain.txt`; use config-driven paths instead.
