[Feature Request] Automatic outbound selection group based on network environment
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 38.2k
- Forks
- 4.6k
- Avg merge
- 19d 15h
- Merged PRs (30d)
- 1
Description
Motivation
A common need on mobile (and not only) is to switch the default outbound based on the network environment rather than per-connection attributes: use direct on home WiFi, use a proxy on cellular, prefer a cheaper outbound on metered networks, etc.
This can partially be emulated today (route rules), but every existing approach falls short:
-
No manual override / no group semantics. With route rules (
wifi_ssid+final), the choice is buried in the rule list. It cannot be temporarily overridden from the Clash API or GUI clients, where selectors are the primary user-facing control, and it is invisible as a group. -
Rule duplication and inconsistency. Environment-based A/B switching is rarely needed for just one rule: the same environment conditions typically get repeated across multiple rules (per domain set, per app, per rule-set...), each rule restating its other conditions alongside the environment condition. The rule list becomes long, and keeping the duplicated parts consistent across edits is error-prone. With an environment-aware group, environment conditions disappear from the route rules entirely — every such rule just points to the same group. This is especially important for preserving the plain semantics of
final: today, "environment-dependent default" forces you to append environment rules that act as a conditionalfinal, polluting the rule list; with the group,finalstays a single unconditional tag. -
Needless per-connection re-evaluation. Environment conditions describe stable system state. With route rules, they are re-evaluated for every new connection even though they change rarely. An event-driven group that re-evaluates only on environment change (Wi-Fi state monitor, network type change — the event sources already exist) is both cleaner and cheaper.
-
Existing connections on environment change. When the environment changes, it is often desirable to handle already-established connections (e.g. drop connections that were bound to the old network). The selector's
interrupt_exist_connectionsprovides exactly this, triggered on outbound switch. Pure rule matching cannot do this at all: a rule change only affects new connections, while existing ones silently keep the old outbound.
Proposal
Two alternative implementations, whichever fits the architecture better.
Both are restricted to network-environment conditions only, and all of them are connection-independent (the choice must be stable rather than per-connection): network_type, network_is_expensive, network_is_constrained, wifi_ssid, wifi_bssid, interface_address, network_interface_address, default_interface_address, and logical combinations of these. Connection-dependent conditions (domain, ip_cidr, port, source_*, process_name, package_name, auth_user, inbound, protocol, ...) should be rejected at config validation. Non-network conditions such as clash_mode are intentionally excluded to keep the semantics of the feature focused.
Option A: extend selector
Let the user choose the selector's mode: auto (rules decide) or a manually selected outbound from the list. Whether selection is automatic is itself a user choice, persistent through the Clash API like any manual selection.
To make the semantics explicit, the current outbounds field is renamed to reflect manual selection, and the automatic behavior is encapsulated in an auto_select object. default now means the default mode ("auto" or a specific outbound tag), while the last-resort of automatic matching is auto_select.final, keeping the two concepts separate:
{
"type": "selector",
"tag": "select",
"manual_outbounds": ["proxy-a", "proxy-b", "direct"],
"default": "auto",
"auto_select": {
"rules": [
{
"wifi_ssid": ["Home-WiFi"],
"outbound": "direct"
},
{
"network_type": ["cellular"],
"outbound": "proxy-a"
}
],
"final": "proxy-b"
},
"interrupt_exist_connections": false
}
Semantics:
- The selector state is
autoor one ofmanual_outbounds; switching between them via Clash API works as today - In auto mode, rules are evaluated top-down on startup and on every environment change; first match wins, otherwise
auto_select.final - When auto mode switches the outbound,
interrupt_exist_connectionsapplies - Renaming
outboundsis breaking; a migration path (fall back to legacy field whenmanual_outboundsis absent) may be needed
Option B: new subnet outbound type
Add a new outbound type alongside selector/urltest that always selects automatically — the sing-box equivalent of Surge's Subnet policy group.
{
"type": "subnet",
"tag": "auto",
"rules": [
{
"wifi_ssid": ["MyHome"],
"outbound": "direct"
},
{
"network_type": ["cellular"],
"outbound": "proxy-a"
}
],
"final": "proxy-b",
"interrupt_exist_connections": true
}
- Rules are evaluated top-down on startup and on every environment change; first match wins, otherwise
final(required) - When the selected outbound changes,
interrupt_exist_connectionsapplies
Option A is more powerful (manual override within a single group, better GUI fit); Option B avoids touching existing selector semantics.
References
- Surge Subnet policy group — selects the policy by current network (
TYPE:WIFI/TYPE:CELLULAR/TYPE:WIRED,SSID:name,BSSID:mac, mandatorydefaultfallback) urltestas a precedent for an automatically deciding group in sing-box
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the existing selector and urltest outbound behavior, then trace the network-environment event sources and Clash API integration mentioned in the proposal. Compare Option A and Option B against config validation and connection interruption semantics; done means one coherent design supports stable environment-based selection, fallback behavior, and outbound switching when the environment changes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- networking
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100