{
 "openapi": "3.1.0",
 "info": {
  "title": "Loop Breaker",
  "version": "1.0.0",
  "description": "Catches your AI agent repeating the same failing step or tool call. Call check_step after each step; when the same call fails the same way 3 times, or runs 5 times in a row, Pro halts the run before it burns more time and money. Free watch-only mode never halts: it flags loops and drafts a weekly report. Pro is $9 a month. Free 500/day; Pro $9/month: https://pay.instaloops.com/b/eVqaEXbtS8QTgdxdgX83C3y"
 },
 "servers": [
  {
   "url": "https://loop.cloudforbots.com"
  }
 ],
 "components": {
  "securitySchemes": {
   "bearer": {
    "type": "http",
    "scheme": "bearer"
   }
  }
 },
 "paths": {
  "/api/run/check_step": {
   "post": {
    "operationId": "check_step",
    "summary": "Call AFTER each tool call or agent step with what you just did and whether it failed",
    "description": "Call AFTER each tool call or agent step with what you just did and whether it failed. Loop Breaker fingerprints the call (tool + normalized args + error) and returns verdict ok, loop_detected or halted. Pro: on a loop, halt=true; stop the run, do not retry, and tell your user what repeated. Free watch-only: never halts, returns would_halt and logs it for the weekly report.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "run_id": {
          "type": "string",
          "description": "Any stable id for this agent run, e.g. \"nightly-sync-2026-10-15\". Use the same id for every step of the run (and its sub-agents)."
         },
         "tool": {
          "type": "string",
          "description": "The tool or step name you just ran, e.g. \"browser.click\" or \"git push\"."
         },
         "args": {
          "description": "The arguments you passed (object or string). Volatile values like timestamps and ids are normalized away."
         },
         "error": {
          "type": "string",
          "description": "The error message if the step failed. Omit or empty if it succeeded."
         },
         "max_failures": {
          "type": "integer",
          "description": "Same failing call this many times = loop. Default 3 (min 2, max 20)."
         },
         "max_repeats": {
          "type": "integer",
          "description": "Same call this many times in a row (even if it succeeds) = loop. Default 5 (min 3, max 50)."
         }
        },
        "required": [
         "run_id",
         "tool"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/loop_status": {
   "post": {
    "operationId": "loop_status",
    "summary": "Show a run's loops so far, whether it is halted, and its last 10 steps.",
    "description": "Show a run's loops so far, whether it is halted, and its last 10 steps.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "run_id": {
          "type": "string",
          "description": "Any stable id for this agent run, e.g. \"nightly-sync-2026-10-15\". Use the same id for every step of the run (and its sub-agents)."
         }
        },
        "required": [
         "run_id"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/weekly_report": {
   "post": {
    "operationId": "weekly_report",
    "summary": "Draft a plain-English report of the last 7 days for your key (or IP): runs, loops caught, wasted repeat steps, and the worst offenders",
    "description": "Draft a plain-English report of the last 7 days for your key (or IP): runs, loops caught, wasted repeat steps, and the worst offenders. Read-only; sends nothing. Show it to your user.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {}
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/key": {
   "post": {
    "operationId": "get_free_key",
    "summary": "Get a free API key",
    "responses": {
     "200": {
      "description": "api_key"
     }
    }
   }
  }
 }
}