Le manifeste de l'application (app.json) déclare l'identité, les ressources et les exigences de votre application. Il se trouve à la racine du dépôt — ou dans un sous-répertoire si l'entrée du registre en spécifie un.
| Champ | Type | Description |
|---|---|---|
name | string | Identifiant unique, en kebab-case (p. ex. "oncall-watchtower") |
version | string | Version Semver (p. ex. "1.0.0") |
displayName | string | Nom lisible affiché dans l'App Store |
description | string | Courte description de ce que fait l'application |
| Champ | Type | Description |
|---|---|---|
author | string | Nom de l'auteur ou de l'équipe |
license | string | Identifiant de licence |
minKiroCrewVersion | string | Version minimale requise de Gateway |
tags | string[] | Étiquettes de découverte (p. ex. ["oncall", "monitoring"]) |
jobFamilies | string[] | Familles d'emplois auxquelles cette application s'applique |
| Champ | Type | Description |
|---|---|---|
agents | string[] | Chemins vers les fichiers JSON des agents (relatifs à la racine de l'application) |
skills | string[] | Chemins vers les répertoires de Skills |
sops | string[] | Chemins vers les fichiers SOP (procédure opérationnelle normalisée) |
mcpServers | object | Définitions des serveurs MCP (même format que mcp.json) |
| Champ | Type | Description |
|---|---|---|
repo | string | Nom du dépôt Git. Utilisé par le proxy blob pour servir les images |
iconPath | string | Chemin vers l'icône de l'application (PNG, carrée, min 256×256) |
screenshots | string[] | Chemins vers les captures d'écran (PNG/JPG, max 5) |
highlights | string[] | Points forts affichés sur la page de détails (max 10) |
L'illustration héros s'affiche sur les lignes de liste Discover, la mise en vedette, les cartes de fonctionnalités et la bannière de la page de détails.
| Champ | Objectif | Taille recommandée |
|---|---|---|
heroImage | Héros en thème clair | 1200×675 (16:9) |
heroImageDark | Variante en thème sombre | 1200×675 (16:9) |
heroImageDetail / heroImageDetailDark | Bannière de la page de détails uniquement (préférée à heroImage pour cet usage) | 1200×288 (25:6) |
Ordre de résolution sur chaque surface : illustration du thème actuel → celle du thème opposé → première capture d'écran → dégradé déterministe avec l'icône de l'application. L'absence d'image héros est gérée proprement.
La forme du chemin dépend de la distribution :
/apps/{name}/ui/ui/hero-light.svg); le registre la réécrit en URL de proxy blob{ "crons": [ { "name": "ticket-refresh", "every": 300, "message": "Check for new high-severity tickets" }, { "name": "daily-digest", "cron_expr": "0 9 * * 1-5", "message": "Generate daily digest", "agent": "digest-agent" } ] }
| Champ | Description |
|---|---|
name | Identifiant de la tâche |
every | Intervalle en secondes (s'exclut mutuellement avec cron_expr) |
cron_expr | Expression cron (s'exclut mutuellement avec every) |
message | Requête envoyée à l'agent à chaque exécution |
agent | Agent à exécuter (optionnel, utilise l'agent par défaut si omis) |
enabled | Par défaut true. Doit être un booléen JSON. false enregistre la tâche cron en pause (visible, reprenable) — pour les tâches qui nécessitent d'abord une configuration par l'utilisateur |
{ "ui": { "entry": "dist/index.mjs", "pages": [ { "route": "/apps/my-app", "label": "My App", "icon": "Shield", "entryPoint": "dist/page.mjs", "mountFunction": "mount" } ], "sidebar": { "section": "Apps", "order": 10 } } }
| Champ | Par défaut | Description |
|---|---|---|
ui.entry | Chemin vers le bundle ESM (relatif à la racine de l'application) | |
ui.pages[].route | Chemin URL de la page | |
ui.pages[].label | Étiquette dans la barre latérale | |
ui.pages[].icon | Nom d'icône Lucide (p. ex. "Shield", "Package") | |
ui.pages[].iconUrl | Chemin d'image d'icône personnalisée (relatif à ui/) | |
ui.pages[].entryPoint | Bundle ESM par page (remplace ui.entry) | |
ui.pages[].mountFunction | "mount" | Nom de la fonction exportée dans le bundle ESM |
ui.sidebar.section | "Apps" | Nom de la section dans la barre latérale |
ui.sidebar.order | 10 | Ordre de tri dans la section |
{ "backend": { "entryPoint": "backend/server.py", "port": "auto", "healthCheck": "/health", "routes": "/api/apps/oncall-watchtower" } }
| Champ | Par défaut | Description |
|---|---|---|
backend.entryPoint | Script à exécuter (relatif à la racine de l'application), ou un chemin de module Python en notation pointée lancé via python -m | |
backend.port | "auto" | Numéro de port ou "auto" pour l'attribution automatique |
backend.healthCheck | "/health" | Chemin du point de terminaison de vérification de santé |
backend.routes | Chemin de route de base pour le backend | |
backend.type | "" | Runtime : "python", "asgi", "node", "exec", ou "" (détection automatique à partir de entryPoint) |
Les backends d'application sont accessibles via le proxy inverse de la gateway à /apps/{name}/api/{path}, ce qui évite les problèmes CORS pour les pages UI du tableau de bord.
Au lieu d'un processus backend autonome (ou en complément), enregistrez des points d'entrée Python qui s'exécutent à l'intérieur du processus de la gateway :
{ "backend": { "hooks": { "routes": "backend.routes:register_routes", "on_startup": "backend.hooks:on_startup", "on_shutdown": "backend.hooks:on_shutdown" } } }
| Champ | Description |
|---|---|
backend.hooks.routes | Enregistre des gestionnaires dans le RouteRegistry interne de la gateway |
backend.hooks.on_startup | Invoqué lorsque les hooks de l'application sont branchés |
backend.hooks.on_shutdown | Invoqué lorsque l'application est désactivée |
Les hooks sont branchés à l'activation de l'application (via on_app_enable, également réexécuté au démarrage de la gateway) — aucun redémarrage de la gateway n'est requis.
{ "permissions": { "api": ["/api/crons", "/api/status", "/api/agents"], "events": ["notification", "slots"], "mcpTools": ["cron_add", "cron_list"], "storage": true, "cron": true, "memory": "app-scoped", "network": false } }
| Champ | Type | Description |
|---|---|---|
permissions.api | string[] | Préfixes de chemins API autorisés (appliqué actuellement) |
permissions.events | string[] | Types d'événements WebSocket autorisés |
permissions.mcpTools | string[] | Noms d'outils MCP autorisés |
permissions.storage | boolean | Peut utiliser le stockage propre à l'application |
permissions.cron | boolean | Peut créer des tâches cron |
permissions.memory | string | Accès à la mémoire : "", "app-scoped", ou "shared" |
permissions.network | boolean | Peut effectuer des requêtes réseau externes |
permissions.jobs | boolean | Peut exécuter des tâches serveur durables à l'aide du SDK Job de l'hôte; la tâche continue après que l'utilisateur a quitté la page de l'application |
Utilisez contributes lorsque votre application ajoute une ligne ou un contrôle compact à une surface gérée par Crew plutôt qu'à une page qui lui est propre.
Chaque entrée crée une ligne dans la barre de commandes Cmd+K. Son activation ouvre un nouveau clavardage initialisé par prompt; définissez autoSend seulement lorsque la commande déclare aussi un argument que la requête interpole avec {argument}.
{ "contributes": { "commands": [ { "id": "summarize-url", "title": "Summarize URL", "subtitle": "Start a research chat", "icon": "FileSearch", "keywords": ["research", "summary"], "prompt": "Summarize {argument} for this project.", "autoSend": true, "argument": { "kind": "url", "placeholder": "https://example.com", "hint": "Enter a public URL", "hosts": ["example.com"] } } ] } }
Les champs de commande requis sont id, title et prompt. subtitle, icon, keywords et autoSend sont facultatifs. Un argument facultatif possède kind ("text" ou "url"), ainsi que les champs facultatifs placeholder, hint, hosts et patternError. hosts n'est valide que pour un argument URL. L'hôte valide la déclaration; le code de l'application ne s'exécute pas dans la barre de commandes.
Une application peut placer jusqu'à deux contrôles actifs à côté des puces d'agent et de projet dans le composeur. Chacun est un module ESM chargé à la demande et reçoit l'identité de la session active depuis le tableau de bord.
{ "contributes": { "sessionControls": [ { "id": "environment", "entryPoint": "dist/session-control.mjs", "label": "Environment", "icon": "Server", "statusPath": "session-status" } ] } }
id et entryPoint sont requis. label, icon et statusPath sont facultatifs. Lorsqu'il est présent, statusPath est une route backend locale à l'application; le tableau de bord l'appelle avec l'identité de la session courante et attend { "state": "ok" | "warn" | "none", "tooltip": "..." }.
Une application peut ajouter jusqu'à huit onglets au panneau latéral du clavardage. Chaque entrée indique l'onglet, son texte de lancement et un module ESM dans le répertoire ui de l'application :
{ "contributes": { "panelTabs": [ { "id": "builds", "title": "Builds", "menuLabel": "Open builds", "menuDescription": "Inspect recent build results", "icon": "Hammer", "entry": "dist/builds-panel.mjs" } ] } }
id, title, menuLabel et entry sont requis. L'hôte charge le module uniquement lorsque l'application est activée.
Une application peut ajouter jusqu'à dix actions aux surfaces de fichiers. L'hôte transmet le chemin sélectionné au point de terminaison local de l'application lorsque l'utilisateur choisit la ligne.
{ "contributes": { "fileMenuItems": [ { "id": "publish-note", "label": "Publish note", "icon": "Upload", "endpoint": "/api/apps/my-app/publish", "surfaces": ["file-overflow", "tree-context", "folder-row"], "when": { "extensions": ["md"], "kinds": ["file"] } } ] } }
id, label, endpoint et au moins une surface prise en charge sont requis. when limite l'affichage de la ligne selon l'extension ou le type de nœud. Le point de terminaison demeure assujetti aux autorisations API de l'application.
{ "setup": { "onInstall": "cd ui && npm install && npm run build", "onUninstall": "echo cleanup done", "onUpdate": "cd ui && npm install && npm run build", "onEnable": "echo enabled", "onDisable": "echo disabled", "configSchema": {} } }
| Champ | Par défaut | Description |
|---|---|---|
setup.onInstall | "" | Commande shell exécutée après l'installation |
setup.onUninstall | "" | Commande shell exécutée avant la désinstallation |
setup.onUpdate | "" | Commande shell exécutée après la mise à jour |
setup.onEnable | "" | Commande shell exécutée à l'activation de l'application |
setup.onDisable | "" | Commande shell exécutée à la désactivation de l'application |
setup.onEnableTimeout | 30 | Délai d'expiration en secondes pour onEnable |
setup.onDisableTimeout | 30 | Délai d'expiration en secondes pour onDisable |
setup.configSchema | {} | Schéma JSON pour la configuration de l'application |
Les scripts s'exécutent avec set -euo pipefail imposé par Crew. Les variables non définies et les échecs de pipe entraînent une sortie immédiate — aucune erreur silencieuse.
Limites de délai d'expiration : onInstall / onUpdate = 300 s, onUninstall = 120 s, onEnable / onDisable = configurable (30 s par défaut).
Si onEnable échoue, l'activation est annulée — l'application reste désactivée et toute ressource enregistrée est désenregistrée. Les échecs de onDisable sont consignés comme avertissements mais ne bloquent pas la désactivation.
onUninstall reçoit KEEP_DATA=1 ou KEEP_DATA=0 dans l'environnement — si l'utilisateur a choisi « Conserver les données de l'application », le script doit éviter de supprimer les répertoires de données utilisateur.
{ "dependencies": { "managedBy": "gateway", "capabilities": { "mcp": [ { "id": "some-mcp-server", "source": "registry" } ], "skills": [ { "id": "some-skill", "source": "registry" } ] }, "commands": ["jq", "node", "python3"], "optionalCommands": ["git"] } }
| Champ | Par défaut | Description |
|---|---|---|
dependencies.managedBy | "gateway" | Qui gère le cycle de vie des dépendances : "gateway" ou "app" |
dependencies.capabilities.mcp | [] | Dépendances requises envers des serveurs MCP |
dependencies.capabilities.skills | [] | Dépendances requises envers des Skills |
dependencies.capabilities.agents | [] | Déprécié pour managedBy: "gateway" — toujours signalé comme non résolu |
dependencies.commands | [] | Commandes système requises; une commande manquante bloque l'installation |
dependencies.optionalCommands | [] | Commandes système vérifiées et signalées, mais qui ne bloquent jamais l'installation |
Les dépendances sont suivies dans un registre à comptage de références. À la désinstallation, Crew indique quelles dépendances peuvent être supprimées en toute sécurité par rapport à celles partagées avec d'autres applications.
| Champ | Par défaut | Description |
|---|---|---|
lifecycle | "gateway" | "gateway" (géré), "app" (autogéré), ou "locked" (ne peut être désinstallé) |
resources | "gateway" | "gateway" (Crew enregistre les agents/Skills/MCP) ou "app" (l'application gère les siennes) |
{ "platform": { "os": ["macos", "linux"], "arch": [], "installMode": "server", "clientInstall": { "shell": "curl -fsSL https://example.com/install.sh | bash", "postInstall": "open ~/Applications/MyApp.app" } } }
| Champ | Par défaut | Description |
|---|---|---|
platform.os | ["macos", "linux"] | Plateformes prises en charge |
platform.arch | [] (toutes) | Architectures prises en charge |
platform.installMode | "server" | "server" ou "client" |
platform.clientInstall.shell | Commande unique pour l'installation locale | |
platform.clientInstall.postInstall | Commande à exécuter après l'installation |
Lorsque installMode: "client", l'App Store affiche des instructions de terminal à copier-coller au lieu d'exécuter l'installation sur le serveur. À utiliser pour les applications qui doivent s'exécuter sur la machine locale de l'utilisateur (p. ex. les applications Electron lorsque Crew s'exécute sur un hôte distant).
{ "openCommand": "open ~/Applications/MyApp.app" }
Pour les applications qui s'exécutent hors du tableau de bord, openCommand déclare comment les lancer. POST /api/apps/{name}/open l'exécute en arrière-plan. Dans un environnement distant sans interface, le point de terminaison retourne plutôt la commande à exécuter localement.
Appliquées au moment de l'installation :
name doit correspondre à /^[a-z0-9]+(?:-[a-z0-9]+)*$/ (kebab-case)version doit correspondre au format semver (X.Y.Z)agents, skills, sops, ui.entry, ui.pages[].entryPoint, backend.entryPoint doivent être relatifs et rester à l'intérieur de la racine de l'application (les chemins absolus et la traversée .. sont rejetés via une résolution canonique et une vérification de confinement)backend.hooks.* sont vérifiés au niveau du format (module.path:callable, aucune traversée exprimable) et vérifiés en confinement au chargementmcpServers utilisent command / args / url / env — et non des chemins de fichiers relatifs à l'application — et ne sont pas vérifiées quant au cheminevery, soit cron_exprroute et un labelLes champs inconnus dans app.json sont préservés lors de l'analyse et retransmis intégralement via to_dict() / to_json(). Les nouvelles fonctionnalités du manifeste peuvent coexister avec des versions plus anciennes de Crew sans compromettre la validation.
{ "name": "oncall-watchtower", "version": "1.0.0", "displayName": "Oncall Watchtower", "description": "Monitor tickets, pipelines, and alarms for your on-call rotation", "author": "kirocrew", "tags": ["oncall", "monitoring"], "agents": ["agents/ticket-analyst.json"], "skills": ["skills/oncall-runbook"], "crons": [ { "name": "ticket-refresh", "every": 300, "message": "Check for new high-severity tickets" } ], "ui": { "entry": "dist/index.mjs", "pages": [ { "route": "/apps/oncall-watchtower", "label": "Oncall", "icon": "Shield" } ] }, "permissions": { "api": ["/api/crons", "/api/status"], "events": ["notification"] }, "platform": { "os": ["macos", "linux"] } }
Référence du manifeste