Rule Format¶
This page describes the JSON file that Rules → Export writes and Rules → Import reads. Use it to write rules by hand, review a shared rule before importing it, or give an AI assistant enough context to draft rules for you.
The full list of condition fields, with the operators and scopes each one accepts, is on Rule Fields. That page is generated from the rule engine, so it always matches the running version.
For what rules do and how to build them in the editor, see Rules.
File shape¶
An import file is a JSON array of rule objects. A single rule object without the array is also accepted.
[
{
"name": "Old unwatched movies",
"description": "Movies added more than a year ago that nobody has watched.",
"media_type": "movie",
"enabled": false,
"target_scope": "movie_version",
"definition": {
"version": 1,
"root": {
"type": "group",
"op": "and",
"children": [
{
"type": "condition",
"field": "media.days_since_added",
"operator": "greater_than",
"value": 365
},
{
"type": "condition",
"field": "watch.never_watched",
"operator": "is_true"
}
]
}
},
"action": {
"outcome": "candidate",
"arr_action": "delete",
"tag_enabled": false,
"auto_delete_enabled": false
}
}
]
Rule object¶
| Key | Required | Value |
|---|---|---|
name |
Yes | Display name. A name that already exists is imported as Name (imported). |
description |
No | Plain-text notes shown with the rule. |
media_type |
Yes | "movie" for movie_version rules, "series" for every other scope. |
enabled |
No | Defaults to true. Use false so the rule can be previewed before it runs. |
target_scope |
Yes | "movie_version", "series", "season", or "episode". |
definition |
Yes | The condition tree. See below. |
action |
No | What happens to matches. Omitted keys use the defaults below. |
Exported files can also contain id, created_at, and updated_at. Import ignores them.
Target scopes¶
| Scope | One match is |
|---|---|
movie_version |
One movie file. A movie with two files is evaluated twice. |
series |
A whole show. |
season |
One season of a show. |
episode |
One episode. |
Each field is only allowed in some scopes. Check the Scopes column on Rule Fields.
Definition¶
version is always 1. root is a group.
Group¶
| Key | Value |
|---|---|
type |
"group" |
op |
"and" (every child must match) or "or" (at least one child must match) |
children |
Non-empty array of groups and conditions. Groups can nest. |
enabled |
Optional. false turns the group off without deleting it. |
Condition¶
| Key | Value |
|---|---|
type |
"condition" |
field |
A field key from Rule Fields, such as media.size |
operator |
An operator the field accepts |
value |
The comparison value. Omit it for exists, not_exists, is_true, and is_false. |
enabled |
Optional. false turns the condition off without deleting it. |
A rule needs at least one enabled condition.
Operators¶
| Operator | value |
|---|---|
equals, not_equals |
One number or string |
greater_than, greater_than_or_equal, less_than, less_than_or_equal |
One number |
before, on_or_before, after, on_or_after |
One ISO date, such as "2024-01-31" |
in, not_in, contains_any, not_contains_any, contains_all, not_contains_all |
Array of strings |
contains_substring, not_contains_substring |
Array of strings (Arr tags only) |
matches_any_regex, not_matches_any_regex |
Array of regex patterns, matched case-insensitively |
exists, not_exists, is_true, is_false |
None. Omit value. |
Text comparisons ignore case.
Values that need care¶
- Sizes (
media.size,disk.free_bytes) are bytes, using 1024-based units. 50 GiB is53687091200. - Duration (
media.duration) is milliseconds. - Ratings have fixed ranges. Values outside them are rejected; see the Value notes column on Rule Fields.
- Per-user playback fields (
playback.user_watched_duration_minutes,playback.user_watched_percent) take an object:{"usernames": ["alice"], "amount": 90}. - Seerr requester IDs are written
"instanceId:userId", such as"7:3".
Install-specific values¶
Some fields and action keys refer to IDs or names that only exist on one Reclaimerr install. A rule that uses them will import, but it must be edited before it matches the right items elsewhere.
- Fields:
library.id,arr.movie_ids,arr.series_ids,seerr.requested_by_user_ids,playback.usernames,playback.fully_watched_usernames,favorites.usernames, and the per-user playback fields. - Action keys:
radarr_service_config_ids,sonarr_service_config_ids, andquality_profile_id.
A rule without a library.id condition covers every library of its media type. To limit it to some libraries, add the library in the rule editor after import.
Action¶
| Key | Default | Value |
|---|---|---|
outcome |
"candidate" |
"candidate" makes matches cleanup candidates. "protect" protects matches and ignores the rest of the action. |
arr_action |
"delete" |
"delete", "unmonitor", "unmonitor_only", "unmonitor_delete_monitor_new_seasons", "unmonitor_delete_list_exclusion", "unmonitor_delete_monitor_or_exclude", or "change_quality_profile" |
tag_enabled |
true |
Tag matches in Radarr/Sonarr |
arr_tag |
rule name | Tag text. Converted to a rec- slug. |
auto_delete_enabled |
false |
Run the action automatically when the review period ends |
auto_delete_delay_days |
null |
Review period override, 0 to 3650. null uses the global default. |
move_instead_of_delete |
false |
Move files to the configured destination instead of deleting them |
quality_profile_id |
null |
Required for change_quality_profile. Install-specific. |
trigger_search |
true |
Search after a quality profile change |
radarr_service_config_ids, sonarr_service_config_ids |
[] |
Limit the action to these Arr instances. Install-specific. |
Arr action limits:
unmonitor_delete_monitor_new_seasonsandunmonitor_delete_monitor_or_excludeare only allowed onseasonrules.unmonitor_delete_list_exclusionis allowed onmovie_versionandseasonrules. Sonarr requires an ended show and removal of the latest regular season before adding an exclusion.change_quality_profileis only allowed onmovie_versionandseriesrules, and needsquality_profile_id.
See Arr Action for what each action does.
Examples¶
Large, low-rated movies¶
[
{
"name": "Large, low-rated movies",
"description": "Movie files over 30 GiB with an IMDb rating under 6.",
"media_type": "movie",
"enabled": false,
"target_scope": "movie_version",
"definition": {
"version": 1,
"root": {
"type": "group",
"op": "and",
"children": [
{
"type": "condition",
"field": "media.size",
"operator": "greater_than",
"value": 32212254720
},
{
"type": "condition",
"field": "imdb.rating",
"operator": "less_than",
"value": 6
}
]
}
},
"action": { "outcome": "candidate", "arr_action": "delete" }
}
]
Ended shows nobody has played in a year¶
[
{
"name": "Stale ended shows",
"description": "Whole shows Sonarr marks ended, with no playback activity for 365 days or no recorded playback at all.",
"media_type": "series",
"enabled": false,
"target_scope": "series",
"definition": {
"version": 1,
"root": {
"type": "group",
"op": "and",
"children": [
{
"type": "condition",
"field": "sonarr.series_status",
"operator": "equals",
"value": "ended"
},
{
"type": "group",
"op": "or",
"children": [
{
"type": "condition",
"field": "playback.days_since_last_activity",
"operator": "greater_than",
"value": 365
},
{
"type": "condition",
"field": "playback.has_activity",
"operator": "is_false"
}
]
}
]
}
},
"action": { "outcome": "candidate", "arr_action": "unmonitor" }
}
]
Protect highly rated movies¶
[
{
"name": "Protect highly rated movies",
"description": "Never offer movies rated 8 or higher on IMDb for cleanup.",
"media_type": "movie",
"enabled": false,
"target_scope": "movie_version",
"definition": {
"version": 1,
"root": {
"type": "group",
"op": "and",
"children": [
{
"type": "condition",
"field": "imdb.rating",
"operator": "greater_than_or_equal",
"value": 8
}
]
}
},
"action": { "outcome": "protect" }
}
]
What import checks¶
Each rule in the file is checked on its own. A rule that fails is reported with its name and the reason, and the other rules still import.
Import rejects a rule when:
target_scopeis missing or unknown- a field or operator is unknown, or the operator is not allowed for that field
- a field is not allowed in the rule's scope
- a required
valueis missing, or a number is outside the field's range - a regex or path value cannot be parsed
- the action breaks an Arr action limit
Import does not check that a date string is a valid date, or that install-specific IDs exist. A wrong value there imports cleanly and never matches. Use Preview Matches in the rule editor before enabling an imported rule.
Writing rules with an AI assistant¶
- Give the assistant this page and Rule Fields, either as links or pasted text.
- Describe the rule in plain words: what to match, whether it is a cleanup or protection rule, and the scope (movies, shows, seasons, or episodes).
- Ask for a JSON array in the format above with
"enabled": false. - Save the reply as a
.jsonfile and import it with Rules → Import. Fix any errors the import reports. - Open the rule, add library or user selections if needed, and check Preview Matches before enabling it.
Sharing rules¶
Rules other users have shared are on Community Rules, along with how to add your own.