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.


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

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.