Sections

Guide utilisateur

Référence config.json

Tous les champs du fichier config.json de Runyard, avec des exemples.

Runyard lit un unique fichier JSON qui décrit vos outils. Cette page documente chaque champ.

Le fichier de configuration se trouve par défaut à ~/Library/Application Support/Runyard/config.json. Vous pouvez le déplacer vers un dossier synchronisé — voyez Synchroniser entre plusieurs Mac.

Structure de premier niveau

{
  "tools": [ /* ... */ ],
  "paths": ["/opt/homebrew/bin"],
  "advanced": { /* réglages temporels optionnels */ }
}
Champ Type Valeur par défaut Description
tools tableau [] Liste des définitions d'outils (voir ci-dessous).
paths string[] [] Répertoires ajoutés en tête du PATH lors du lancement de toute commande. Listés par ordre de priorité. ~ est remplacé par votre dossier personnel.
advanced objet Réglages temporels (voir Réglages avancés).

Lancer à l'ouverture de session n'est pas stocké dans config.json. Activez l'option dans Réglages → General → Launch Runyard at login ; macOS conserve le choix dans la liste système des éléments d'ouverture de session.

Définition d'outil

Chaque entrée de tools représente un outil.

Champ Type Valeur par défaut Description
name string requis Nom affiché dans le menu.
type string "service" "service", "shortcut" ou "group" (voir Types d'outils).
directory string requis* Racine du projet (~ est développé). Les commandes s'exécutent depuis ce dossier sauf si workingDir est défini.
startCommands tableau requis* Processus à lancer (voir Commandes de démarrage).
stopCommands tableau Commandes d'arrêt personnalisées (voir Commandes d'arrêt).
actions tableau Éléments de menu supplémentaires (voir Actions).
tools tableau Outils imbriqués dans un groupe. Services et raccourcis uniquement — pas de groupes imbriqués.
autoStart booléen false Démarre automatiquement cet outil au lancement de Runyard (service uniquement).
installCommand objet Commande à exécuter si le chemin de marquage est absent (voir Commande d'installation).
keepMenuOpen booléen false Garde le menu ouvert en cliquant sur Start/Stop (service uniquement).
paths string[] Entrées PATH supplémentaires pour cet outil.
pathsOverride booléen false Si true, paths remplace entièrement les chemins globaux au lieu de les fusionner.

* directory et startCommands sont requis pour les outils service, optionnels pour shortcut/group.

Types d'outils

Type Apparence Champs requis
"service" En-tête en gras + Start/Stop + pastille d'état + journaux + actions. directory, startCommands
"shortcut" En-tête en gras + liste d'actions. Aucune gestion de processus. actions (au moins une)
"group" Sous-menu avec outils imbriqués et/ou actions. actions OU tools (au moins un)

Les services imbriqués dans un groupe se comportent exactement comme les services de premier niveau. Les groupes imbriqués ne sont pas autorisés.

Commandes de démarrage

Chaque entrée de startCommands est un processus à lancer.

Champ Type Valeur par défaut Description
label string requis Nom unique de ce processus.
command string requis Exécutable à lancer (par exemple npm, docker-compose).
args string[] [] Arguments passés à la commande.
workingDir string dossier de l'outil Répertoire de travail, relatif à directory.
startupCheck string URL HTTP à interroger jusqu'à ce qu'elle renvoie un 2xx ou 3xx pendant le démarrage du service.
startupFallbackPort number Port de repli si la détection automatique échoue. Également utilisé comme indice si plusieurs ports sont détectés.
startupRequestTimeout number global Délai HTTP par requête (en secondes) pour le sondage de démarrage. Remplace advanced.startupRequestTimeout uniquement pour ce processus.
waitFor string Étiquette d'un autre processus qui doit être en bon état avant que celui-ci ne démarre.

Vérifications de démarrage indépendantes du port

Si startupCheck est une URL locale sans port explicite (par exemple http://localhost/api/health), Runyard y injecte le port détecté au démarrage. Votre configuration fonctionne donc même si le serveur de développement choisit un port différent à chaque lancement.

Une URL avec un port explicite (par exemple http://localhost:3001/health) est utilisée telle quelle.

Dépendances de processus avec waitFor

"startCommands": [
  { "label": "Backend",  "command": "npm", "args": ["run", "dev"], "startupFallbackPort": 3001 },
  { "label": "Frontend", "command": "npm", "args": ["run", "dev"], "workingDir": "frontend",
    "startupFallbackPort": 5173, "waitFor": "Backend" }
]

Frontend ne démarre pas tant que la vérification de démarrage de Backend n'a pas réussi.

Commandes d'arrêt

Optionnelles. Lorsque stopCommands est défini, Runyard exécute chaque commande séquentiellement au lieu d'envoyer SIGTERM. Une fois terminées, tout processus résiduel est forcé à se fermer, par sécurité.

Utilise la même forme que startCommands. Les champs comme startupCheck, startupFallbackPort et waitFor sont ignorés.

"stopCommands": [
  { "label": "Compose Down", "command": "docker-compose", "args": ["down"] }
]

En l'absence de stopCommands, l'arrêt par défaut est SIGTERM → délai de grâce → SIGKILL.

Actions

Les actions ajoutent des éléments personnalisés au menu d'un outil. Chaque action doit spécifier exactement un type : url, command, reveal, applescript ou applescriptFile.

Champ Type Valeur par défaut Description
label string requis Texte de l'élément de menu.
url string URL à ouvrir dans le navigateur par défaut.
command string Commande shell à exécuter.
args string[] [] Arguments pour la commande shell.
workingDir string dossier de l'outil Répertoire de travail pour la commande.
reveal string Chemin à ouvrir dans le Finder (relatif au dossier de l'outil, ou absolu/~).
applescript string Code AppleScript inline.
applescriptFile string Chemin vers un fichier .applescript.
showWhen string "running" "always", "running" ou "stopped" (service uniquement).
keepMenuOpen booléen false Garde le menu ouvert en cliquant sur cette action.

Exemples d'actions

Ouvrir une URL :

{ "label": "Ouvrir le frontend", "url": "http://localhost:5173" }

Exécuter une commande shell :

{ "label": "Amorcer la base", "command": "npm", "args": ["run", "db:seed"] }

Ouvrir un fichier dans une application précise :

{ "label": "Éditer README", "command": "open", "args": ["-a", "TextEdit", "./README.md"], "showWhen": "always" }

Ouvrir un projet dans Cursor :

{ "label": "Ouvrir dans Cursor", "command": "cursor", "args": ["."], "showWhen": "always" }

Afficher un dossier dans le Finder :

{ "label": "Ouvrir le projet", "reveal": ".", "showWhen": "always" }
{ "label": "Ouvrir les logs du backend", "reveal": "backend/logs", "showWhen": "always" }

AppleScript inline :

{ "label": "Activer Safari", "applescript": "tell application \"Safari\" to activate", "showWhen": "always" }

AppleScript multiligne (utilisez \n) :

{
  "label": "Mettre Safari au premier plan",
  "applescript": "try\ntell application \"System Events\" to tell process \"Safari\"\nset frontmost to true\nend tell\nend try",
  "showWhen": "always"
}

AppleScript depuis un fichier :

{ "label": "Déployer", "applescriptFile": "scripts/deploy.applescript", "showWhen": "always" }

Espaces réservés de port

Les URL d'action prennent en charge deux espaces réservés :

{ "label": "API Docs", "url": "http://localhost:{{port:Backend}}/api/docs" }

Si le port n'est pas encore connu (outil non démarré), l'espace réservé reste en place et l'URL ne s'ouvre pas.

Comportement de showWhen

Valeur Affiché quand
"running" (par défaut) L'outil est en cours d'exécution.
"stopped" L'outil est arrêté ou en erreur.
"always" Toujours affiché.

showWhen ne s'applique qu'aux outils service. Pour shortcut et group, les actions sont toujours visibles.

Commande d'installation

Exécutée une fois avant le premier démarrage, si un fichier de marquage est absent. Utile pour npm install et équivalents.

"installCommand": {
  "command": "npm",
  "args": ["install"],
  "markerPath": "node_modules"
}
Champ Type Valeur par défaut Description
command string requis Exécutable.
args string[] [] Arguments.
markerPath string "node_modules" Chemin (relatif au dossier de l'outil) vérifié avant l'exécution. S'il existe, l'installation est sautée.

Réglages avancés

Tous les champs sont optionnels. Les valeurs par défaut sont indiquées.

"advanced": {
  "startupTimeout": 30.0,
  "startupPollInterval": 1.0,
  "startupRequestTimeout": 5.0,
  "sigTermGracePeriod": 3.0,
  "installTimeout": 300.0,
  "stopCommandTimeout": 30.0
}
Champ Valeur par défaut Description
startupTimeout 30.0 Secondes totales d'attente pour que la vérification de démarrage réussisse avant de marquer un processus en erreur.
startupPollInterval 1.0 Secondes entre deux sondages de démarrage.
startupRequestTimeout 5.0 Secondes d'attente pour une seule requête HTTP de sondage de démarrage. Peut être remplacé par processus via startupRequestTimeout.
sigTermGracePeriod 3.0 Secondes entre SIGTERM et SIGKILL lors de l'arrêt d'un processus sans stopCommands.
installTimeout 300.0 Secondes d'attente pour la commande d'installation avant abandon.
stopCommandTimeout 30.0 Secondes d'attente pour chaque entrée de stopCommands.

Chemins et résolution du PATH

Les commandes s'exécutent via /usr/bin/env avec un PATH construit sur mesure. Les règles :

Configuration type :

{
  "paths": ["~/.nvm/versions/node/v22.0.0/bin", "/opt/homebrew/bin"]
}

Pour les utilisateurs d'asdf, ajoutez ~/.asdf/shims (et /opt/homebrew/bin si asdf a été installé via Homebrew) :

{
  "name": "Mon application Phoenix",
  "directory": "~/Code/mon-app",
  "paths": ["~/.asdf/shims", "/opt/homebrew/bin"],
  "startCommands": [
    { "label": "Server", "command": "mix", "args": ["phx.server"],
      "startupCheck": "http://localhost:4000/health", "startupFallbackPort": 4000 }
  ]
}

Vérifications d'état (Sondes)

Une probe est un type d'outil qui interroge un point d'extrémité arbitraire à son propre intervalle. Les sondes sont indépendantes de tout service géré par Runyard — vous pouvez sonder une API distante, une base de données locale, ou n'importe quoi qui parle HTTP ou accepte une connexion TCP.

Les sondes apparaissent comme des lignes dans le menu avec un point d'état en direct :

Lorsqu'une sonde est en échec, un petit triangle d'avertissement rouge apparaît à côté de l'icône Runyard dans la barre de menus, et tout groupe contenant la sonde en échec affiche le même triangle à côté de son nom dans le menu déroulant.

Schéma d'une sonde

{
  "name": "Production API",
  "type": "probe",
  "autoStart": true,            // optionnel, par défaut true
  "interval": 30,               // optionnel, secondes; défaut 30, minimum 5
  "failureThreshold": 2,        // optionnel, vérifications consécutives échouées avant de marquer en échec; défaut 2, minimum 1

  // Sonde HTTP (mutuellement exclusive avec tcp)
  "http": {
    "url": "https://api.example.com/health",
    "expectStatus": 200,                    // optionnel; int ou [int]; défaut 200
    "expectBodyContains": "ok",             // optionnel; sous-chaîne sensible à la casse
    "requestTimeout": 5                     // optionnel; secondes; défaut 5
  },

  // Sonde TCP (mutuellement exclusive avec http)
  "tcp": {
    "host": "db.internal",
    "port": 5432,
    "connectTimeout": 3                     // optionnel; secondes; défaut 3
  }
}

Une sonde doit spécifier exactement un des deux : http ou tcp.

Seuil d'échec

Une sonde bascule en échec après failureThreshold vérifications consécutives échouées (défaut 2), et revient à saine après 1 vérification réussie. Le seuil évite les oscillations sur des coupures réseau transitoires tout en faisant remonter les vraies pannes en un seul intervalle. Définissez failureThreshold: 1 pour une sonde agressive qui bascule à la première erreur, ou une valeur plus élevée pour plus de tolérance.

Mettre en pause / reprendre depuis le menu

Cliquez sur l'icône pause/lecture à droite d'une ligne de sonde pour suspendre ou reprendre la vérification. Le nouvel état est écrit dans votre config.json (le champ autoStart). Le menu ne se ferme pas.

Sous-menu par sonde

Chaque ligne de sonde a un sous-menu contenant :

Sondes à l'intérieur des groupes

Le tableau tools d'un outil de type group peut contenir des entrées probe aux côtés de services et de raccourcis. Les sondes en échec à l'intérieur d'un groupe s'affichent comme un triangle rouge sur l'élément de menu parent du groupe.

Action healthCheck ponctuelle

Le tableau actions de tout outil peut inclure une action de type healthCheck. Cliquer dessus lance une vérification ad-hoc et met à jour l'étiquette de l'action en ligne pendant ~3 secondes avec le résultat.

"actions": [
  {
    "label": "Verify Staging",
    "healthCheck": {
      "http": {
        "url": "https://staging.example.com/health",
        "expectStatus": 200
      }
    }
  }
]

La forme de l'action healthCheck reflète le bloc http ou tcp d'une sonde, moins les champs d'exécution (interval, autoStart).

Exemple complet

{
  "paths": ["~/.nvm/versions/node/v22.0.0/bin", "/opt/homebrew/bin"],
  "tools": [
    {
      "name": "MyApp",
      "directory": "~/Code/my-app",
      "autoStart": true,
      "installCommand": { "command": "npm", "args": ["install"] },
      "startCommands": [
        { "label": "Backend",  "command": "npm", "args": ["run", "dev"],
          "startupCheck": "http://localhost/api/health", "startupFallbackPort": 3001 },
        { "label": "Frontend", "command": "npm", "args": ["run", "dev"],
          "workingDir": "frontend", "startupFallbackPort": 5173, "waitFor": "Backend" }
      ],
      "actions": [
        { "label": "Ouvrir le frontend",  "url": "http://localhost:{{port}}/" },
        { "label": "API Docs",            "url": "http://localhost:{{port:Backend}}/api/docs" },
        { "label": "Amorcer la base",     "command": "npm", "args": ["run", "db:seed"] },
        { "label": "Ouvrir dans Cursor",  "command": "cursor", "args": ["."], "showWhen": "always" },
        { "label": "Ouvrir le projet",    "reveal": ".", "showWhen": "always" }
      ]
    },
    {
      "name": "Liens rapides",
      "type": "shortcut",
      "actions": [
        { "label": "Grafana", "url": "https://grafana.example.com" },
        { "label": "Jira",    "url": "https://jira.example.com" }
      ]
    }
  ],
  "advanced": {
    "startupTimeout": 45.0,
    "startupPollInterval": 1.0
  }
}