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 | requis | "service", "shortcut", "group" ou "healthCheck" (voir Types d'outils). |
directory |
string | requis* | Service uniquement. Racine du projet (~ est développé). Les commandes s'exécutent depuis ce dossier sauf si workingDir est défini. Ignoré sur les autres types d'outils. |
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 (service) / true (vérification d'état) |
Démarre automatiquement cet outil au lancement de Runyard. Par défaut false pour les services ; les vérifications d'état sont à true par défaut (elles sondent sauf si vous mettez false). |
keepSystemAwake |
booléen | false |
Lorsque le service tourne, empêche le système de se mettre en veille. Voir Garder éveillé. |
keepDisplayAwake |
booléen | false |
Lorsque le service tourne, empêche aussi l'écran de se mettre en veille. N'a aucun effet si keepSystemAwake n'est pas également true. |
installCommand |
objet | - | Commande à exécuter si le chemin de marquage est absent (voir Commande d'installation). |
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. directory est réservé aux services : il est ignoré sur les outils shortcut, group et healthCheck, et retiré du fichier lors de l'enregistrement.
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) |
"healthCheck" |
Pastille d'état + sondage HTTP/TCP périodique (voir Health Checks). | http OU tcp (exactement 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. |
argsest une liste d'arguments distincts, pas une ligne de commande. Chaque entrée est transmise à la commande telle quelle, comme un seul argument. Runyard ne la passe jamais par un shell, donc il ne sépare jamais une entrée sur les espaces. Placez chaque option ou valeur dans sa propre entrée :["run", "dev"], et non["run dev"]. Une entrée peut contenir des espaces lorsqu'elle doit parvenir au programme comme un seul argument (par exemple"--command=zsh -lc 'npm start'"). Cela s'applique àargspartout où il apparaît : commandes de démarrage, commandes d'arrêt, actions de type commande et commande d'installation.
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. Le champ requis type sélectionne le genre d'action : "url", "command", "reveal", "applescript", "applescriptFile" ou "healthCheck". Le champ de charge utile correspondant à ce type est obligatoire ; tout autre champ de charge utile est rejeté par la validation.
| Champ | Type | Valeur par défaut | Description |
|---|---|---|---|
label |
string | requis | Texte de l'élément de menu. |
type |
string | requis | L'une de "url", "command", "reveal", "applescript", "applescriptFile", "healthCheck". |
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. Sur un service, relatif au directory de l'outil ; sur un shortcut/group (sans directory), utilisez un chemin absolu ou ~. |
reveal |
string | - | Chemin à ouvrir dans le Finder. Sur un service, un chemin relatif est résolu par rapport au directory de l'outil ; sur un shortcut/group, utilisez un chemin absolu ou ~. |
applescript |
string | - | Code AppleScript inline. |
applescriptFile |
string | - | Chemin vers un fichier .applescript. |
showWhen |
string | "running" |
"always", "running" ou "stopped" (service uniquement). |
confirm |
boolean | false |
Si true, Runyard demande une confirmation avant d'exécuter l'action. |
Exemples d'actions
Ouvrir une URL :
{ "label": "Ouvrir le frontend", "type": "url", "url": "http://localhost:5173" }
Exécuter une commande shell :
{ "label": "Amorcer la base", "type": "command", "command": "npm", "args": ["run", "db:seed"] }
Ouvrir un fichier dans une application précise :
{ "label": "Éditer README", "type": "command", "command": "open", "args": ["-a", "TextEdit", "./README.md"], "showWhen": "always" }
Ouvrir un projet dans Cursor :
{ "label": "Ouvrir dans Cursor", "type": "command", "command": "cursor", "args": ["."], "showWhen": "always" }
Afficher un dossier dans le Finder :
{ "label": "Ouvrir le projet", "type": "reveal", "reveal": ".", "showWhen": "always" }
{ "label": "Ouvrir les logs du backend", "type": "reveal", "reveal": "backend/logs", "showWhen": "always" }
AppleScript inline :
{ "label": "Activer Safari", "type": "applescript", "applescript": "tell application \"Safari\" to activate", "showWhen": "always" }
AppleScript multiligne (utilisez \n) :
{
"label": "Mettre Safari au premier plan",
"type": "applescript",
"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", "type": "applescriptFile", "applescriptFile": "scripts/deploy.applescript", "showWhen": "always" }
Espaces réservés de port
Les URL d'action prennent en charge deux espaces réservés :
{{port}}: port détecté du dernier processus de l'outil.{{port:Label}}: port d'un processus précis, identifié par son étiquette.
{ "label": "API Docs", "type": "url", "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.
Confirmation avant exécution
Placez confirm à true sur une action et Runyard affichera une alerte de confirmation avant de l'exécuter. Pratique pour les actions destructives : tuer des serveurs de dev, vider un cache, supprimer une base de données.
{
"label": "Tuer les serveurs dev résiduels",
"type": "command",
"command": "pkill",
"args": ["-f", "next dev"],
"confirm": true,
"showWhen": "always"
}
Le bouton principal de l'alerte exécute l'action ; le bouton par défaut est Annuler, pour qu'un appui accidentel sur Retour ne déclenche rien.
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",
"enabled": true
}
| 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. |
enabled |
boolean | true |
Quand false, la commande d'installation est conservée dans le JSON mais ignorée au runtime. Permet de désactiver temporairement l'étape d'installation sans perdre la configuration. |
Comportement à trois états
| Configuration | État dans l'interface | Runtime |
|---|---|---|
installCommand absent |
« Activer l'installation automatique » désactivé, champs vides/placeholders | Jamais configuré ; aucune installation |
"installCommand": { …, "enabled": false } |
« Activer l'installation automatique » désactivé, champs remplis et grisés | Configuré mais ignoré ; données utilisateur conservées |
"installCommand": { …, "enabled": true } (ou enabled omis) |
« Activer l'installation automatique » activé, champs remplis | Configuré et exécuté au démarrage si le marqueur est absent |
Le commutateur Réglages → Tools → Commande d'installation se lie à enabled. Le désactiver ne supprime pas le reste de la configuration ; il définit simplement enabled: false.
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,
"logMaxFileSizeMB": 5,
"logKeepRotations": 3,
"logMaxAgeDays": 30
}
| 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. |
logMaxFileSizeMB |
5 |
Taille (Mo) qu'un journal peut atteindre avant que Runyard ne le fasse tourner. Les fichiers archivés sont renommés *.log.1, *.log.2.gz, etc., et compressés en gzip à partir de la deuxième rotation. Plage : 1–100. |
logKeepRotations |
3 |
Nombre d'archives conservées sur le disque pour chaque journal. Les plus anciennes sont supprimées à la prochaine rotation. Plage : 1–20. |
logMaxAgeDays |
30 |
Les journaux archivés plus vieux que cette valeur sont supprimés au démarrage de l'application. Le fichier .log en cours n'est jamais supprimé par âge. Plage : 1–365. |
Chemins et résolution du PATH
Les commandes s'exécutent via /usr/bin/env avec un PATH construit sur mesure. Les règles :
- Les
pathsglobaux sont inclus par défaut. - Les
pathspar outil sont fusionnés au-dessus des chemins globaux (globaux d'abord, puis ceux de l'outil). - Définissez
pathsOverride: truesur un outil pour remplacer entièrement les chemins globaux. À utiliser uniquement quand un outil entre en conflit avec des binaires globaux.
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",
"type": "service",
"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
Une vérification d'état est un type d'outil qui interroge un point d'extrémité arbitraire à son propre intervalle. Les vérifications d'état sont indépendantes de tout service géré par Runyard : vous pouvez interroger une API distante, une base de données locale, ou n'importe quoi qui parle HTTP ou accepte une connexion TCP.
Les vérifications d'état apparaissent dans le popover sous forme de cartes repliables propres (lorsqu'elles sont définies au niveau racine) ou de rangées compactes (lorsqu'elles sont imbriquées dans un groupe). La pastille d'état et le point d'état en direct vous indiquent ce qui se passe :
- Point vert / Healthy : la dernière vérification a réussi.
- Point rouge / Failing : 2 vérifications consécutives ou plus ont échoué (configurable via
failureThreshold). - Point gris / Paused : la vérification est suspendue, ou la première vérification n'est pas encore terminée (Unknown).
Lorsqu'une vérification d'état est en échec, un petit triangle d'avertissement rouge apparaît à côté de l'icône Runyard dans la barre de menus. Les groupes qui contiennent la vérification d'état en échec basculent aussi leur pastille agrégée en état d'avertissement.
Schéma d'une vérification d'état
{
"name": "Production API",
"type": "healthCheck",
"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
// Vérification 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
},
// Vérification TCP (mutuellement exclusive avec http)
"tcp": {
"host": "db.internal",
"port": 5432,
"connectTimeout": 3 // optionnel; secondes; défaut 3
}
}
Une vérification d'état doit spécifier exactement un des deux : http ou tcp.
Seuil d'échec
Une vérification d'état 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 vérification d'état agressive qui bascule à la première erreur, ou une valeur plus élevée pour plus de tolérance.
Mettre en pause / reprendre depuis le popover
Utilisez Pause / Resume pour suspendre ou reprendre le sondage. Sur une carte de niveau racine, le bouton vit dans la barre de boutons en pied de carte. Sur une rangée imbriquée dans un groupe, c'est un bouton-icône à droite de la rangée. Pause et Resume sont des contrôles d'exécution uniquement : ils ne modifient pas config.json, donc la vérification d'état respecte le champ autoStart au prochain lancement. Le popover ne se ferme pas.
Contrôles par vérification d'état
Une carte de vérification d'état au niveau racine affiche :
- Un en-tête avec le nom de la vérification d'état et une pastille Healthy / Failing / Paused / Unknown.
- Une ligne meta avec la dernière latence, un horodatage relatif « checked Xs ago » et l'intervalle de sondage (par exemple
247 ms · checked 12s ago · every 30s). - Un sparkline 20 barres des derniers échantillons de latence : vert pour les succès, rouge pleine hauteur pour les échecs.
- Un pied avec Pause / Resume, Check now (lance une vérification hors-bande sans affecter le minuteur régulier) et Logs (ouvre
~/Library/Logs/Runyard/{NomVerification}.logdans Console.app).
Cliquez-droit sur une rangée imbriquée pour copier l'URL du point d'extrémité (http://...) ou hôte:port dans le presse-papiers.
Statistiques de latence (p50 / p95 / moyenne)
Survolez la pastille d'état ou le sparkline pour ouvrir le popover des statistiques : p50 (médiane), p95 (queue lente), latence moyenne, et taux d'échec. Les statistiques sont calculées sur une fenêtre glissante d'une heure des sondages récents. La fenêtre est fixe et non configurable, choisie pour fournir suffisamment d'échantillons pour un p95 significatif à tout intervalle de sondage raisonnable (5 s à 60 s), tout en bornant l'utilisation mémoire.
La fenêtre est conservée en mémoire seulement et se réinitialise quand Runyard se ferme. Tant que cinq sondages réussis ne sont pas accumulés après un (re)démarrage ou après une longue période hors ligne, le popover affiche une vue « peu d'échantillons » avec la latence la plus récente au lieu du résumé complet.
Vérifications d'état à l'intérieur des groupes
Le tableau tools d'un outil de type group peut contenir des entrées healthCheck aux côtés de services et de raccourcis. Les vérifications d'état imbriquées en échec font basculer la pastille agrégée du groupe en état d'avertissement. Les rangées imbriquées s'affichent de manière compacte sans le sparkline. Promouvez-en une au niveau racine si vous voulez le sparkline + l'UI complète de la carte.
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",
"type": "healthCheck",
"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 vérification d'état, moins les champs d'exécution (interval, autoStart).
Garder éveillé
Activez keepSystemAwake: true sur un service pour empêcher macOS de se mettre en veille tant que ce service fonctionne. Runyard lance un caffeinate -i -w <pid> par processus de démarrage actif, donc le système reste éveillé tant qu'au moins un processus du service est vivant. Chaque assertion par processus se libère dès que son PID surveillé disparaît (arrêt propre, SIGKILL, ou crash), et l'assertion globale du service ne tombe que lorsque tous les processus de démarrage ont quitté. L'ordre des startCommands n'a aucune importance.
Ajoutez keepDisplayAwake: true pour aussi passer -d, qui empêche l'écran de s'assombrir ou de se verrouiller. C'est une option à activer manuellement, car elle accélère la décharge de la batterie.
{
"name": "Big Build",
"type": "service",
"directory": "~/Code/big-build",
"keepSystemAwake": true, // système éveillé pendant l'exécution
"keepDisplayAwake": false, // l'écran s'assombrit normalement (défaut)
"startCommands": [
{ "label": "Build", "command": "npm", "args": ["run", "build"] }
]
}
Les mêmes champs fonctionnent sur les outils healthCheck. Une vérification n'a pas de PID, donc Runyard maintient un caffeinate -i indéfini tant que la vérification est active (non mise en pause) et le libère dès que vous la mettez en pause, la retirez de la config, ou désactivez le champ.
{
"name": "Prod Status",
"type": "healthCheck",
"keepSystemAwake": true, // maintient caffeinate pendant le sondage
"interval": 30,
"http": { "url": "https://api.example.com/healthz", "expectStatus": 200 }
}
La même infrastructure caffeinate pilote aussi le bouton Garder éveillé du popover, un filet de sécurité manuel que vous pouvez activer sans modifier la configuration. Les activations manuelles, liées à un service et liées à une vérification peuvent toutes être actives en même temps ; chacune maintient sa propre assertion d'alimentation indépendante.
Limitation : macOS ne garde pas votre Mac éveillé lorsque le capot est fermé, quel que soit l'outil anti-veille utilisé. C'est une contrainte de sécurité thermique qui s'applique à tout outil basé sur caffeinate.
Popover de la barre de menus
Le popover est l'unique UI de barre de menus. Quelques clés UserDefaults pilotent son comportement :
Clé UserDefaults |
Type | Défaut | Description |
|---|---|---|---|
collapsed.{toolName} |
Bool |
false |
État réduit par carte. Écrit quand vous cliquez sur le chevron d'une carte ou sur le bouton Tout réduire / Tout déplier de l'en-tête. Restauré entre les lancements. |
popoverShowSummary |
Bool |
true |
Cache ou affiche la ligne N running · M errors dans l'en-tête du popover. |
popoverDefaultState |
String |
"lastUsed" |
État de réduction par défaut appliqué à chaque carte de premier niveau à chaque ouverture du popover. Défini par le sélecteur segmenté de Réglages → General → Popover. "expanded" force toutes les cartes ouvertes à chaque ouverture ; "collapsed" les force fermées ; "lastUsed" conserve la mémoire par carte. Les réductions manuelles pendant une session sont conservées jusqu'à la prochaine ouverture, puis réinitialisées (sauf en mode "lastUsed"). |
Ces clés vivent dans ~/Library/Preferences/ca.bonevil.runyard.plist. Modifiez-les avec defaults write ca.bonevil.runyard <clé> <valeur> si vous devez réinitialiser la mise en page depuis la ligne de commande.
Le popover est persistant par défaut. Il ne se ferme que sur Échap, un clic à l'extérieur, ou la perte de focus.
Exemple complet
{
"paths": ["~/.nvm/versions/node/v22.0.0/bin", "/opt/homebrew/bin"],
"tools": [
{
"name": "MyApp",
"type": "service",
"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", "type": "url", "url": "http://localhost:{{port}}/" },
{ "label": "API Docs", "type": "url", "url": "http://localhost:{{port:Backend}}/api/docs" },
{ "label": "Amorcer la base", "type": "command", "command": "npm", "args": ["run", "db:seed"] },
{ "label": "Ouvrir dans Cursor", "type": "command", "command": "cursor", "args": ["."], "showWhen": "always" },
{ "label": "Ouvrir le projet", "type": "reveal", "reveal": ".", "showWhen": "always" }
]
},
{
"name": "Liens rapides",
"type": "shortcut",
"actions": [
{ "label": "Grafana", "type": "url", "url": "https://grafana.example.com" },
{ "label": "Jira", "type": "url", "url": "https://jira.example.com" }
]
},
{
"name": "API de production",
"type": "healthCheck",
"interval": 30,
"failureThreshold": 2,
"http": {
"url": "https://api.example.com/health",
"expectStatus": 200,
"expectBodyContains": "ok"
}
}
],
"advanced": {
"startupTimeout": 45.0,
"startupPollInterval": 1.0
}
}