Operations ​
An operation (op) is one data change your addon asks for: set a database field, replace a resource in an archive, add a string, register an asset group, copy a loose file, add a track. You don't write code for it. You list op files in the operations block of swofty.json, and every swofty build (and every Play) applies the ops of each enabled addon to a copy of the game's files, or hands them to swofty_core to apply in memory while the game boots. The game folder keeps its stock files.
An addon with only operations is a data addon. An addon with code can list operations too.
An operation file ​
An op file is JSON with a schema_version and a list of ops. Each op names its kind in op:
{
"schema_version": 1,
"ops": [
{ "op": "set", "select": "rules.stop_go_penalty", "field": "penalty_duration", "value": "10" }
]
}List the file under the field for its kind:
"operations": {
"database": ["db/changes.json"]
}| Field in an op file | Meaning |
|---|---|
schema_version | 1 |
ops | The ops, applied in order |
fields | Optional. For add-row: extra key names to copy, keyed by <table>.<row name>, or the only ones with copy: listed (Key names) |
strict | Optional. true fails the build on an add-row completeness warning (The completeness check) |
Every op takes two extras from your addon's db settings: {{id}} in any string is replaced with the setting's value, and "when": { "id": value } keeps the op only when each listed setting has that value.
The operations fields ​
| Field | Holds | Changes | Reference |
|---|---|---|---|
database | Op files of database ops, no prefix: set, add-row, put-record, remove-record | Records in gamedatabases.2025. | Database operations |
erp | Op files of ERP ops, no prefix: replace-resource, add-resource, copy-resource, put-resource, remove-resource, add-mipmaps, patch-pkg, warn | Resources in . archives | ERP operations |
assets | Op files that mix every kind, each op with a prefix: db., erp., lang., group., file., track., ... | Everything above, plus text, asset groups, loose files and tracks | Asset op files, Asset API |
files | [{ "source", "target" }] entries, no op file | Loose files in the game folder | File operations |
screens | [{ "name", "file", "flow", "anchor", "view_model" }] entries | New in-game screens, installed as swofty/ui/<name>. | In-game UI |
ui | *. patch files | Menus. Not built yet: the build skips them with a warning | UI patches |
A database file and an assets file with db. ops are the same model: the build adds db. to every op in a database file and erp. to every op in an erp file, then plans them together. Each files entry becomes a file.put. Choose assets when one file should change several kinds at once.
native sits in the same block but is not an operation: it names an engine plugin, a DLL with code that runs in the game. launcher, outside operations, names a launcher plugin, whose build hook can return ops of its own. An addon with either is a code addon.
Asset op files ​
In an assets file, the prefix before the dot names the kind:
{
"schema_version": 1,
"ops": [
{ "op": "erp.put-resource", "erp": "2025_asset_groups/f1_2026_vehicle_package/teams/toro_rosso/wep/toro_rosso.erp",
"resource": "eaid://f1_2026_vehicle_package/teams/toro_rosso/wep/toro_rosso.wep", "source": "erp/car.erp" },
{ "op": "db.set", "select": "entrants.teams.team[_metadata_=toro_rosso_26]", "field": "display_name_code", "value": "AT" },
{ "op": "lang.set", "language": "*", "key": "lng_team_tor_hashtag", "value": "AlphaTauri" },
{ "op": "warn", "message": "Racing Bulls livery" }
]
}| Kind | Ops | Changes | Reference |
|---|---|---|---|
db.* | db., db., db., db. | Game database records | Database operations |
erp.* | erp., erp., erp., erp., erp., erp., erp., erp. | Archive resources, and mip files in the game folder | ERP operations |
lang.* | lang., lang., lang. | In-game strings, in one language or all (*); new keys are added | In-game text |
group.* | group. | An asset group in the engine's asset manifest | Asset API |
file.* | file. | A loose file in the game folder | File operations |
track. | source: a folder holding an unpacked track package | A whole track: database rows, archive, menus, ERS | A track with its own name |
item. | id, name, optional author, version, description | A read-only tile in the in-game ADDON SETTINGS screen | Asset API |
warn | message | Nothing; prints the message at build |
db.remove-row is defined but not built: a build with one fails. A patch-pkg edit other than clone-entry and set-value makes the build skip every ERP op of that addon, with a warning.
An unknown op name or field fails the build and names the file.
Sources ​
A source is a path in your addon folder. To read from the addon's data or cache folder, give an object:
"source": "erp/car.erp"
"source": { "root": "data", "path": "library/my-mod/files/car.erp" }root is addon (the default), data ($DATA/addon-data/<id>/) or cache ($DATA/cache/addons/<id>/). A path that leaves its folder fails the build. See Sources.
Build route and runtime route ​
Each kind reaches the game one of two ways:
- Build route.
swofty buildwrites a changed copy of the game file into the overlay folder, and Play swaps it into the game folder for the session through the journal. - Runtime route.
swofty buildwrites the changes toswofty/assets.json, and swofty_core, the in-game loader, applies them in memory while the game boots. The game's files stay stock.
| Kind | Build route | Runtime route | With the in-game loader |
|---|---|---|---|
group | none | Registered when the engine parses its asset manifest | Runtime |
erp | The archive is rewritten | An overlay archive the game reads first | Runtime |
db | gamedatabases.2025. is rewritten | db_edits, applied as the database loads | Runtime |
lang | none | A string table added after the stock one | Runtime |
file | The file is copied into the game folder | Served from swofty/overlay/ | Build (runtime is experimental) |
- Without the in-game loader,
erp,dbandfiletake the build route, andgroupandlangops wait: the build lists them and the game doesn't see them. track.add,item.showandwarnhave no route: the build handles them itself.- Some changes force the build route: an
erp.remove-resource, a replaced resource whose layout differs from the stock one, and database edits the loader can't apply. - To force a kind onto the build route, add it to
"build_assets"in$DATA/config.json, for example"build_assets": ["db"]. To turn on the experimental runtimefileroute, add"runtime_assets": ["file"].
The full rules are in Deliveries.
Order and conflicts ​
A build applies ops in this order:
track.addops from every addon, in load order. Track activation clones the base track's database rows before any other database op runs.- Addons in the profile's load order.
- Within one addon: its
databasefiles, thenerpfiles, thenassetsfiles, each in the order listed, thenfilesentries, then the ops its build hook returns.
A later write to the same target wins. Replacing what another addon wrote counts as a conflict, and the build prints a line per pair of addons, the winner first:
warning: Scuderia AlphaTauri overrides Example Livery on 12 database values and 1 text string| Target | Replaced by | Composes with |
|---|---|---|
| A database record | db., db., db. | db. |
| A resource in an archive | erp., erp., erp. | erp., erp., erp. |
| A slice of a texture array | erp. | |
| A string in a language | lang. | lang., which never conflicts |
| A game path | file., erp. | |
| An asset group | group. |
To make your addon win, move it later in the load order, or name the other addon in load_after (manifest). See Order and conflicts.
Check what a build did ​
swofty build| Output | Meaning |
|---|---|
runtime: swofty/assets. | What goes the runtime route |
replace <path>, add <n> file(s) under <folder> | Game files the build route replaces or adds |
warning: <addon>: <message> | A warn op |
warning: <addon>: <n> lang op(s) wait for lang support in swofty_core | Ops with no route: the in-game loader is missing |
<addon>: <n> database values, <n> archive resources, <n> files, <n> text strings, <n> tracks | What each addon writes |
warning: <addon> overrides <addon> on <n> database values, ... | A later addon replaced targets an earlier one wrote; swofty conflicts lists them |
warning: conflict: <target>: <addon> (<item>) overrides <addon> (<item>) | Two items of one addon wrote the same target |
overlay <buildhash>: <folder> | The build's folder, with plan. and swofty/assets. |
A build that can't apply an op fails and names the addon and the cause, such as <select>: no row matches.
Reference ​
- Database operations, ERP operations, File operations, UI patches: each kind's fields.
- Asset API: asset op files, deliveries, what swofty_core does in game, and the native API.
- Changes at runtime: one worked example per runtime kind.
- Addon manifest: the
operationsblock among every otherswofty.jsonfield.