Skip to content

Profile Transforms

Clash Nyanpasu 2.0 builds a runtime configuration from a configuration profile and its transforms. The older “proxy chain” wording refers to this profile transformation workflow. A transform reads the result produced so far and passes its output to the next step; it does not rewrite the source profile.

A configuration profile is a file profile or a composition profile that can be selected for use. A transform profile is a reusable operation and cannot be activated on its own.

Clash Nyanpasu provides three transform types 3 transform types:

  • YAML overlay (shown as Merge on some existing profiles) applies declarative merge rules.
  • JavaScript runs a script against the current configuration object.
  • Lua runs a script against the current configuration table.
  1. In Profiles, create a transform by choosing Merge (YAML), JavaScript, or Lua. A transform can use a local file or another supported profile source.
  2. Open a file or composition profile. In Profile transforms, move transforms from Available to Enabled.
  3. Drag enabled transforms into the order you want, then apply the change.
  4. To add transforms shared by the active configuration, use Global transforms in Profiles and set their order there.

A newly created transform is not enabled automatically. Scoped transforms run from top to bottom before global transforms, which also run from top to bottom.

For a composition profile, the app processes the optional base profile and each contributor with that file’s scoped transforms. It appends contributor proxies in the order listed, then runs the composition profile’s scoped transforms, followed by global transforms.

flowchart TD
    A[Selected file or composition] --> B[Scoped transforms in list order]
    B --> C[Global transforms in list order]
    C --> D[Application and core post-processing]
    D --> E[Generated runtime configuration]

The YAML source must have a mapping at its top level. Ordinary mapping keys merge recursively: nested mappings keep unspecified values, while scalars and sequences replace the matching value. A new key is added. This serves the same broad purpose as OpenClash’s merge-style configuration editing; the rules below describe Nyanpasu 2.0. Overlay directives operate on dotted paths and run in the order they appear in the YAML document.

Key Effect
append__path / append-path Add a sequence to the end of an existing sequence.
prepend__path / prepend-path Add a sequence to the beginning of an existing sequence.
override__path Replace the value at an existing dotted path.
filter__path Filter or transform items in an existing sequence with Lua expressions.

Append and prepend require a sequence as the directive value and an existing destination sequence. If the directive value is not a sequence, the path is missing, or the target is not a sequence, the operation is skipped with a warning. override__path also skips a missing path with a warning; it does not create one. These skipped-path warnings do not by themselves fail the candidate configuration.

This appends one rule and keeps the existing rules entries. The rules field must already be a sequence.

append__rules:
- DOMAIN-SUFFIX,example.org,DIRECT

filter__path requires an existing sequence. A string value is a Lua predicate evaluated once for each item: true keeps that item and false removes it. A filter mapping uses a when predicate and one action. A list of filters runs sequentially, with each operation receiving the previous operation’s output.

Keep every proxy except Trojan proxies. The expression must return a boolean.

filter__proxies: |
item.type ~= 'trojan'

For more cases, see the current overlay executor examples.

The JavaScript runner uses Boa and calls a default-exported function with the current configuration object. Its contract is main(config: ClashConfig): ClashConfig: ClashConfig describes the input and returned configuration; write executable JavaScript without TypeScript annotations. Like CFW Mixins or preprocessing, a transform edits a configuration and returns the result; the analogy does not imply script compatibility. The default export must return a mapping-compatible configuration, and a returned promise is awaited. If a promise remains pending for the runner’s short wait window (about two seconds), the transform fails. console.log, console.info, console.warn, and console.error are captured in the step logs.

This preserves the original two-rule example while checking that rules is an array before appending.

export default function main(config) {
const rules = ["DOMAIN-SUFFIX,google.com,PROXY", "DOMAIN,example.org,PROXY"];
if (Array.isArray(config.rules)) {
config.rules.push(...rules);
} else {
config.rules = rules;
}
return config;
}

The runner exposes selected pure Web APIs, but no general fetch() API. It can resolve local modules and HTTP(S) ES-module imports; downloaded modules are cached for up to 30 days. Only import remote modules you trust. See the JavaScript runner source.

The Lua runner uses Lua 5.4 syntax and the mlua ALL_SAFE standard-library preset. It exposes the current configuration as the global config; the script must return a table containing a mapping. Console output is captured in the step logs.

local rules = {
'DOMAIN-SUFFIX,google.com,PROXY',
'DOMAIN,example.org,PROXY',
}
if type(config.rules) ~= "table" then
config.rules = {}
end
for _, rule in ipairs(rules) do
table.insert(config.rules, rule)
end
return config

See the Lua runner source. For examples that add rule sets or proxy-group icons, see profile transform examples and the icon example; some fields in these examples depend on the selected core.

  1. Open Inspect from the Profiles sidebar.
  2. Switch between Latest build and Applied to core. The chip beside the switch shows the core and revision that was applied.
  3. Choose the list or graph view. The list draws the build as a branch line and groups the steps by stage: Source, Profile transforms, Global transforms, Nyanpasu, and Result. Turn on Only steps that changed something to hide the steps that left the configuration as it was.
  4. Select a step. Final configuration opens in Output; every other step opens in Changes, which shows its diff from the previous step. Output shows the YAML the step produced, and Logs shows what it logged. Core effective configuration is what the core reported back.
  5. Search for a field name, such as dns.nameserver, to find the steps that touched it.

To discard unsaved source edits, use Reset in the profile editor or choose Cancel and confirm discarding changes. To disable a transform, move it from Enabled to Available in the scoped or global transform editor and apply the change. To undo saved content, restore the desired transform source and save it.