Skip to content

title: "Référence CLI" description: "Piloter Mercy SF depuis un autre programme : chaque commande, sa sortie JSON, les codes de sortie et des exemples travaillés." ​

Référence CLI, piloter Mercy SF depuis un autre programme ​

mercy-cli a un mode non interactif : des arguments en entrée, un objet JSON en sortie. Il est destiné aux tableaux de bord, aux superviseurs et aux scripts.

Cette page est la promesse. Les commandes et les noms de champs ci-dessous ne changeront pas sans préavis. Tout le reste de la CLI, le menu, ses formulations, la mise en page de sa sortie, peut changer à tout moment, alors ne construisez rien dessus.

Lancée sans argument, le menu interactif démarre exactement comme avant.

Chaque réponse porte "api". Aujourd'hui c'est 1. Ajouter un champ ne le change pas, un appelant qui ne lit que les champs qu'il connaît n'est pas affecté. Il change quand un champ est retiré ou que son sens change, vous pouvez donc refuser de tourner face à une forme pour laquelle vous n'avez pas été construit.


Se connecter ​

Les comptes créés via l'authentification unique S&F n'ont besoin de rien de plus. Un compte qui appartient à un serveur et n'a jamais fait partie de l'authentification unique n'existe pas de son point de vue, et a besoin de --server :

bash
mercy-cli --status --user <account> --server https://f1.sfgame.net/

--server fonctionne avec toutes les commandes ci-dessous.

Sortie ​

Toutes les commandes sauf --start impriment du JSON et rien d'autre, donc --json est déjà la valeur par défaut et le passer ne change rien. Il existe pour les appelants qui préfèrent le dire plutôt que de compter sur un défaut, et pour --start, qui sinon écrit un journal lisible par un humain.


Chaque panneau que dessine l'application ​

bash
mercy-cli --views
mercy-cli --view <name> --user <account> --character <name>

--views affiche le catalogue et ne demande ni compte ni mot de passe. --view répond à l'un d'eux pour un personnage.

Chaque nom mène exactement à la fonction que dessine l'application. C'est tout l'intérêt : un nombre calculé une seconde fois finit par être calculé autrement, et deux fenêtres de la même installation se contredisent.

nomce qu'il répond
account_overviewla ligne de ce personnage dans le tableau des comptes
achievementsles succès, et ce que le moteur viserait
analyticsl'historique enregistré de ce personnage
battle_historyles combats conservés, le plus récent d'abord
blacksmithmétal, arcane et démontages restants aujourd'hui
combat_decisionce que le module de combat a décidé, et pourquoi
dungeonschaque donjon avec son niveau et sa progression
fight_calibrationle modèle de combat appris pour ce personnage
gearce que vaut chaque emplacement face au sac
hellevatorl'hellevator : étage, santé, prochaine action
legendary_dungeonle panneau du donjon légendaire, santé comprise
live_eventsquels événements tournent, et leurs fenêtres
scrapbook_cachecombien d'adversaires scoutés sont en cache
scrapbook_targetsquels objets manquants valent la chasse
world_bossle boss mondial et sa boutique

La réponse est toujours {"ok": true, "view": "<nom>", "data": …}. Cinq d'entre elles viennent du disque et répondent sans toucher au jeu.

Lire ​

Lister les personnages d'un compte ​

bash
mercy-cli --characters --user <account>
json
{
  "ok": true,
  "characters": [
    { "character": "Hero", "server": "https://s1.sfgame.net/", "level": 345 },
    { "character": "Alt",  "server": "https://s42.sfgame.net/", "level": 88 }
  ]
}

Une seule connexion couvre tous les personnages du compte, tous serveurs confondus. level vaut null si l'état de ce personnage n'a pas pu être récupéré, l'entrée est tout de même listée, parce que savoir qu'il existe est l'objet de l'appel.

Lire l'état d'un personnage ​

bash
mercy-cli --status --user <account> --character <name>

--character peut être omis quand le compte n'en a qu'un.

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
}

Tout provient d'une seule récupération d'état, il n'y a donc pas de sections à demander et rien à économiser en demandant moins.

guild vaut null quand le personnage n'est dans aucune. scrapbook_items vaut null tant que l'album n'a pas été lu au moins une fois. Un emplacement d'équipement vide est omis plutôt que listé comme null.

À propos des noms d'objets : le protocole porte un identifiant de modèle et un emplacement, pas un nom d'affichage, et c'est donc ce que vous obtenez. C'est aussi par là que l'illustration est adressée, un tableau de bord peut donc afficher exactement l'image que l'application de bureau affiche. Inventer un nom ici serait une supposition invérifiable.

Répéter une lecture à intervalle régulier ​

bash
mercy-cli --status --user <account> --character <name> --watch 60

Une connexion, puis un objet toutes les 60 secondes jusqu'à l'arrêt du processus. Utilisez ceci plutôt que de relancer la commande en boucle : chaque exécution est une nouvelle connexion, ce qui est la façon la plus coûteuse de surveiller un nombre et la plus voyante du côté du serveur. Le plancher est de 30 secondes. Un tour raté est imprimé et la boucle continue, un observateur qui abandonne au premier hoquet ressemble exactement à un observateur où tout va bien.

Ce qu'il affrontera ensuite, et pourquoi ​

bash
mercy-cli --plan --user <account> --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
    }
  ]
}

La même décision que celle affichée par l'application : les candidats notés sur les objets, l'XP quotidienne et le rang, puis multipliés par les probabilités. outcome vaut planned, waiting, blocked ou empty, et reason dit lequel en une phrase.

Cela ne dépense ni combat ni champignon. Cela parcourt en revanche le serveur pour trouver des candidats, ce n'est donc pas gratuit en requêtes, ne le mettez pas dans une boucle serrée.

Répéter un combat ​

bash
mercy-cli --simulate --user <account> --character <name> --against <player>
json
{ "ok": true, "against": "Someone", "against_level": 340, "win_chance": 0.63, "iterations": 1000 }

De l'arithmétique. Une consultation part vers le serveur pour savoir qui c'est ; le combat lui-même n'est jamais envoyé. win_chance est le nombre de victoires sur les combats tranchés, une simulation qui ne parvient pas à conclure rend donc compte de moins de combats qu'elle n'en a lancés.

Ce qui est porté ​

bash
mercy-cli --inventory --user <account> --character <name>
json
{ "ok": true, "carried": 12, "backpack": [ { "slot_index": 0, "model_id": 55 } ] }

Une seule liste, parce que le jeu n'en tient qu'une. Les objets ont la même forme que dans --status, plus slot_index.

Album ​

bash
mercy-cli --scrapbook --user <account> --character <name>
json
{ "ok": true, "unlocked": true, "owned": 1102, "monsters": 214 }

unlocked vaut false en dessous du niveau qui donne un album, et owned y vaut null. Ce n'est pas une erreur.

Combats enregistrés ​

bash
mercy-cli --history --user <account> --character <name> --limit 50
json
{ "ok": true, "total": 4210, "returned": 50, "battles": [] }

Les plus récents d'abord. Ils sont enregistrés par l'installation qui a fait tourner le bot, pas récupérés depuis le serveur, un processus qui vient de démarrer n'a donc rien à montrer, et ce n'est pas un défaut. total est ce qui existe, returned est ce que --limit a laissé.


Agir ​

Faire tourner le bot ​

bash
mercy-cli --start --user <account> --character <name>

Tourne jusqu'à l'arrêt du processus, en journalisant au fil de l'eau. --character est obligatoire ici : lister et lire un état sont inoffensifs, mais démarrer le bot fait jouer, et se tromper de personnage n'est pas quelque chose que l'on peut défaire.

--all fait tourner à la place tous les personnages du compte dans ce même processus. C'est une connexion pour le compte plutôt qu'une par personnage, ce qui coûte moins cher et empêche les personnages d'invalider mutuellement leur session.

Sur Ctrl-C (ou SIGTERM), le coup en cours a le droit de se terminer avant que le processus ne s'arrête, plutôt que d'être coupé au milieu d'une requête.

Des événements plutôt que de la prose ​

bash
mercy-cli --start --user <account> --character <name> --events

Un objet JSON par ligne, un superviseur lit donc ligne par ligne :

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 vaut l'un de started, stopping, stopped, arena_win, arena_loss, dungeon_win, dungeon_loss, quest_done, scrapbook_win, scrapbook_loss, scrapbook_items (qui porte un count).

Cette liste va s'allonger. Traitez un événement que vous ne reconnaissez pas comme un événement à ignorer, pas comme une erreur, c'est toute la raison pour laquelle les noms sont écrits en toutes lettres au lieu d'être ce que Rust a imprimé.

Utilisez ceci plutôt que de lire le journal humain. Ce journal est écrit pour une personne et peut être reformulé à tout moment ; le parser signifie que votre outil casse quand quelqu'un améliore une phrase.

Ramasser ce qui attend ​

bash
mercy-cli --claim --user <account> --character <name>

Calendrier, tâches quotidiennes, déblocages en attente. --character est obligatoire, pour la même raison que --start.

Lire ou changer la configuration ​

bash
mercy-cli --config --user <account> --character <name>
mercy-cli --config --user <account> --character <name> --set auto_arena=false
json
{ "ok": true, "settable": ["auto_arena"], "changed": [ { "key": "auto_arena", "from": true, "to": false } ] }

La lecture renvoie toute la configuration sous config. Les noms de champs à l'intérieur de ce bloc ne font pas partie de cette promesse, seules les clés listées dans settable en font partie. La configuration compte bien plus de cent champs et grossit à chaque version ; les promettre toutes reviendrait à ne jamais pouvoir remanier les réglages.

--set accepte true/false, on/off, yes/no, 1/0, exige toujours --character (un interrupteur appartient à un personnage, et « le seul » est une supposition acceptable pour lire et fausse pour écrire), et peut être répété. La valeur est relue depuis le disque ensuite et l'appel échoue si elle n'a pas atterri, car signaler un changement qui n'a pas eu lieu est le seul résultat dont on ne peut pas se remettre.


Exploitation ​

Quelle version est-ce ​

bash
mercy-cli --version
json
{ "ok": true, "version": "2.12.0", "api": 1 }

La seule commande qui n'a besoin ni d'un mot de passe ni du réseau. Un superviseur doit pouvoir demander à quoi il parle avant d'avoir des identifiants pour lui parler.

Est-ce joignable ​

bash
mercy-cli --health --user <account> --character <name>
json
{ "ok": true, "character": "Hero", "level": 345, "round_trip_ms": 412 }

Se connecter, récupérer, rapporter, sortir. Délibérément minuscule : une vérification de santé qui renvoie une fiche de personnage complète invite à la parser, et alors la vérification devient une interface à part entière.


Le mot de passe ​

Il n'y a pas de drapeau --password, exprès. Les arguments de ligne de commande sont lisibles par tous les autres processus de la machine, ps, /proc, le gestionnaire de tâches, donc un tableau de bord qui ferait tourner ceci pour plusieurs personnes livrerait tous leurs mots de passe de jeu à quiconque a un shell sur cette machine.

Deux voies à la place :

bash
MERCY_SF_PASSWORD='…' mercy-cli --status --user someone
bash
printf '%s' "$password" | mercy-cli --status --user someone --password-stdin

--password-stdin lit la première ligne de l'entrée standard, ce qui garde aussi le secret hors de l'environnement.


Codes de sortie ​

CodeSignification
0Succès, et pour --help
1Ça a tourné et échoué, la raison est dans error, et ok vaut false
2L'appel était erroné : option inconnue, valeur manquante, aucune action. Sur stderr

La différence entre 1 et 2 compte pour un superviseur : 2 échouera de la même façon à chaque fois et demande un humain, 1 peut très bien marcher à la prochaine tentative.


Erreurs ​

Les échecs sont aussi du JSON, un seul parseur gère donc les deux :

json
{ "ok": false, "error": "no character called 'Typo' on this account" }

ok est présent dans chaque réponse. Vérifiez-le avant toute chose.

Causes fréquentes :

MessageQue faire
--user is required--user manque (toute action sauf --version)
--start needs --character (or --all)Nommez la cible ; elle ne sera pas devinée
this account has N characters — name one with --characterIl y en a plusieurs, choisissez-en un
no character called '…' on this accountFaute de frappe ; --characters liste les noms valides
no password: set MERCY_SF_PASSWORD or pass --password-stdinChoisissez l'une des deux voies pour le mot de passe
login failed: …Vérifiez les identifiants ou le serveur ; les comptes hors authentification unique ont besoin de --server
'…' is not settable from herePas sur la liste autorisée ; --config sans --set imprime settable
'…' did not save — it still reads back unchangedLe changement n'a pas atterri ; vérifiez les droits d'écriture

Raspberry Pi et autres petites cartes ​

L'application de bureau n'est pas compilée pour ARM. WebKitGTK sur ARM, c'est précisément là qu'un possesseur de Pi a signalé un plantage juste après la connexion, et livrer une version que personne ici ne peut tester serait une promesse que ce projet ne peut pas tenir. La CLI n'a pas d'interface, donc rien de tout cela, et elle est compilée pour ARM64 à chaque version.

Vérifiez d'abord que la carte tourne sur un système 64 bits :

bash
uname -m   # aarch64 est celui qu'il faut, armv7l signifie système 32 bits

Pour un Raspberry Pi OS 32 bits, il n'y a pas de version. Réinstaller avec l'image 64 bits est le seul passage : ce sont des cibles différentes et rien ne se convertit.

Prenez ensuite mercy-cli-linux-arm64 sur la page de téléchargement :

bash
chmod +x mercy-cli-linux-arm64
sudo mv mercy-cli-linux-arm64 /usr/local/bin/mercy-cli
mercy-cli --version

Tout le reste de cette page fonctionne pareil à partir de là. Un Pi 4 fait tourner plusieurs personnages sans peine, un Pi Zero 2 W en tiendra un. mercy-node-linux-arm64 est sur la même page et c'est le travailleur de la flotte, pas ce par quoi on commence.

Installez-le en service avec la recette systemd ci-dessous et activez-le avec systemctl enable, il revient alors tout seul au redémarrage de la carte.

Recettes ​

Ramasser sur chaque compte une fois par jour

bash
for account in alpha beta gamma; do
  MERCY_SF_PASSWORD="$(pass mercy/$account)" \
    mercy-cli --claim --user "$account" --character Hero || echo "failed: $account"
done

Garder une tuile de tableau de bord à jour

bash
MERCY_SF_PASSWORD='…' mercy-cli --status --user someone --character Hero --watch 60

Une connexion, un objet par minute. Ne relancez pas ceci depuis cron chaque minute à la place, ce serait une nouvelle connexion à chaque fois.

Enregistrer les événements dans un fichier

bash
MERCY_SF_PASSWORD='…' mercy-cli --start --user someone --character Hero --events \
  >> events.ndjson

Vérifier à quoi vous parlez avant de vous connecter

bash
api=$(mercy-cli --version | jq -r .api)
[ "$api" = "1" ] || { echo "unknown contract version: $api"; exit 1; }

En service systemd

ini
[Service]
Environment=MERCY_SF_PASSWORD=…
ExecStart=/usr/local/bin/mercy-cli --start --user someone --all --events
Restart=on-failure
KillSignal=SIGTERM

SIGTERM laisse le coup en cours se terminer. Merci de ne pas lui envoyer SIGKILL.


Ce que cela ne fait pas encore ​

Démarrer plusieurs personnages et les arrêter individuellement (--all les démarre tous et les arrête tous ensemble), un canal de contrôle vers un processus en cours, et changer quoi que ce soit au-delà des interrupteurs de modules.

Si vous avez besoin de l'un d'eux, dites lequel, il est plus facile de construire la bonne chose que de deviner et de la voir inutilisée.

Mercy SF n'est affilié ni à Shakes & Fidget ni à Playa Games. Utilisation à vos risques.