CLI Reference

Install, commands, flags, examples, output, and troubleshooting.

Contents

  1. Quick reference
  2. Install
  3. Synopsis & default behavior
  4. Stages
  5. Flags
  6. Examples
  7. Output structure
  8. Safety behavior
  9. Troubleshooting
  10. afkj-parse

1  Quick reference

Two commands, run from the afkj-parser folder: ./afkj-extract reads the game install into out/raw/, and ./afkj-parse turns that into the feed at out/api/. Both are small launchers for the Python packages in src/, so they need no install beyond the libraries in section 2.

TaskCommand
After a game update (game closed)./afkj-extract --locales-from cdn, then ./afkj-parse build
What changed since the last importprinted by build; details in out/build/diff.md, or ./afkj-parse diff
One hero's changed texts./afkj-parse diff --hero karma (--locale zh for another language)
After stargazer imports the feed./afkj-parse accept: the feed becomes the next diff's base
Which heroes are in the feed, and why./afkj-parse roster
Season art (portraits, artifacts, phantimals)./afkj-extract --only portraits --only artifacts --only phantimals
Help./afkj-parse --help, ./afkj-parse build --help, ./afkj-extract --help

The whole routine, with stargazer's side, is in Integrations §2.1.

1.1 Ways to run them

HowWhere it works
./afkj-parse …, ./afkj-extract …The documented way. Shell launchers for macOS and Linux that always run the code in src/.
python3 -m afkj_parse … with PYTHONPATH=srcAnywhere Python runs, Windows included; the same program the launchers start.
pip install -e ., then afkj-parse …Anywhere; installs both commands on the PATH (needs a recent pip).
make feed, make clean, …Shortcuts for macOS and Linux, listed in section 10.1; each runs the commands above and adds nothing of its own.

1.2 Reading the output

afkj-parse build prints one line per gate (source, model, feed, diff), the findings that need attention under it, where it wrote, and a last line that is either PASSED or FAILED with what to do next:

afkj-parse build  extract 1.6.11, build 14368
  source  out/raw (read-only)

  ✓ source  passed
  ✓ model   passed   1 warning, 4 notes
      ! M3   heroes missing a core skill slot: general: skill2, skill3
  ✓ feed    passed   1 note
  ✓ diff    passed   no changes since the baseline

  feed    out/api   129 heroes · 18 artifacts · 5 phantimals · 19 charms · 16 locales
  diff    out/build/diff.md
  report  out/build/report.md
  model   out/build/model

PASSED  in 4.8s
MarkMeaning
✓ / ✗a gate passed / failed; a failed gate stops the build and the feed is not written
✗ F12an error, with its check code; → under it is the suggested fix
! M3a warning: worth reading, does not fail the build (unless --strict)
· M17a note: counted by default, listed with -v; report.md always has them all
–a gate that did not run, because an earlier one failed

-q prints only errors and the result line, --json prints report.json. Output is coloured on a terminal and plain when piped or redirected; NO_COLOR=1 turns colour off and FORCE_COLOR=1 on. Fatal errors (a missing source, a bad config.json) print one error: line and exit 2.

2  Install

Install the libraries once, then use the bundled ./afkj-extract launcher — no package install, and it always runs the current code in ./src.

# one-time: install dependencies
python3 -m pip install --user pycryptodome lz4 lupa
#   + for the textures stage:  Pillow texture2ddecoder

# run (from the project folder)
cd afkj-parser
./afkj-extract [args]

Requires Python ≥ 3.9 and a local AFK Journey install whose "Complete" resources have finished downloading. A pip install -e . (to get a bare afkj-extract on PATH) needs a recent pip/setuptools; the launcher avoids that. No stage reads the Unity bundles; the research/atlas_sprites.py sprite tool needs UnityPy (the [bundles] extra).

Command shorthand in this page The examples below write afkj-extract … for brevity. Run it as ./afkj-extract … (the launcher, simplest) or PYTHONPATH=src python3 -m afkj_extract …, from the afkj-parser folder. For a friendlier, fully-spelled-out walkthrough see the How-to.

3  Synopsis & default behavior

afkj-extract [--source DIR] [--out DIR] [--only STAGE ...] [--tables NAMES]
             [--textures GLOB] [--hero NAMES] [--linear] [--reference DIR] [--limit N]
             [--list | --dry-run] [--verify REF] [-q]

With no arguments, afkj-extract auto-discovers the game container, runs the data stages (localization + tables), and writes to ./out. The textures, portraits, artifacts stages are opt-in (via --only) and need the [textures] extra. Each run first prints what it will touch:

afkj-extract  game 1.6.11
  source  ~/Library/Containers/<uuid>/Data/Documents/data (read-only)
  output  out (write)

  ✓ loc        17 files · … records
  ✓ tables     924 files · … records

DONE  in 38.2s  → out
Note on a full run A plain afkj-extract extracts all skill partitions present in the archive. For quick iteration use --only to pick a stage, --tables to pick tables, or --limit to cap the number of skill files.

4  Stages

StageStateProduces
locDONEout/raw/locales/<code>.json — localization key → text, from the install or, with --locales-from cdn, all 17 from the CDN
tablesDONEout/raw/tables/*.json — hero/skill tables with resolved arrays and exact defaults, plus HeroScripts.json, the integer settings of each hero battle script, read from its bytecode (Raw data §10.5)
texturesDONE (opt-in)out/raw/textures/**.png — loose AST/ASTC art decoded to PNG. Needs the [textures] extra.
portraitsDONE (opt-in)out/images/heroes/ — every hero's roster portrait named by the feed's slug (<slug>.png, as stargazer names them), skin alternates in alt/, and manifest.csv. Full runs replace the folder; --hero updates selected heroes and preserves others. Art this install has not downloaded is warned about and listed in the manifest, except under --hero, which requests it explicitly and so fails. See Architecture → Portrait export.
artifactsDONE (opt-in)out/images/artifacts/ — the permanent artifacts and the current season's (<slug>.png), told apart by manifest.csv's set column. Rebuilt on each run. See Architecture → Artifact & icon export.
phantimalsDONE (opt-in)out/images/phantimals/: the current season's Phantimal portraits (the CampPet units, sub-units included), named by the feed's slug (<slug>.png), and manifest.csv. Rebuilt on each run. See Architecture → Phantimal export.

Without --only, the data stages (loc + tables) run. textures, portraits, artifacts and phantimals run only when named with --only. manifest.json describes the last extraction invocation, including selections, status and statistics. Dry runs and preflight failures do not replace it; unselected output may be older.

5  Flags

FlagMeaning
--source DIRGame data directory to read. Default: auto-discover the sandbox container by bundle id. Point at a manual copy to extract off-machine.
--out DIROutput directory. Default ./out. Refused if it overlaps a game source tree in either direction or uses unsafe output links.
--only STAGERun only this stage; repeatable (--only loc --only tables). One of loc, tables, textures, portraits, artifacts, phantimals.
--tables NAMESComma-separated table names (whitespace is trimmed; empty and unknown values fail) for the tables stage (e.g. Unit,SkillBuff,TavernPool). Default: the curated core set and HeroScripts. Selecting specific tables skips skill partitions.
--textures GLOBFilter the textures stage by a path/filename glob (e.g. *herohead*). Default: all ~12k loose AST images under ui/.
--locales-from install|cdnFor the loc stage. install (default) exports the languages downloaded in-game; cdn downloads all 17 from the game's public CDN (hash-verified, cached in out/raw/cdn/<build>/), after checking that the CDN's file table is the installed game's, so text and tables are one build. If the CDN is ahead: open the game, let it update, close it, re-run. See Integrations → CDN.
--hero NAMESLimit the textures or portraits stage to these heroes. Comma-separated; each is an English name (Karma), internal codename (doublehead), or Unit ID (132), case-insensitive. Matches playable heroes only, and prints what each name resolved to. Combines with --textures (both must match). See Architecture → Finding a hero's art.
--linearWrite images' stored linear color values untouched. By default the image stages (textures, portraits, artifacts, phantimals) sRGB-encode them, the same conversion the game applies on screen, so PNGs match in-game colors. Use this only when feeding a linear-workflow tool. The default is checked against in-game screenshots; see Architecture → Color.
--reference DIRFor the portraits stage: an existing portrait folder, such as stargazer's src/assets/images/character. The manifest's in_reference column says which portraits it has (yes/no); the summary lists the heroes it lacks and the reference files the export lacks.
--limit NPositive integer cap on skill partitions or textures. Limited runs preserve unselected output.
--list, --dry-runValidate selections and required dependencies, print the source, version and plan, then exit without writes. This does not decode every selected asset.
--verify REFAfter extracting, semantically diff out/raw/locales/* against a reference export directory (e.g. ../AFKJourneyData) and report missing, extra and changed keys. Any mismatch returns failure.
-q, --quietOnly warnings and errors.
--versionPrint the tool version and exit.

Exit codes: 0 success; 1 extraction or verification failure; 2 argument, preflight, dependency or safety failure. Errors remain visible with --quiet.

6  Examples

# See what would happen — no writes
afkj-extract --list

# All data stages, to ./out (including all skill partitions)
afkj-extract

# Just localization, and check it against the reference export
afkj-extract --only loc --verify ../AFKJourneyData

# A few specific tables, fast
afkj-extract --only tables --tables Unit,SkillBuff,SkillBuffUI,TavernPool

# Core tables + only the first 20 skill files (dev loop)
afkj-extract --only tables --limit 20 --out /tmp/afkjout

# Extract from a manual copy of the data dir instead of the live container
afkj-extract --source /Volumes/dump/afkj/data --out ./out

# Textures (opt-in). Needs: pip install --user Pillow texture2ddecoder
afkj-extract --only textures --textures "*herohead*"    # just hero-head icons
afkj-extract --only textures --hero Karma               # one hero's art: portrait, ult, tavern art, skins, icons
afkj-extract --only textures --hero "Karma,Ravion,132"  # several heroes (names, codenames, IDs)
afkj-extract --only textures                            # ALL ~12k images (slow)

# Hero portraits for stargazer (and skin alternates for chaldea)
afkj-extract --only portraits --reference ../stargazer/src/assets/images/character
cp out/images/heroes/*.png ../stargazer/src/assets/images/character/   # bulk replace, after the checks below
afkj-extract --only portraits --hero "Karma,Igor"         # a few heroes

# Artifact art: the permanent six (stargazer) + the current season's set (chaldea), one folder
afkj-extract --only artifacts

# The current season's Phantimal portraits for chaldea
afkj-extract --only phantimals
Before a bulk replace Run the checks in Architecture → Replacing stargazer's portraits: research/portrait_audit.py (what changes), portrait_webp_check.mjs (what the build ships), and portrait_import_check.py (match-screenshot import).
Globs are substring-greedy --textures "*herohead_132*" also matches heroes 1322–1325. For one hero prefer --hero; with a glob, pin the boundary: "*herohead_132[._]*". --hero and --textures only filter the image stages; without one of them in --only the CLI prints a note and ignores them.

7  Output structure

out/
  manifest.json                 latest invocation: schemaVersion, versions, source, scope,
                                  status, options, stats, optional error
  raw/locales/en.json                 { "<key>": "<text>" }
  raw/locales/_stage.json             format version, game version, file-table hash, install or CDN build
  raw/tables/Unit.json                { fields:[...], arrayFields:[...], rows: { "<key>": {…} } }
  raw/tables/Skill/Skill_0.json       per-skill partitions
  raw/tables/HeroScripts.json         {Script, Name, Value}: hero battle script settings
  raw/tables/_stage.json              format version, game version, file-table hash, complete
  raw/cdn/<build>/…                   the CDN download cache (--locales-from cdn)
  raw/textures/**/*.png               decoded art (only when the textures stage is run)
  images/heroes/<slug>.png            hero roster portraits (portraits stage)
  images/heroes/alt/<slug>_alt.png     skin portraits
  images/heroes/manifest.csv          slug, English name, unit ID, source files, in_reference
  images/artifacts/<slug>.png         permanent and current-season artifacts (artifacts stage)
  images/artifacts/manifest.csv       slug, English name, Fairy ID, set, season, source file
  images/phantimals/<slug>.png        the current season's Phantimals (phantimals stage)
  tools/                              outputs of tools/
  …

Table rows are full objects keyed by primary key (grouped tables use JSON-encoded pairs such as "[1,1]"), with defaults applied and $arrayRef arrays resolved inline (see Architecture → Output). Localization is a flat {key: text} dict per language — the loc stage emits every language present on the source (a language file appears only after you've selected it in-game; --list shows which), or with --locales-from cdn all 17 from the game's CDN, after checking the CDN serves the installed build.

8  Safety behavior

9  Troubleshooting

SymptomCause / fix
error: no sandbox container for com.farlightgames.igame.iosGame not installed, never run, or discovery metadata is inaccessible. Pass an explicit --source /path/to/data if known. Otherwise launch it once and let "Complete" resources finish downloading. Or pass --source to a copy of the data dir.
error: AFK Journey is running: game files are never read while it is openClose the game and re-run. There is no override.
error: cannot check whether the game is runningProcess inspection failed, so game files stay untouched. Fix the check (libproc or pgrep); there is no override.
error: output … overlaps a game source treeChoose an --out outside the container / app bundle.
ModuleNotFoundError: lupa (tables stage)pip install lupa (or pip install -e .). Localization needs only pycryptodome + lz4.
No module named 'texture2ddecoder' or PIL (textures stage)python3 -m pip install --user Pillow texture2ddecoder
Images look darker / more contrasty than in-gameThey were extracted with --linear or by an older version, which wrote the stored linear values. Re-run without --linear. There's no HDR or color profile to add; the default output already has the game's sRGB encode.
error: no playable hero matches '…'Check the spelling. The error suggests the closest names. Use the name shown in-game, the codename, or the Unit ID. --hero covers playable heroes only, not NPCs or monsters.
Extraction is slowA full run processes all available skill files. Use --only, --tables, or --limit for quick loops.
Localization diffs in --verify (<0.1%)Check whether the reference and install are the same game version. Small differences can be version skew, but still return a failure status until investigated.

10  afkj-parse

./afkj-parse turns raw tables into the feed stargazer imports. It reads either this repo's extract output or an AFKJourneyData checkout, and never writes to either. What it builds is described in Model & feed; the raw data in Raw data.

./afkj-parse build  [--source DIR] [--source-kind auto|extract|dump] [--config FILE]
                    [--work DIR] [--out DIR] [--locales en,zh] [--baseline DIR] [--no-diff]
                    [--limit N] [--strict] [-v] [-q] [--json]
./afkj-parse check  [--out DIR] [--strict] [-v] [-q]
./afkj-parse diff   [--out DIR] [--base DIR] [--hero SLUG] [--locale CODE] [--config FILE] [--work DIR]
./afkj-parse accept [--out DIR] [--work DIR] [--baseline DIR]
./afkj-parse roster [--source DIR] [--source-kind auto|extract|dump] [--config FILE]
FlagMeaning
--sourceRaw data: out/raw/ by default (or $AFKJ_SOURCE); ../AFKJourneyData is the fallback when the extract fails its gate, or when there is no install to extract from (a --depth 1 clone is enough: Integrations §2.3). The layout is detected; --source-kind forces it.
--configHero lists (blocklist, awakeningLv2Blocklist, forceParse), locales.skip and expectations (including diff.attentionShare); config.json by default. An unknown or mistyped setting stops the run (exit 2) and names it: counts are whole numbers from 0, attentionShare a number from 0 to 1.
--workThe report (report.json, report.md), the diff report (diff.md) and the model dump (model/); out/build/ by default. diff and accept read the last report from it.
--outThe feed; out/api/ by default, with out/internal/ beside it. Each replaced as a whole, and only when every gate passes.
--localesEmit only these locales. en must be among them; locales.skip still applies.
--baseline, --baseThe diff's base: out/baseline/ by default. diff --base also takes any feed directory.
--no-diffSkip the diff gate and diff.md.
--hero, --localediff only: print every changed text of one hero, old over new, in one locale (en by default).
--limitParse only the first N heroes, for development. The model gate runs; the feed is not written.
--strictWarnings fail a gate too.
-v, -q, --jsonList notes too; print only errors and the result; print report.json instead (section 1.2).
CommandDoes
buildRuns the source gate, the model, the model gate, the feed, the feed gate and the diff against the baseline, in that order, stopping at the first gate that fails. Writes out/build/diff.md and publishes out/api/ and out/internal/ only if every gate passes. See Model & feed §1.1.
checkRuns the feed gate alone on a feed on disk, including the check for files the feed does not list; the internal/ beside it is checked when there.
diffPrints what changed from --base to --out: flagged heroes first, heroes whose English or Chinese text changed one per line, heroes changed only in other languages on one line, then artifacts, phantimals, charms and buff records. With --hero, it prints one hero's changed texts, old above new, with the changed words marked (coloured on a terminal, [-old-] and {+new+} when piped). out/build/diff.md is the same report as Markdown. List changes are attributed from the last build report's lists against _accepted.json's. See Model & feed §7.
acceptMakes the feed stargazer imported the next diff's base: copies its bulk files into out/baseline/api/, the internal files into out/baseline/internal/, and writes out/baseline/_accepted.json. Refuses (exit 1) without a passing build report for this very feed, byte for byte. See Model & feed §7.4.
rosterPrints every playable hero (ID, codename, name, status, hidden levels), the status counts, and M6 and M12's suggestions for config.json. Status is feed, feed (forced), hidden: blocklist, hidden: blocklist (permanent), hidden: the game disables it or no skill file; hidden levels read e.g. Awakening L2 (IsShow) or Awakening L2 (list).

Exit status: 0 passed, 1 a gate failed (or accept refused), 2 bad input (a missing source or feed, a bad config, or --source, --out, --work and --baseline that are the same folder or nested in one another; the default layout keeps them side by side under out/).

On build 14368, roster shows 129 heroes as feed, three as hidden: blocklist (permanent) (Hogan, Guywin and Joey, not in the public game), and six as hidden: the game disables it (Lorsan, Baden, Thane, Tephesia, Grezhul and a dev placeholder); IsShow hides the Awakening L2 of Ulmus, Mikola, Sinbad and Harak.

10.1 Make targets

TargetRuns
make feed./afkj-extract --locales-from cdn, then ./afkj-parse build. The game must be closed.
make images./afkj-extract --only portraits --only artifacts --only phantimals, at a season start or when art changes
make cleanDeletes everything under out/ except baseline/. It never promotes a feed.
make checkRuff and the offline test suite

These are shortcuts for macOS and Linux; each runs the commands in its row and nothing else, so the commands themselves work the same without make. The update routine is in Integrations §2.1.