Appearance
CLI-Referenz — Mercy SF aus einem anderen Programm steuern
English version: cli-api.md
mercy-cli hat einen nicht-interaktiven Modus: Argumente rein, ein JSON-Objekt
raus. Gedacht für Dashboards, Überwachung und Skripte.
Diese Seite ist die Zusage. Die Kommandos und Feldnamen hier ändern sich nicht ohne Ankündigung. Alles andere an der CLI — das Menü, seine Formulierungen, das Aussehen der Ausgabe — darf sich jederzeit ändern. Bitte baue nichts darauf.
Ohne Argumente startet das interaktive Menü wie bisher.
Jede Antwort trägt "api". Heute ist das 1. Ein neues Feld ändert die Zahl
nicht — wer nur die Felder liest, die er kennt, ist davon nicht betroffen.
Sie ändert sich, wenn ein Feld verschwindet oder seine Bedeutung wechselt. So
kannst du dich weigern, gegen eine Form zu laufen, für die du nicht gebaut bist.
Inhalt
- Anmelden
- Das Passwort
- Ausgabe
- Lesen — Charakterliste, Zustand, Plan, Simulation, Rucksack, Sammelalbum, Historie, Wiederholung
- Handeln — Bot starten, Ereignisse, Einsammeln, Konfiguration
- Betrieb — Version, Erreichbarkeit
- Abbruchcodes
- Fehler
- Rezepte
- Was es noch nicht gibt
Anmelden
Konten aus dem S&F-Single-Sign-on brauchen nichts weiter — --user genügt, und
eine Anmeldung deckt alle Charaktere des Kontos ab, über Server hinweg.
Ein Konto, das zu genau einem Server gehört und nie Teil des SSO war, existiert
für das SSO nicht. Solche Konten brauchen --server:
bash
mercy-cli --status --user <konto> --server https://f1.sfgame.net/--server funktioniert mit jedem Kommando auf dieser Seite.
Das Passwort
Es gibt kein --password, und das bleibt so.
Kommandozeilenargumente sind für jeden anderen Prozess auf der Maschine lesbar —
ps, /proc, der Task-Manager. Ein Dashboard, das die CLI für mehrere Leute
aufruft, würde damit sämtliche Spielpasswörter an jeden weitergeben, der eine
Shell auf dieser Kiste hat.
Zwei Wege stattdessen:
bash
MERCY_SF_PASSWORD='…' mercy-cli --status --user jemandbash
printf '%s' "$passwort" | mercy-cli --status --user jemand --password-stdin--password-stdin liest die erste Zeile der Standardeingabe. Das hält das
Geheimnis auch aus der Umgebung heraus, was der sicherere der beiden Wege ist:
die Umgebung eines Prozesses ist auf manchen Systemen ebenfalls auslesbar.
Ausgabe
Jedes Kommando außer --start gibt JSON aus und sonst nichts. --json ist
damit bereits die Vorgabe und ändert nichts. Es existiert für Aufrufer, die es
lieber hinschreiben als sich auf eine Vorgabe zu verlassen — und für --start,
das sonst ein Log für Menschen schreibt.
Lesen
Lesende Kommandos verändern nichts. --character darf fehlen, wenn das Konto
genau einen Charakter hat; bei mehreren ist es ein Fehler, weil Raten hier nichts
kostet, aber auch nichts nützt.
Charaktere eines Kontos auflisten
bash
mercy-cli --characters --user <konto>json
{
"ok": true,
"characters": [
{ "character": "Hero", "server": "https://s1.sfgame.net/", "level": 345 },
{ "character": "Alt", "server": "https://s42.sfgame.net/", "level": 88 }
]
}Eine Anmeldung deckt jeden Charakter des Kontos ab, serverübergreifend. level
ist null, wenn der Zustand dieses Charakters nicht abrufbar war — der Eintrag
bleibt trotzdem in der Liste, denn dass er existiert, ist der Sinn des Aufrufs.
Den Zustand eines Charakters lesen
bash
mercy-cli --status --user <konto> [--character <name>]json
{
"ok": true,
"character": "Hero",
"server": "https://s1.sfgame.net/",
"level": 345,
"class": "DemonHunter",
"race": "DarkElf",
"experience": { "current": 740300000, "next_level": 769800000 },
"silver": 725000000,
"mushrooms": 8,
"honor": 12043,
"rank": 1800,
"action": "CityGuard",
"attributes": {
"strength": { "base": 4077, "bonus": 1200 },
"dexterity": { "base": 1000, "bonus": 300 },
"intelligence": { "base": 900, "bonus": 250 },
"constitution": { "base": 3000, "bonus": 800 },
"luck": { "base": 700, "bonus": 150 }
},
"equipment": [
{
"slot": "Weapon",
"model_id": 55,
"color": 1,
"class": "DemonHunter",
"epic": true,
"legendary": false,
"armor": 0,
"min_damage": 900,
"max_damage": 1400,
"upgrades": 3,
"attributes": { "strength": 420, "constitution": 210 },
"rune": { "type": "FireDamage", "value": 60 },
"enchantment": "SwordOfVengeance",
"gem": { "type": "Strength", "value": 300 }
}
],
"arena": {
"fights_for_xp": 7,
"next_free_fight": "2026-08-06T12:04:11+02:00",
"opponents": [50099, 34316, 13668]
},
"tavern": {
"thirst_for_adventure_sec": 3600,
"beer_drunk": 2,
"mushroom_skip_allowed": true,
"quests": [
{ "length_sec": 600, "silver": 120000, "experience": 45000,
"location": "Wolves", "item": true }
]
},
"guild": {
"name": "Blvck Clover",
"rank": 12,
"honor": 90000,
"members": [
{ "name": "Hero", "level": 345, "last_online": "2026-08-06T09:12:00+02:00" }
]
},
"scrapbook_items": 1102
}Alles stammt aus einem Zustandsabruf. Deshalb gibt es keine Abschnitte anzufordern und nichts zu sparen, indem man weniger verlangt — ein Schalter pro Abschnitt wäre nur eine weitere Möglichkeit, den Aufruf falsch zu machen.
guild ist null, wenn der Charakter in keiner Gilde ist. scrapbook_items ist
null, solange das Sammelalbum noch nie gelesen wurde. Ein leerer
Ausrüstungsplatz wird weggelassen statt als null aufgeführt.
Zu den Gegenstandsnamen: das Protokoll überträgt eine Modell-ID und einen Platz, keinen Anzeigenamen — also bekommst du das. Es ist zugleich das, worüber die Grafiken adressiert werden, ein Dashboard kann also genau dasselbe Bild zeichnen wie die Anwendung. Einen Namen zu erfinden wäre eine Vermutung, die du nicht nachprüfen könntest.
Auf einem Takt wiederholen
bash
mercy-cli --status --user <konto> --character <name> --watch 60Eine Anmeldung, danach alle 60 Sekunden ein Objekt, bis der Prozess beendet wird.
Nutze das, statt den Befehl in einer Schleife neu aufzurufen. Jeder neue Aufruf ist eine neue Anmeldung — die teuerste Art, eine Zahl zu beobachten, und aus Sicht des Spielservers die auffälligste.
Untergrenze sind 30 Sekunden. Ein fehlgeschlagener Durchgang wird ausgegeben und die Schleife läuft weiter: eine Überwachung, die beim ersten Schluckauf aufgibt, sieht genauso aus wie eine, bei der alles in Ordnung ist.
Anwendbar auf --status, --plan, --simulate, --history, --inventory,
--scrapbook und --health.
Was als Nächstes gekämpft wird, und warum
bash
mercy-cli --plan --user <konto> [--character <name>]json
{
"ok": true,
"outcome": "planned",
"reason": "Next: Someone — 3 scrapbook items, 72% odds",
"candidates": [
{
"name": "Someone",
"level": 340,
"source": "pool",
"missing_items": 3,
"rank_gain": 12,
"favourite": false,
"win_chance": 0.72,
"item_score": 300.0,
"xp_score": 60.0,
"rank_score": 25.0,
"base": 385.0,
"score": 277.2
}
]
}Dieselbe Entscheidung, die die Anwendung zeichnet: Kandidaten werden nach
Gegenständen, Tages-XP und Rangzuwachs bewertet und dann mit der Siegchance
multipliziert. base ist die Summe der drei Anteile, score dieselbe Summe mal
win_chance — deshalb kann ein starker Kandidat mit schlechten Aussichten hinter
einem schwächeren mit guten landen.
outcome ist planned, waiting, blocked oder empty. reason sagt in
einem Satz, welches davon und warum.
source sagt, woher der Kandidat kommt: die drei Arenagegner, der durchsuchte
Spielerpool oder die Bestenliste um den eigenen Rang herum.
Das kostet keinen Kampf und keinen Pilz. Es durchsucht aber nach Kandidaten, ist also nicht kostenlos in Anfragen — bitte nicht auf einen engen Takt legen.
Einen Kampf durchrechnen
bash
mercy-cli --simulate --user <konto> [--character <name>] --against <spieler>json
{ "ok": true, "against": "Someone", "against_level": 340, "win_chance": 0.63, "iterations": 1000 }Reine Rechnerei. Eine Anfrage geht an den Server, um nachzusehen, wer der Spieler überhaupt ist; der Kampf selbst wird nie gesendet.
win_chance sind Siege geteilt durch entschiedene Kämpfe. Eine Simulation, die
sich nicht auflösen lässt, meldet deshalb weniger iterations, als sie
angesetzt hat — dann ist der Wert auf weniger Durchläufen gebaut und
entsprechend gröber.
Was getragen wird
bash
mercy-cli --inventory --user <konto> [--character <name>]json
{ "ok": true, "carried": 12, "backpack": [ { "slot_index": 0, "model_id": 55 } ] }Eine einzige Liste, weil das Spiel eine einzige führt. Eine Aufteilung in „Tasche" und „Truhe" wäre eine Unterscheidung, die das Protokoll nicht macht.
Die Gegenstände haben dieselbe Form wie bei --status, zusätzlich slot_index.
Sammelalbum
bash
mercy-cli --scrapbook --user <konto> [--character <name>]json
{ "ok": true, "unlocked": true, "owned": 1102, "monsters": 214 }unlocked ist false, solange der Charakter zu niedrigstufig für ein
Sammelalbum ist; owned ist dann null. Das ist kein Fehler, und ok
bleibt true.
Aufgezeichnete Kämpfe
bash
mercy-cli --history --user <konto> [--character <name>] [--limit <n>]json
{ "ok": true, "total": 4210, "returned": 50, "battles": [] }Neueste zuerst.
Wichtig: diese Kämpfe wurden von der Installation aufgezeichnet, die den Bot laufen ließ — sie werden nicht vom Server geholt. Ein frisch gestarteter Prozess auf einer anderen Maschine hat also nichts anzuzeigen, und das ist kein Fehler.
total ist, was vorhanden ist. returned ist, was --limit übrig gelassen hat.
Handeln
Handelnde Kommandos verlangen --character ausdrücklich. Lesen und Auflisten
sind harmlos, aber den Bot auf dem falschen Charakter zu starten spielt das
Spiel — und das nimmt man nicht zurück.
Den Bot laufen lassen
bash
mercy-cli --start --user <konto> --character <name>
mercy-cli --start --user <konto> --allLäuft, bis der Prozess beendet wird.
--all führt jeden Charakter des Kontos in diesem einen Prozess. Das ist
eine Anmeldung für das Konto statt einer pro Charakter — billiger, und die
Charaktere machen sich nicht gegenseitig die Sitzung ungültig.
Bei Ctrl-C (oder SIGTERM) darf der laufende Zug zu Ende gehen, bevor der Prozess aussteigt, statt mitten in einer Anfrage abgeschnitten zu werden.
Ereignisse statt Prosa
bash
mercy-cli --start --user <konto> --character <name> --eventsEin JSON-Objekt pro Zeile, damit eine Überwachung zeilenweise mitliest:
json
{"at":"2026-08-06T17:22:04+02:00","api":1,"event":"arena_win","character":"Hero"}
{"at":"2026-08-06T17:22:31+02:00","api":1,"event":"quest_done","character":"Hero"}event ist eines von started, stopping, stopped, arena_win,
arena_loss, dungeon_win, dungeon_loss, quest_done, scrapbook_win,
scrapbook_loss, scrapbook_items (trägt zusätzlich count).
Diese Liste wird wachsen. Behandle ein unbekanntes Ereignis als eines zum Überspringen, nicht als Fehler. Genau deshalb sind die Namen ausgeschrieben und nicht das, was Rust zufällig ausgibt: so kann eine Umbenennung im Programm nicht stillschweigend ein Feld bei dir umbenennen.
Nutze das statt des Logs für Menschen. Jenes ist für einen Leser geschrieben und darf jederzeit umformuliert werden — es zu zerlegen heißt, dass dein Werkzeug bricht, sobald jemand einen Satz verbessert.
Einsammeln, was bereitliegt
bash
mercy-cli --claim --user <konto> --character <name>Kalender, Tagesaufgaben, ausstehende Freischaltungen. --character ist Pflicht,
aus demselben Grund wie bei --start.
Konfiguration lesen oder ändern
bash
mercy-cli --config --user <konto> [--character <name>]
mercy-cli --config --user <konto> --character <name> --set auto_arena=falsejson
{ "ok": true, "settable": ["auto_arena"], "changed": [ { "key": "auto_arena", "from": true, "to": false } ] }Beim Lesen kommt die gesamte Konfiguration unter config zurück.
Die Feldnamen innerhalb dieses Blocks sind nicht Teil der Zusage — nur die
Schlüssel, die unter settable aufgeführt sind. Die Konfiguration hat weit über
hundert Felder und wächst mit jeder Version; sie alle zuzusagen hieße, die
Einstellungen nie wieder umbauen zu können, ohne fremde Dashboards zu brechen.
--set nimmt true/false, on/off, yes/no, 1/0 und darf mehrfach
vorkommen. --character ist dabei immer Pflicht: ein Schalter gehört zu
einem Charakter, und „der einzige" ist eine Vermutung, die zum Lesen taugt und
zum Schreiben nicht.
Der Wert wird anschließend von der Platte zurückgelesen, und der Aufruf schlägt fehl, wenn er nicht angekommen ist. Eine Änderung zu melden, die nicht stattfand, ist das einzige Ergebnis, von dem sich ein Aufrufer nicht erholen kann.
Betrieb
Welcher Stand ist das
bash
mercy-cli --versionjson
{ "ok": true, "version": "2.12.0", "api": 1 }Das einzige Kommando, das weder Passwort noch Netz braucht. Eine Überwachung muss fragen können, womit sie redet, bevor sie Zugangsdaten hat, um zu reden.
Ist es erreichbar
bash
mercy-cli --health --user <konto> [--character <name>]json
{ "ok": true, "character": "Hero", "level": 345, "round_trip_ms": 412 }Anmelden, abrufen, melden, aussteigen. Bewusst klein gehalten: eine Erreichbarkeitsprüfung, die ein ganzes Charakterblatt zurückgibt, lädt dazu ein, es zu zerlegen — und dann ist die Prüfung selbst eine Schnittstelle geworden.
Abbruchcodes
| Code | Bedeutung |
|---|---|
0 |
Erfolg, und für --help |
1 |
Es lief und schlug fehl — der Grund steht in error, ok ist false |
2 |
Der Aufruf war falsch: unbekannte Option, fehlender Wert, keine Aktion. Auf stderr |
Der Unterschied zwischen 1 und 2 ist für eine Überwachung entscheidend: 2 scheitert jedes Mal gleich und braucht einen Menschen. 1 klappt womöglich beim nächsten Versuch. Ein Wiederholungsmechanismus, der beide gleich behandelt, läuft entweder ewig gegen einen Tippfehler oder gibt bei einem Netzhänger zu früh auf.
Fehler
Auch Fehlschläge sind JSON, damit ein einziger Parser beide Fälle abdeckt:
json
{ "ok": false, "error": "no character called 'Typo' on this account" }ok ist in jeder Antwort vorhanden. Prüfe es vor allem anderen.
Häufige Ursachen:
| Meldung | Was zu tun ist |
|---|---|
--user is required |
--user fehlt (außer bei --version) |
--start needs --character (or --all) |
Ziel benennen, es wird nicht geraten |
this account has N characters — name one with --character |
Mehrere vorhanden, einen wählen |
no character called '…' on this account |
Tippfehler; --characters zeigt die gültigen Namen |
no password: set MERCY_SF_PASSWORD or pass --password-stdin |
Passwortweg wählen |
login failed: … |
Zugangsdaten oder Server prüfen; bei Nicht-SSO-Konten --server |
'…' is not settable from here |
Der Schlüssel steht nicht auf der Positivliste; --config ohne --set zeigt settable |
'…' did not save — it still reads back unchanged |
Die Änderung kam nicht an; Schreibrechte prüfen |
Rezepte
Alle Konten einmal täglich einsammeln
bash
for konto in alpha beta gamma; do
MERCY_SF_PASSWORD="$(pass mercy/$konto)" \
mercy-cli --claim --user "$konto" --character Hero || echo "fehlgeschlagen: $konto"
doneEine Kachel im Dashboard aktuell halten
bash
MERCY_SF_PASSWORD='…' mercy-cli --status --user jemand --character Hero --watch 60Eine Anmeldung, ein Objekt pro Minute. Nicht per Cron jede Minute neu aufrufen.
Ereignisse in eine Datei mitschreiben
bash
MERCY_SF_PASSWORD='…' mercy-cli --start --user jemand --character Hero --events \
>> ereignisse.ndjsonVor dem Anmelden prüfen, womit man redet
bash
api=$(mercy-cli --version | jq -r .api)
[ "$api" = "1" ] || { echo "unbekannte Vertragsversion: $api"; exit 1; }Als systemd-Dienst
ini
[Service]
Environment=MERCY_SF_PASSWORD=…
ExecStart=/usr/local/bin/mercy-cli --start --user jemand --all --events
Restart=on-failure
KillSignal=SIGTERMSIGTERM lässt den laufenden Zug zu Ende gehen. Bitte kein SIGKILL.
Was es noch nicht gibt
Mehrere Charaktere aus einem Prozess starten und einzeln wieder stoppen
(--all startet alle, stoppt aber auch alle zusammen), ein Steuerkanal für einen
laufenden Prozess, und das Ändern von mehr als den Modulschaltern.
Wenn du eines davon brauchst, sag welches. Das Richtige zu bauen ist einfacher, als zu raten und es dann ungenutzt liegen zu sehen.