{
  "service": "hostit",
  "version": "1",
  "apex": "https://hostit.mifcom.dev",
  "deploy_endpoint": "https://hostit.mifcom.dev/api/v1/deploy",
  "lookup_endpoint": "https://hostit.mifcom.dev/api/v1/projects/{name}",
  "url_template": "https://{name}.hostit.mifcom.dev",
  "name_rule": "^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$",
  "max_upload_bytes": 104857600,
  "max_extract_bytes": 524288000,
  "supported_types": ["static", "docker"],
  "type_detection": {
    "rule": "If 'Dockerfile' is at the upload root, type=docker; otherwise type=static.",
    "override_file": "hostit.json",
    "override_schema": {
      "type": "static|docker",
      "port": "int (Dockerfile apps only; default 3000; Coolify proxies HTTPS to this port)",
      "spa_fallback": "bool (static apps only; default true)"
    }
  },
  "deploy_request": {
    "method": "POST",
    "url": "https://hostit.mifcom.dev/api/v1/deploy",
    "body_options": [
      {
        "kind": "multipart/form-data",
        "fields": {
          "name": "string (required)",
          "tarball": "file (.tar.gz, required)",
          "password": "string (required only when updating an existing project; alternative: Authorization: Bearer <password>)"
        }
      },
      {
        "kind": "raw",
        "content_type": "application/gzip",
        "query": { "name": "string (required)" },
        "body": "raw .tar.gz bytes",
        "headers": { "Authorization": "Bearer <password>  (required only when updating)" }
      }
    ]
  },
  "deploy_response_first": {
    "url": "https://<name>.hostit.mifcom.dev",
    "password": "<save this; required for future updates>",
    "revision": "rev-...",
    "type": "static|docker",
    "size_bytes": 12345,
    "image": "<registry>/hostit-<name>:<revision>",
    "build_log_url": "/api/v1/projects/<name>/builds/<revision>"
  },
  "deploy_response_subsequent": {
    "url": "https://<name>.hostit.mifcom.dev",
    "password": null,
    "revision": "rev-...",
    "type": "static|docker"
  },
  "errors": {
    "401": "missing or invalid password",
    "409": "name reserved or build already in progress",
    "413": "upload too large",
    "422": "bad name, bad tarball, or build failed (response includes build_log_tail)"
  },
  "behind_the_scenes": [
    "1. hostit accepts the tarball, mints a per-project password (first deploy only) and stores its argon2id hash.",
    "2. For static uploads, hostit wraps the files in a tiny nginx image. For Dockerfile uploads, it builds the user's Dockerfile.",
    "3. The image is tagged 'hostit-<name>:<revision>' and pushed to a local Docker registry.",
    "4. hostit calls Coolify's API to create-or-update a Docker Image application named 'hostit-<name>' with domain '<name>.hostit.mifcom.dev'.",
    "5. Coolify pulls the image, runs it on the host, and adds a Traefik route. From that point on, requests to the project URL never touch hostit again.",
    "6. The user's project is now visible and managed in the Coolify UI like any other Coolify app."
  ],
  "agent_recipe": [
    "1. GET this URL to confirm capabilities.",
    "2. CRITICAL — Ask the user EXPLICITLY for the project name. Do NOT infer it from the working directory, package.json name, git repo name, or any other source. The name becomes a public subdomain (<name>.hostit.mifcom.dev) and is permanently locked to a password on first deploy, so the user must own this choice consciously. You may suggest a slug as a starting point, but wait for the user to confirm or correct before submitting. Constraints: 3-40 chars, lowercase alphanumeric + hyphens, no leading/trailing hyphen.",
    "3. GET /api/v1/projects/<name> — if {exists:true}, ask the user for the password they saved last time.",
    "4. tar+gzip the user's project directory (cd into it; tar czf - .).",
    "5. POST /api/v1/deploy with multipart fields {name, tarball, password?} OR raw application/gzip with ?name= and Authorization: Bearer.",
    "6. On 200, show the user the returned URL.",
    "7. If 'password' is a non-null string (first-ever deploy of this name), do ALL of: (a) save it to your own memory under a stable key like 'hostit:<name>' so you can reuse it for future updates this session, (b) show the password verbatim to the user, (c) explicitly ask them to store it in a password manager (1Password, Bitwarden, browser keychain) — emphasise it is shown only once by the API, has no recovery flow, and your memory copy is a convenience not a substitute for their own backup."
  ],
  "password_policy": {
    "where_returned": "POST /api/v1/deploy response, field 'password', only on the FIRST deploy of a given name.",
    "shown_once": true,
    "recovery": "none",
    "agent_must": [
      "save it to its own memory keyed by project name",
      "display the plaintext to the user",
      "instruct the user to store it in a password manager"
    ]
  }
}
