{
  "id": "osc-stack-diagnose-restart-my-app",
  "job": "When an app you run on Open Source Cloud breaks, ask your AI coding tool (Claude Code, Codex or any MCP client) to find out why, restart it if a restart will fix it, and confirm the new instance is serving. Starts from an app that already exists.",
  "aliases": [
    "my app is down, let claude code fix it",
    "ai agent diagnose and restart a broken app",
    "read my app logs and restart it from an mcp client",
    "why did my deploy fail"
  ],
  "distinctFrom": [
    {
      "stack": "deploy-agent-written-app",
      "difference": "That stack creates the app (create-my-app) and ends at wait-for-app-ready. This one starts from an existing appId, after that check returned failed or the app broke later. It never calls create-my-app."
    },
    {
      "stack": "provision-agent-backend",
      "difference": "That stack creates databases and storage. This one creates nothing; it reads, restarts and verifies."
    }
  ],
  "inputs": [
    {
      "protocol": "MCP",
      "source": "an MCP client connected to https://mcp.osaas.io/mcp (operator mode: read tools via osc_call_tool, restart via osc_write_tool)"
    },
    {
      "protocol": "My App",
      "source": "an app already deployed with create-my-app, identified by its appId from list-my-apps"
    }
  ],
  "outputs": [
    {
      "protocol": "report",
      "consumer": "the user",
      "content": "the cause the agent found (from diagnose-my-app and get-my-app-logs), what it did about it, and whether the new instance answered ready"
    }
  ],
  "recommendedPath": {
    "chain": [
      {
        "step": 1,
        "mcpTool": "list-my-apps",
        "role": "confirm the appId",
        "note": "Every My App tool asks for the appId to be confirmed this way first. After one 'App not found', do not retry with name variants; ask the user. If the thing that broke could be a catalog service (a database, storage) rather than a My App, use the service branch below instead."
      },
      {
        "step": 2,
        "mcpTool": "diagnose-my-app",
        "readOnly": true,
        "role": "one report: app details, build status, pod status, public URL health, /healthz dependency health, recent startup logs, parameter store binding, custom domain health, and a list of issues found",
        "note": "Read the build status and the logs, not only the public URL. In a read on 2026-10-11 of an app whose build had failed, the public URL still answered HTTP 200 (the runner's loading page listens on port 8080) while /healthz returned 500 and the logs showed the git clone failing with HTTP 500, so there was no package.json and the app exited with code 254."
      },
      {
        "step": 3,
        "mcpTool": "get-my-app-logs",
        "readOnly": true,
        "role": "full log lines when the report's excerpt is not enough",
        "note": "Call it WITHOUT level first. level=error matches /error/i and drops most framework startup output, so a crash at startup can look empty with the filter on. Use tail or since to narrow. If the logs show a git clone 403 or an authentication failure, follow the advisory to list-git-credentials and update-my-app-github-token, which applies the new token with a rolling restart, instead of calling restart-my-app."
      },
      {
        "step": 4,
        "mcpTool": "restart-my-app",
        "role": "restart, only when the cause is one a restart can fix",
        "note": "A restart pulls the latest commit from the app's git repository and restarts the container. So it cannot fix a source the platform cannot clone, and it will also deploy anything new on the branch. Use rebuild=true only when dependencies or the base image changed, or a plain restart did not help. If get-my-app shows haEnabled: true, rebuild=true is required. A rebuild failure is NOT returned by this tool; it shows up later as buildStatus 'failed'. If the tool returns status 'failed_rebuild', call it again at once with rebuild=true. A repeated_restart_warning means stop restarting and go back to diagnose-my-app."
      },
      {
        "step": 5,
        "mcpTool": "wait-for-app-ready",
        "readOnly": true,
        "role": "confirm the NEW instance is serving",
        "note": "Pass awaitNewGeneration: true, so the check waits for the new pod and not the old one still serving during the swap. Call again only while it returns checkAgain: true. If it reports buildStatus 'failed', or healthStatus 'not running', go back to step 2."
      }
    ],
    "serviceInstanceBranch": {
      "when": "the broken thing is a catalog service instance (PostgreSQL, MinIO, Valkey and so on), not a My App",
      "chain": [
        "list-service-instances",
        "get-logs-for-instance",
        "restart-service-instance",
        "get-instance-status"
      ],
      "note": "Not every service exposes a restart endpoint; restart-service-instance says so when it is unavailable."
    },
    "escalation": {
      "mcpTool": "submit-feedback",
      "note": "When a rebuild does not clear a crash the tool descriptions attribute to the platform (for example the config-fetch crash), report it with the app name and a log excerpt."
    },
    "tokensPerDay": null,
    "tokensPerDayBasis": "The chain creates no services, so it adds no new running cost. No figure is claimed for the tool calls themselves.",
    "measuredWallClockSeconds": null,
    "wallClockMeasured": false,
    "gapNote": "No timed end-to-end run of a break, diagnose, restart and recover cycle yet. Steps 1 and 2 were run read-only on 2026-10-11 against a real failed app; steps 4 and 5 were not run (nothing was restarted). Named gap, not a filled-in figure."
  },
  "boundaries": [
    "The platform does not restart a broken app on its own; this recipe is the agent doing it on request.",
    "A restart is not a fix for a cause in the code or in the source repository. Diagnose first.",
    "High availability (enable-app-ha) is for Node.js apps on paid plans; on an HA app a failed rebuild keeps the old slot serving, on a non-HA app it leaves the app unavailable until a build succeeds."
  ],
  "nextStep": {
    "page": "https://www.osaas.io/use-cases/observability",
    "why": "Watching the app over time (Grafana, Prometheus) is a different job from getting it running again."
  },
  "toolsVerifiedLive": {
    "date": "2026-10-11",
    "method": "osc_search_tools (operator mode) for list-my-apps, diagnose-my-app, get-my-app-logs, restart-my-app, wait-for-app-ready, get-my-app, enable-app-ha, list-service-instances, get-logs-for-instance, restart-service-instance, get-instance-status, submit-feedback; list-my-apps and diagnose-my-app called read-only via osc_call_tool."
  },
  "gateCheck": {
    "gatedServiceId": "eyevinn-just-go-live",
    "usesGatedService": false,
    "note": "This stack does not name or link eyevinn-just-go-live."
  },
  "verifiedOn": "2026-10-11",
  "publishedAt": "https://www.osaas.io/use-cases/diagnose-and-restart",
  "descriptorUrl": "https://www.osaas.io/stacks/diagnose-restart-my-app.json"
}
