Skip to content

Latest commit

 

History

History

addon

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

addon/: the Everloot collector

The in-game addon for WoW: Forever. It records what you see while you play (sightings, loot windows, vendors, full auction-house scans you start, recipes, trainers, your own gold, the world position of each zone you enter) into its SavedVariables file, shows /ask answers from the Everloot Desktop App, and adds auction prices to item tooltips. It uses only the game's addon API and never plays the character. Records match the upload contract (packages/protocol, see its schema/records/) field for field.

Status: 0.3.21 Alpha. The automated contract tests pass; live-client rendering of the Everloot window's tabs, crest, fonts and interactions remains unverified. The in-client checks in docs/2026-10-08-beta-client-checklist.md, docs/2026-10-18-addon-0.3.2-beta-checklist.md, docs/2026-10-19-addon-0.3.3-beta-checklist.md and docs/2026-10-21-addon-0.3.10-launch-checklist.md are still open, and the full scan (docs/design/specs/2026-10-16-forever-market-design.md) has not run in the Forever client.

Run it

Download the zip from everloot.app/addon, or build it from the repository root:

python scripts/package-addon.py

That writes web/public/downloads/Everloot-<version>.zip. Extract Everloot/ into the Forever client's Interface/AddOns/, /reload, then run /everloot status. Login and /reload print one line (the version, how many modules are on and off, any that could not start and any paused collection); /everloot status lists every module and row count. Auction capture is on in a new install (/everloot auctions off turns it off). At the auction house, open the Everloot tab after Blizzard's tabs and click Scan this house (or type /everloot scan) for a full scan: at most one every 15 minutes, read in chunks, summarised per item, and the last three scans per realm kept. Nothing scans without that click. The tab shows the cooldown, whether the last scan is in your saved file yet, a Share now button (a /reload, which writes the file so the Desktop App can send it) and a price lookup with the tooltip's lines. If the tab cannot be added, an Everloot scan button takes its place. The list of your installed addons is off until /everloot addons on; it is sent only from the upload page, after its preview. /everloot addons off stops it and deletes every recorded addon row.

A replication scan that cannot start or times out now tries a partial price sample, when the client's search APIs are available. It reads actual item/commodity search rows for at most 20 browse keys and 40 requests, paced at least one second apart and within 90 seconds of starting. It stops when the house closes or auctions are disabled. Empty attempts refund the cooldown; successful samples retain it. The sample is not a full-market snapshot and does not populate the full-scan cache. Before a sample stores, only the newest earlier sample of that realm stays in the file, so samples do not fill the per-kind row cap.

Profession observations retain the API's recipe ID and learned flag when available. A client with a complete-list reader uses it; otherwise the status explicitly says filtered recipe list. The addon never changes the player's filters. Up to 500 recipes are read in chunks; reaching that cap is reported. Only learned recipes are written (the status counts the others). For each recipe and colour the file keeps the lowest and the highest rank it was seen at: the highest is written when the colour changes, or at the first logout or reload on a new UTC day, so levelling a profession adds a few rows per recipe, not one per skill point or per reload. Disabling professions stops queued chunks. Tooltip prices show the item's newest public observation day separately from when the price file was built, and warn when either is old. Community values combine all auction houses on the realm; they are recorded asking-price estimates, not live listings or guaranteed sale prices. Below the prices, the tooltip shows where the item drops when three installs looted the source: each rate as drops of loot windows, with its installs and the date of the uploads behind it, from the drop rates the Desktop App writes into the same EverlootPrices file. Once that file is in the game, a missing price or drop source is said in one muted line; nothing is written to your SavedVariables. Without the file, tooltips carry no community line, and the first item tooltip says once per install, in chat, that community prices come from the Everloot Desktop App (everloot.app/addon). addon/tests/drops_contract.py holds the rules. Nothing in the addon calls a buy, bid or post API; addon/tests/market_contract.py traps them.

Price tooltips use separate label/value rows with native coin icons. Community market, minimum and historical values stay distinct from your own scan; the vendor sell price appears beside them when the client knows it. The amounts are per unit. The header names your realm with its ruleset (PvP, PvE, RP, RP-PvP, Hardcore) split off the name in its own colour, as the realm list shows it; drop rates sit in the value column too, their loot windows and installs beneath. A source you have met is named as your client showed it ("Drops from Defias Bandit"), read from your own sightings and loot in the saved file; one you have not met keeps its id ("NPC 116"). Dates, units listed, reporters, all-house scope and stale-data warnings remain visible. /everloot price prints the same amounts as plain text. Disenchant outcomes and values are not yet available; the addon does not guess them from an item's color or type.

Ask about an item's price

  • For an immediate answer from the files already in game, type /everloot price followed by a shift-clicked item link or item id. This works away from the auction house too. Your own scan can supply a value before the community has enough observations.
  • For an online recorded-market answer, type /ask price followed by an item link or id. New questions include your current realm; you can name another explicitly, for example /ask price 2589 on Nightslayer. An item name works when Everloot can resolve it uniquely. Otherwise, the answer asks for an item id.
  • Keep the Desktop App running with Ask enabled. /reload or log out to write the question; after the app processes it, /reload again to load the answer. This is a file bridge, not live in-game internet access. If a later load still has no answer for a question, the addon says once that no answer arrived and to open the Desktop App with Ask turned on (everloot.app/addon), then /reload. The question stays saved until it is answered.
  • Price questions need no AI model key. Answers identify the realm, all-house scope, recorded values, observation day and missing data. A missing local cache row does not prove the website lacks a price; the local community file holds at most 2,000 items. Full history is on everloot.app/tools/auctions.

Each scan records your faction (faction) and which house it read (house): Alliance or Horde from the auctioneer's faction, Neutral for a goblin house whose auctioneer has none, and nothing when the client gives no auctioneer to read. The game files list separate Alliance, Horde and Blackwater (neutral) houses with different cuts, so the site keeps a market per house next to the realm-wide one.

When scans are on, the cooldown is over and no scan is running, opening the auction house shows a small Scan prices for Everloot prompt beside it, once per visit. One click scans; closing it hides it until the next visit. It never scans by itself. /everloot scanprompt off turns it off (the Everloot scan button and /everloot scan still work). With scans off, the first visit prints one line saying how to opt in.

NPC and quest facts

When you target an NPC the addon also notes its creature type and rank, and when you accept a quest it records the quest's title, level, quest log header (category), suggested group size, tag, giver and your faction (Alliance or Horde, no name).

For the world map, an NPC window (merchant, gossip, quest, trainer, flight map, bank, auction house, stable, innkeeper) records where you stand as that NPC's place (positionKind = "interaction") with a role for the service, once per NPC, role and zone. Targeting still records positionKind = "player", which never becomes a pin. Looting an object adds where you stand (mapId, x, y), a gatherKind (herb, ore, chest, fishing, other) from the spell you cast just before (UNIT_SPELLCAST_SENT) and the object's name from that cast's target (sourceObjectName). Trainer rows carry trainerNpcId. Targeting rows are kept once per NPC, zone and spot (rounded to 1 on the 0..100 scale). Window rows and object loot rows each have their own 2,000-row cap, apart from targeting rows and creature loot, so /everloot status can show npc_sighting (targeting) paused while windows still record. A rare or a treasure the minimap shows (C_VignetteInfo) is recorded at its own position, as the vignette API gives it: a creature as an npc_sighting with positionKind = "vignette" (its own share and cap), a game object as an object_sighting, once per vignette, zone and spot. Zoning into a dungeon or raid records an instance_entrance: the instance from GetInstanceInfo and where you stood outdoors when the loading screen started (PLAYER_LEAVING_WORLD), once per instance and zone; a dungeon finder teleport records none. A boss fight's end inside one (ENCOUNTER_END) records an encounter: kill or wipe, difficulty, group size and the bosses' creature ids when the client sends them, and with ENCOUNTER_START seen, when the pull started and how many seconds it took. Each dungeon or raid run with a boss pull is one instance_run row: when you entered and left, the first pull, the last kill, pulls, kills and wipes, and the bosses killed. A run survives a reload, a corpse run or a trip out; it ends after 30 minutes outside, in another instance, at the game's reset line, or when a boss it already killed is pulled again; only time outside counts toward the 30 minutes. No names (docs/design/specs/2026-11-02-pull-and-run-records-design.md). The start, length and runs, like the boss pulls below, wait on E.RUN_RECORDS in core.lua: off until the release that ships them, so a nightly writes encounter rows as before. None of these has run in the Forever client yet. Forever's client uses the modern UI: on launch night 0.3.16 recorded no quests and no vendors, because QUEST_ACCEPTED carries only the quest id there and the old GetQuestLogTitle and GetMerchantItemInfo are missing. Quests are now read with C_QuestLog.GetLogIndexForQuestID and C_QuestLog.GetInfo, and vendor prices with C_MerchantFrame.GetItemInfo, as the build's API documentation and its own merchant window do; clients with the old calls keep them. A call that is missing or returns something unexpected records nothing for that field. The site shows each value only after 3 installs agree.

When the game shows you an item's tooltip, modules/itemfacts.lua records the numbers the game files do not hold: armor, block, damage per second, each stat and each resistance, one item_fact row per line with the item id, the number and the client build. It reads them with GetItemStats on the plain item from GetItemInfo, so an enchant or a random suffix on your copy never counts, and a tooltip whose GUID is not an item's records nothing. Each item is read once per client build; an item with no numbers is read once per session and not kept. It follows the open-world toggle and shares the 2,000-row cap. Not yet run in the Forever client.

Gold per hour

/everloot gph start begins a session and opens a small window you can drag; gph pause stops the clock (gph start resumes), gph stop saves the session, gph reset throws it away, gph show and gph hide open and close the window, gph history prints the last five, gph cut on|off sets the auction cut.

  • It counts, while running: items you loot (the game's "You receive loot" lines, so other players' loot, quest rewards, purchases and crafts are left out), money you loot or get as your share of group loot, quest money (QUEST_TURNED_IN), and what you sell at a vendor. A reload or logout pauses the clock and the session resumes when you are back; after a crash it waits, paused.
  • Each item is valued from the Everloot market value on your realm (the file the Everloot Desktop App writes), else your own last full scan, else the vendor price, and the window says which. With the cut on (the default) 5% is taken from market and scan values, as the faction houses take it.
  • Total = item values + looted money + quest money. Vendor sales are shown apart and not added: the items sold are already in the item values.
  • The window shows the clock, total, gold per hour, the value by source, the top five items and the zone.

Sessions are personal. They live in EverlootDB.gph, not in EverlootDB.records, so no uploader reads them and nothing is sent. The last 50 finished sessions are kept in EverlootDB.gph.sessions, oldest first, each:

Field Meaning
v Shape version, 1.
character, realm The character that ran it (kept in your file only).
startedAt, endedAt UTC, YYYY-MM-DDTHH:MM:SSZ.
seconds Time the session ran, pauses left out.
zone, zones The zone it started in, and every zone entered, in order (at most 10).
money { loot, quest, vendor } in copper.
items { itemId, count, unit, source } per item, most valuable first. unit is copper per item after the cut; source is market, scan, vendor or none. At most 200 items.
itemValue, total, perHour Copper. total is itemValue + money.loot + money.quest.
cut The auction cut taken from market and scan values: 0.05, or 0 when off.

The running session is EverlootDB.gph.current (item counts in counts, by item id); EverlootDB.gph.cut holds the cut setting.

Completion tracker

Off until /everloot completion on (then /reload). It reads your achievements, reputation, titles and completed quests with the calls Forever's own windows use, in chunks across frames, and waits out combat. /everloot completion reads now; /everloot completion off deletes every row it wrote. It never tracks, expands, clicks or changes anything.

  • Catalog rows (achievement_catalog, reputation_catalog, title_catalog, quest_chain_catalog): ids, names, criteria text, standing headers and quest ids. No player data. The site lists an entry after 3 installs report it identically.
  • Owned rows (achievement_owned, reputation_owned, title_owned, quest_owned): your character's progress under an 8-digit key made from your install id and the character's GUID, never the name. They leave this file from the upload page, with the collection choice ticked and a verified grant, or through the Desktop App's private sync described below.
  • Character rows (profession_owned, lockout_owned, talent_owned): your professions, this week's raid lockouts and the talent build of your active spec group, under the same key. They are never part of an upload file. The Everloot Desktop App's private sync sends these own-character rows (professions, raid lockouts, the active talent build) only for a character you linked: the app sends that character's rows and everloot.app keeps only the categories you switched on. Each read replaces this character's row, a build with no spent points writes none, and /everloot completion off deletes them with the rest. The anonymous talent_snapshot of the talents module is unchanged.
  • Character sheet row (stats_owned): the numbers the character sheet shows (attributes, attack power, hit, crit, haste, expertise, spell power, healing, armor, defense, dodge, parry, block), one row per character under the same key, read out of combat. Percent stats are rounded to 2 decimals and the rest to whole numbers; a stat the game will not give is left out, and with fewer than the five attributes there is no row. Never part of an upload file; the Desktop App's private sync sends it for a linked character and everloot.app keeps it only if you switched on that category; /everloot completion off deletes it.
  • PvP row (pvp_owned): the PvP rank (renown on Forever's PvP rank faction: rank, points, next-rank threshold, top rank), the season and lifetime honorable kills from the Statistics tab, one row per character under the same key. Whole numbers only, no rank title; a field the game will not give is left out, and with neither a rank nor honorable kills there is no row. A read made before the statistics load keeps the character's last kill count. Never part of an upload file; sent and kept the same way as the stats row; /everloot completion off deletes it.
  • A changed achievement or standing replaces its earlier row. Titles and completed quests are additions.
  • The file stays bounded: at most 1500 achievements read, 600 progress rows per character, and about 3 MB of completion rows and remembered ids in all. A limit reached stops recording, says so once in chat that session, and /everloot status says which one.
  • Combat (PLAYER_REGEN_DISABLED or InCombatLockdown) pauses a read between frames; it picks up when combat ends. /everloot completion off also stops a read that is under way.
  • The reputation list is the rows the reputation window shows now; a collapsed header hides its factions and the module never expands one. /everloot status says how many headers were collapsed.

Settings

Esc > Options > AddOns > Everloot, or /everloot options, lists every module with a switch: what it records and where it goes. A switch that has a /everloot command runs that command, so the page and chat always agree. Changes apply after a reload; the page has a Reload now button. A client without the game's options API shows the page as a window instead.

The Everloot window

Left-click the minimap button, or /everloot window, for the Everloot window. Its sidebar has five items.

  • Home lists every character this install has seen: gold, level, professions, raid lockouts (shown only while the completion tracker is on) and when it was last seen, with totals for each realm and for the account and a "This week" line (gold in and out for this character over seven days). Below it, the gold per hour session with a Pause button.
  • Gold has four tabs. Overview shows every character's gold by realm and the last 30 days as bars. Ledger lists the money events by category, by day or by receipt. Sales lists auction sales one by one or by item. Session is the gold per hour session. Ledger and Sales can be set to today, 7 days, 30 days or all; Overview always shows the last 30 days. Overview, Ledger and Sales can be set to this character or the account; Session has neither.
  • Collection shows this character's achievements, reputation, titles and raid lockouts from the rows the completion tracker wrote, so it needs /everloot completion on; with it off the tab says so and has a button that runs that command.
  • Professions shows each profession in the profession book with its rank and the recipes recorded for it by difficulty colour.
  • Settings opens this page. "What you've added", the row counts in your saved file, is on that page now.

Ask, Build plan and Auctions are no longer in the sidebar. /ask and /everloot plan (the planner workspace) still work.

The Gold tab and the character list on Home read two tables that exist only in your SavedVariables file. EverlootDB.roster holds one row per character you log in with (name, realm, class, level, faction, gold while the gold module is on, professions); the Your characters row in the options turns it off. EverlootDB.ledger holds your money events, your auction sales and each character's closing gold for each day, kept per character: up to 5,000 events and 90 days, 2,000 sales and 400 daily closes, the oldest dropped first. For days before the ledger existed, the Gold tab also reads the older money_event rows from the file, without copying them. Neither table is a record, neither is read by an upload, and nothing in the window uploads anything. An auction sale is recorded when you collect its letter at the mailbox, from the invoice: item name, count, the price after the auction house's cut and the deposit. The buyer's name is never read.

When the game says a buyer was found, Sales lists the item at once as "sold, gold pending". Collecting the letter turns that row "paid" with the price; a row with no letter after 48 hours reads "unmatched", and a letter collected later still fills it. The ledger also records repairs and vendor purchases at an open merchant (a repair paid from the guild bank costs you nothing and is left out), gold traded with another player (Trades in, Trades out), gold sent with a letter (Mail out) and gold in a letter from one of your own characters (Mail in). A letter from anyone else, or the auction house's own letter, adds no Mail in row. Gold that goes from one of your characters to another is marked as such: with the account selected it leaves the totals and shows on its own line, "Moved between your characters"; with one character selected it counts as that character's gold in or out. The trade partner's and the letter's names are compared with your own characters' names and then dropped. These categories are local only and never uploaded. Today, 7 days and 30 days start at UTC midnight (today, today and the 6 days before it, today and the 29 days before it).

The window is built the first time it opens and registers no events, so recording never depends on it. An error inside it closes it until /reload and /everloot status names the error. The Everloot window switch on the settings page turns it off; the minimap button then opens the plan workspace as before. The crest it uses is media/crest.tga, which the release zip carries beside the code.

Hovering the minimap button shows what its clicks do. The Minimap button switch on the settings page hides it after a /reload; /everloot window still opens the window.

The minimap button also holds other addons' minimap buttons. Buttons made with LibDBIcon (most addons' round minimap buttons) move into it at login; hover the crest and they show in a small panel beside it, which closes when the mouse leaves. Its clicks stay the same. Blizzard's own minimap buttons and any other button are left where they are. The first time it gathers a button, chat says how many. /everloot buttons off, or the Addon buttons in the Everloot button switch on the settings page, turns it off; the buttons go back around the minimap after a /reload.

Census

On in a new install, which says so once in chat; an install from before the census keeps it off until /everloot census on (then /reload). It counts who plays what: race, class, level and faction, never a name. It leaves your computer from the upload page, or from the Desktop App if you allowed the census there. /everloot census says whether it is on and how many rows it holds; /everloot census off stops it at once and deletes every row it wrote.

  • Your own characters (census_self): at login and at each level-up, your character's game id (GUID), race and class tokens (UnitRace and UnitClass second return, e.g. Scourge, HUNTER), level, faction and realm.
  • Players you see (census_seen): the same fields, without the realm, for players you target, mouse over or group with, plus how you first saw them that day (target, mouseover or group). Units with a hidden level, no race, class or faction, or a GUID that is not a player's are skipped, and so are you.
  • Nothing else is read about another player: no name, guild, gear or position. addon/tests/census_contract.py fails if census.lua names a call that could read them, and lists every call the module may make.
  • One row per character per UTC day, with the latest level that day. At most 2,000 rows of each kind; the oldest days go first. A player already recorded today at the same level costs no new memory, so mouseover in a busy city stays cheap.
  • The rows are sent from the upload page, which counts them first ("312 characters seen, 2 of your own"), or by the Desktop App if you allowed the census on its setup screen or in its settings. The command-line uploader never sends them. The server replaces each GUID with a keyed hash before it stores anything, and the site publishes only counts that cover at least 10 characters from at least 3 installs (docs/design/specs/2026-10-18-census-design.md).

Players

Off until /everloot players on (then /reload), and meant to stay off until the player pages on the site are switched on (docs/design/specs/2026-10-20-player-pages-design.md). This is the one module that reads other players' names and guilds, so it is separate from the census, which never does. /everloot players says whether it is on and how many characters it holds; /everloot players off stops it at once and deletes every row. An install with it off is asked once, in an Everloot window a few seconds after the first loading screen and never in combat: Turn on runs /everloot players on, Leave off keeps it off. The window says what is recorded and points to /everloot players off and the hide form (everloot.app/players/opt-out). Either answer, or /everloot players on|off typed or set on the settings page, is saved as playersAsked, and the question never comes back. addon/tests/options_contract.py holds the rules.

  • What a row holds (player_seen): name (UnitName), realm (GetRealmName), race and class tokens (UnitRace, UnitClass), level (UnitLevel) and the guild name when the game shows one (GetGuildInfo). The date is the row's capturedAt; the site keeps the day, not the time.
  • A second row (guild_kill): when ENCOUNTER_END reports a kill inside a dungeon or raid and the game shows your character in a guild, the guild name, realm, your faction (UnitFactionGroup), the encounter, the instance map id and difficulty (GetInstanceInfo) and the time. No character name. At most 60 a UTC day; written only while the module is on, and /everloot players off deletes these rows with the others. The guild page counts a kill once two installs report it.
  • Whom it reads: your own characters at login and at each level-up, and players you target, mouse over or group with (PLAYER_TARGET_CHANGED, UPDATE_MOUSEOVER_UNIT, GROUP_ROSTER_UPDATE). Not nameplates, not the guild roster, not the who list, not inspection. Players from another realm are skipped.
  • Nothing else: no position, gear, GUID, chat or history. addon/tests/players_contract.py fails if players.lua names a call that could read them, and lists every call the module may make.
  • Load: a player already read is left alone for 10 minutes, target and mouseover reads are at least a quarter of a second apart, at most 300 new characters a UTC day, at most 1,000 rows in the file (the oldest go first, about 200 KB). One row per character, kept in place.
  • Sending: only from the upload page, which counts the rows first. The Desktop App and the command-line uploader never send them. The site drops them until the owner has turned the player pages on.

Boss pulls

Not in any build until E.RUN_RECORDS is on (docs/RELEASING.md, "Release gates"). Then it is on by default, new install or upgraded, and says so once in chat. After each boss pull in a dungeon or raid it writes one pull_summary row: the boss, kill or wipe, how long it took, and for each member of your group their name, class, role and the damage done, healing done, damage taken and deaths that the game's own damage meter (C_DamageMeter) shows. /everloot pulls says whether it is on and how many pulls it holds; /everloot pulls off stops it at once and deletes every row.

  • No combat log. Forever restricts COMBAT_LOG_EVENT_UNFILTERED, and the module never registers it. It reads the meter's totals once per pull, after combat ends, when the client stops hiding them. A total the client still hides, or a member with no meter line, is left out of the row, never written as zero. A client without the meter gets rows with the group and assigned roles only, and /everloot status says so.
  • Role: the group role the game shows (UnitGroupRolesAssigned), marked assigned; without one, healer when healing done was larger than damage done, else damage, marked inferred. A tank is never inferred.
  • Nothing else about another player: no gear, talents, guild, position or chat. addon/tests/pulls_contract.py lists every call the module may make.
  • Size: about 150 bytes a member. At most 200 pulls and 2,000 member entries in the file (about 300 KB); then it pauses like every other kind.
  • Matching: a meter line goes to a member by isLocalPlayer, then GUID. A line whose GUID is readable but not in the group (a pet, a creature, a stranger) is ignored; the name is used only when the GUID is hidden and the class agrees, and two lines for one member leave that total out.
  • Sending: from the upload page, which counts the rows first, or the Desktop App; the command-line uploader never sends them. The site keeps them privately for a year in their own tables, shows them nowhere, and deletes any character someone hides on the site's hide form. None of this has run in the Forever client yet.

Linking a character

/everloot link <code> links the character you are playing to your everloot.app account. The site shows the code (EL-7K3Q-9P) to a signed-in player; it works once, for 15 minutes. Nothing happens without the command.

  • What a row holds (character_link): the code, your character's name, realm, race, class, level, faction and GUID, and the completion key for it. Only your own character is read.
  • Sending: after /reload or logout, the Everloot Desktop App, signed in with permission to link characters, sends the row to your account's link endpoint and nowhere else. Uploads never carry it. The site keeps a keyed hash in place of the GUID.
  • What a link is: a claim made from this file, not proof that you own the character. If another account links the same character, both links are frozen.
  • A new code on the same character replaces its row; at most 10 rows are kept. /everloot link says how many there are and /everloot link clear deletes them. addon/tests/link_contract.py lists every call the command may make.

Talents, selftest and the plan panel

Bring a website plan into the game

Open /everloot for the Talents / Raid workspace, or load a plan straight into the plan panel with /everloot plan <share code>. Right-click the minimap button, or use /everloot options, for collection settings. /everloot status still prints the collector status.

  1. Make a build on everloot.app's talent calculator or raid planner and choose Copy for addon.
  2. Open the matching tab in the addon, paste the link or code, and click Import (or press Enter).
  3. Talents shows your progress, and the next point when the plan carries a spend order (see Spend order). Raid compares class counts per group and checks buffs on the current roster. Apply points and arrange players yourself.

Talent export copies the selected set only. Talent links with two sets import the first; a second-set-only link imports that set. A link carries each set's spend order beside its code, #plan=<code>&order=<order> for the first set and #plan2=<code>&order2=<order> for the second, and the set that loads takes its own order only. Paste links into this Import box: /everloot plan takes a bare share code, not a link. For saved short links, open the website and use Copy for addon to choose the set. Raid codes preserve planned talent trees for the website. The addon cannot verify another player's talent choices or identify players from a class-only code. Differences in game build remain visible. Imports stay in your local SavedVariables file; roster names are never saved by this workspace. Copy plan link returns the loaded set to the website under the same keys, with the order it came with when the addon could read it; an order it could not read is left out, never made up. Copy current raid opens your actual roster there. Use Ctrl+C in the selected field.

The window is created when opened, refreshes on relevant character/group changes while visible, and uses no polling loop. Escape closes it. This workspace still needs a live-client layout and behavior check; a passing Lua contract is not an in-game test. Drag its header beside the game's talent window to keep the next-point highlights visible.

  • Talents (on by default). Reads your build through C_Traits and C_ClassTalents: the active spec group and, once dual spec is unlocked at level 40, the second one. Each build is one talent_snapshot record: class, level, spec group, config id, tree id, every spent node with its ranks and choice, and Blizzard's own loadout string from C_Traits.GenerateImportString when the client returns one (exportStatus says ok, unavailable, failed, empty or unexpected). A row is written only when the build changes. The rows hold no character name. They are not in the public corpus until the data policy says how talent builds are published. /everloot talents prints each group and a share code.
  • Selftest. /everloot selftest checks each talent API, that it returns sane data, and that the loadout export and import functions exist (ImportLoadout and ViewLoadout are never called). It prints PASS, FAIL, SKIP and INFO lines and saves them under selftest in the SavedVariables file. Run it once with the talent window closed and once open. It also prints your race token (INFO player race), the value the census stores.
  • Plan panel (display only). /everloot plan <share code> loads an Everloot talent plan and shows, beside the talent window, where your build differs and, for a plan with a spend order, the next point to spend. A pasted code has no order; a link brings its own through the workspace's Import box. /everloot plan reopens it (it also has a paste box), plan hide closes it, plan clear forgets it. When the talent window is open it also puts a green overlay on the next talent, when there is one, and red ones on mismatches. It never spends a point, clicks, imports a loadout or acts for you. The plan and its order are kept in your SavedVariables file.
  • Saved builds. When the Desktop App has synced your everloot.app builds into the EverlootBuilds slot addon, /everloot plan also lists them in chat, this character's first (the label's name, and its realm when it has one), then the rest of your class, and /everloot plan <number> loads one (/everloot plan <number> 2 loads its second talent set, marked [2 sets] in the list). Each set keeps its own planned or provisional spend order when available; its code, validated order and set are kept in SavedVariables and in Copy plan link. Missing or unusable metadata leaves ranks readable with unknown order. Older version 1 slot files still load. Addon 0.3.12 ignores the new order fields and keeps ranks only; update the addon to follow spend order. Nothing is uploaded by selecting a build.

Share code, version 1

One line of text, safe to paste into chat or a URL fragment. The web calculator and the addon use the same format (see docs/2026-10-17-talent-share-code.md):

EL1-<class>-<spec>-<build>-<payload>
Field Meaning
EL1 Format version 1. A reader refuses a version it does not know.
class Lowercase class token, as UnitClass gives it, e.g. mage.
spec The client's spec id for the class (Forever has one per class; the builders study reads 1482 and 1484 to 1491 from Blizzard's files, pending /everloot selftest), or 0 when unknown. A plan with a spec id that differs from yours loads with a warning.
build Client build the plan was made on, e.g. 1.60.1.70450. A different build shows a warning because node ids can move.
payload base64url (RFC 4648 section 5, no = padding) of the ASCII text node:rank,node:rank:choice,....

node is the client's trait node id, rank is the target rank (1 to 50), and an optional third number is the zero-based entry of a choice node. A node absent from the list is planned at zero. The site lists the items by node id, and their order is not a spend order. Example: EL1-mage-1482-1.60.1.70450-OTAwMDE6Miw5MDAwMjoxOjEsOTAwMDQ6Mg carries 90001:2,90002:1:1,90004:2.

Spend order

A plan can carry the order its points are spent in, as a token of its own beside the code: O1p-<sequence> when a player planned it, O1g-<sequence> when a tool generated it. The format, its 64-point limit and its test vectors are in docs/2026-10-17-talent-share-code.md under "Spend order". For the example code above, O1p-AABCC is both points in 90001, then 90002, then 90004 twice.

  • With an order, Talents names the next point: the first point in the order you have not spent, even when the game says it cannot be bought yet. A generated order is labelled provisional, which is neither a recommendation nor a record of anyone's play. The addon does not check that each point could be spent at its place in the order; the game says whether the next one can be bought now.
  • Without one, the order is unknown and no point is named next. Talents lists the missing points the game says you can add now, none of them first, and apart from them any the game says nothing about. Item order and node ids are never used as an order.
  • An order the addon cannot read (damaged, made by a newer version, of a kind it does not know, over 64 points, or not matching the code's points) leaves the talents loaded, and Talents says why the order is unknown. An order that names a talent your tree does not have is not followed either.
  • Addon 0.3.12 loads the talents from these links but not their order: it stops at &, and still names a next point from the code's item order.

Test it

The contract tests run the Lua in real Lua 5.1 through lupa:

python -m pip install lupa==2.6 jsonschema==4.25.1
python addon/tests/run_all.py

run_all.py holds the one list of tests that pull-request checks, releases and nightlies all run, and fails if a test script in addon/tests/ is missing from it. Run one test on its own with python addon/tests/<name>.py. The two planner tests, raid_plan_contract.py and planner_contract.py, run as their own CI step.

Run them from the repository root. CI also rebuilds the zip. For a version that is not released yet it fails if the zip differs from the one committed in web/public/downloads/, so commit the rebuilt zip with the change. For a version that is already tagged, the published zip stays as it is and the next release builds a new one.

Where things live

addon/
├── Everloot.toc        Interface 16001 (Forever 1.60.1), SavedVariables: EverlootDB
├── core.lua            event dispatch, module registry, toggles, rolling store, /everloot
├── modules/
│   ├── openworld.lua   target/mouseover sightings, NPC window places, loot windows, merchant windows
│   ├── itemfacts.lua   armor, stats and resistances from the item tooltips you see, once per item and build
│   ├── guild.lua       roster, attendance, saved lockouts (published only through an officer)
│   ├── gear.lua        equipped item level sample, at most once an hour
│   ├── auctions.lua    full auction-house scans you start (Forever); listed buyouts on older clients; on in a new install
│   ├── gold.lua        your own gold: loot, quests, vendors, flights, mailed auction sales, postage, buyouts
│   ├── professions.lua recipe colours at your rank (C_TradeSkillUI); required rank and cost from trainer windows
│   ├── ask.lua         /ask stores a question; the Everloot Desktop App's answers show after /reload
│   ├── addons.lua      your installed addons' names, titles and versions; off until enabled
│   ├── mapbounds.lua   each zone's corners in world coordinates, once per zone per build
│   ├── talents.lua     your talent build per spec group, plus the game's own loadout string
│   ├── completion.lua  achievements, reputation, titles, quest chains: catalogs and your progress; off until enabled
│   ├── census.lua      race, class, level and faction of your characters and players you see; on in a new install
│   ├── players.lua     name, realm, race, class, level and guild of your characters and players you see; off until enabled
│   ├── pulls.lua       each boss pull: your group's names, classes, roles and damage meter totals; on once released
│   ├── selftest.lua    /everloot selftest and /everloot talents
│   ├── plan.lua        share code reader and the display-only plan panel
│   ├── raid_data.lua   raid buff list generated from web/src/data/game-data/raid-*.json
│   ├── raid.lua        /everloot raid: buffs missing per group, and a raid share code; display only
│   ├── prices.lua      item tooltips: your latest scan and the Everloot Desktop App's community prices
│   ├── drops.lua       item tooltips: where an item drops, from the public rates in the same file
│   ├── gph.lua         gold per hour sessions, kept in your file only
│   ├── conveniences.lua  sell greys and repair at a merchant, Collect all at the mailbox; each off until enabled, no records
│   └── window.lua      the Everloot window: Home from what the file holds; built on first open, no records
├── media/crest.tga     the crest, 128 px, packaged beside the code
└── tests/              Lua 5.1 contract tests and their fixtures

Every Blizzard call is guarded, so a system missing from the client disables its module instead of raising an error.