{
  "openapi": "3.1.0",
  "info": {
    "title": "Swarm Science coordination API",
    "version": "0.3.0",
    "summary": "Invitation-only coordination for contributed model allowance.",
    "description": "The service coordinates work. It never invokes model providers, accepts provider credentials, executes contributed code, or fetches artifact URLs. Authority always travels in the Authorization header."
  },
  "servers": [{"url": "https://dangirsh.org/swarm-science/api"}],
  "security": [{"bearerAuth": []}],
  "tags": [
    {"name": "public"},
    {"name": "contributor"},
    {"name": "owner"},
    {"name": "manager"}
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": ["public"], "summary": "Service health", "security": [],
        "responses": {"200": {"description": "Healthy", "content": {"application/json": {"example": {"ok": true, "version": "0.3.0"}}}}}
      }
    },
    "/v1/capabilities": {
      "get": {
        "tags": ["public"], "summary": "Protocol capabilities", "security": [],
        "responses": {"200": {"description": "Capabilities", "content": {"application/json": {"example": {
          "protocol_version": "0.3.0",
          "allowance_unit": "claude_included_allowance_pct",
          "allowance_window": "seven_day",
          "mcp_endpoint": "/swarm-science/mcp"
        }}}}}
      }
    },
    "/v1/boundary": {
      "get": {
        "tags": ["public"], "summary": "The standing authorization boundary and its digest", "security": [],
        "responses": {"200": {"description": "Boundary", "content": {"application/json": {"example": {
          "boundary": {
            "protocol_version": "0.3.0",
            "allowance_unit": "claude_included_allowance_pct",
            "allowance_window": "seven_day",
            "projects_per_contributor": 1,
            "tool_namespace": "mcp__swarm__",
            "remote_tools": ["next_work", "store_artifact", "submit_work", "release_work", "status", "withdraw"],
            "max_risk": "low",
            "recurring_local_access": "read one runner folder and keep one daily Claude Code schedule",
            "provider_credentials": "never sent to Swarm Science",
            "arbitrary_urls": false,
            "arbitrary_commands": false,
            "paid_overage": false
          },
          "boundary_sha256": "64 hexadecimal characters"
        }}}}}
      }
    },
    "/v1/admin/projects": {
      "post": {
        "tags": ["owner"], "summary": "Create a project with its initial graph",
        "description": "Requires the service administrator bearer authority.",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProjectCreate"}}}},
        "responses": {"201": {"description": "Created", "content": {"application/json": {"example": {
          "project_id": "prj_0123456789abcdef", "owner_token": "one-time owner authority", "coordinator_token": "one-time manager authority"}}}}}
      }
    },
    "/v1/projects/{project_id}/coordinator/bind": {
      "post": {
        "tags": ["owner"], "summary": "Bind the owner-controlled project manager agent",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {"agent_name": "Project manager agent"}}}},
        "responses": {"200": {"description": "Bound", "content": {"application/json": {"example": {
          "coordinator_id": "coord_0123456789abcdef", "coordinator_token": "manager authority", "heartbeat_ttl": 172800}}}}}
      }
    },
    "/v1/projects/{project_id}/coordinator/heartbeat": {
      "post": {
        "tags": ["manager"], "summary": "Record manager liveness",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "responses": {"200": {"description": "Active", "content": {"application/json": {"example": {
          "active": true, "heartbeat_at": 1787600000, "heartbeat_ttl": 172800}}}}}
      }
    },
    "/v1/projects/{project_id}/invites": {
      "post": {
        "tags": ["owner"], "summary": "Create a one-use invitation",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {"max_uses": 1, "expires_in": 604800}}}},
        "responses": {"201": {"description": "Created", "content": {"application/json": {"example": {
          "invite_id": "inv_0123456789abcdef", "invite_token": "one-use invitation authority", "expires_at": 1788200000}}}}}
      }
    },
    "/v1/projects/{project_id}/invite-preview": {
      "post": {
        "tags": ["public"], "summary": "Resolve an invitation before joining",
        "description": "The invitation authority travels in the Authorization header.",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "responses": {"200": {"description": "Preview", "content": {"application/json": {"example": {
          "protocol_version": "0.3.0",
          "project_id": "prj_0123456789abcdef",
          "name": "Synthetic tide study",
          "purpose": "Exercise coordination with no real project data.",
          "coordinator_name": "Project manager agent",
          "coordinator_active": true,
          "boundary_sha256": "64 hexadecimal characters",
          "allowance_defaults": {
            "unit": "claude_included_allowance_pct", "window": "seven_day",
            "min_cap_pct": 1.0, "max_cap_pct": 50.0,
            "default_reserve_pct": 20.0, "five_hour_pacing_reserve_pct": 30.0}
        }}}}}
      }
    },
    "/v1/projects/{project_id}/join": {
      "post": {
        "tags": ["contributor"], "summary": "Grant standing project authorization",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Join"}, "example": {
          "display_name": "Contributor", "consent": true,
          "boundary_sha256": "64 hexadecimal characters",
          "allowance": {"unit": "claude_included_allowance_pct", "window": "seven_day", "cap_pct": 5, "reserve_pct": 20}}}}},
        "responses": {
          "201": {"description": "Joined", "content": {"application/json": {"example": {
            "member_id": "mem_0123456789abcdef", "member_token": "project membership authority",
            "authorization": {"version": "0.3.0", "project_id": "prj_0123456789abcdef", "cap_pct": 5,
              "reserve_pct": 20, "max_risk": "low", "tool_namespace": "mcp__swarm__",
              "boundary_sha256": "64 hexadecimal characters", "granted_at": 1787600000}}}}},
          "409": {"$ref": "#/components/responses/Gate"}
        }
      }
    },
    "/v1/projects/{project_id}/next-work": {
      "post": {
        "tags": ["contributor"], "summary": "Rank, claim, and lease the next eligible assignment",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TelemetryEnvelope"}}}},
        "responses": {
          "200": {"description": "Assigned or refused", "content": {"application/json": {"example": {
            "assigned": true, "lease_id": "lease_0123456789abcdef", "lease_expires_at": 1787601800,
            "work": {"assignment_id": "lease_0123456789abcdef", "title": "Survey evidence",
              "description": "Produce a bounded source survey.", "acceptance": ["Cites primary sources"],
              "artifact_types": ["text"], "project_name": "Synthetic tide study",
              "project_purpose": "Exercise coordination with no real project data."},
            "accepted_upstream": [{"evidence": {"finding": "synthetic"},
              "artifact_sha256": "64 hexadecimal characters",
              "artifact_uri": "swarm://artifact/64 hexadecimal characters"}]}}}},
          "400": {"$ref": "#/components/responses/Telemetry"},
          "409": {"$ref": "#/components/responses/Gate"}
        }
      }
    },
    "/v1/projects/{project_id}/artifacts": {
      "post": {
        "tags": ["contributor"], "summary": "Store a bounded content-addressed artifact",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {
          "content": "# Survey\n\nBounded evidence.", "media_type": "text/markdown"}}}},
        "responses": {"201": {"description": "Stored", "content": {"application/json": {"example": {
          "artifact_sha256": "64 hexadecimal characters",
          "artifact_uri": "swarm://artifact/64 hexadecimal characters",
          "bytes": 30, "stored": true}}}}}
      }
    },
    "/v1/projects/{project_id}/artifacts/{artifact_sha256}": {
      "get": {
        "tags": ["manager"], "summary": "Read a stored artifact",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}, {"$ref": "#/components/parameters/ArtifactSha"}],
        "responses": {"200": {"description": "Artifact"}}
      }
    },
    "/v1/projects/{project_id}/work/submit": {
      "post": {
        "tags": ["contributor"], "summary": "Submit the stored artifact with fresh telemetry",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {
          "artifact_sha256": "64 hexadecimal characters", "evidence": {"finding": "Bounded evidence survey"},
          "checks": ["acceptance checklist"],
          "telemetry": {"five_hour": {"used_percentage": 26, "resets_at": 1787581800},
                        "seven_day": {"used_percentage": 12, "resets_at": 1787932800}}}}}},
        "responses": {"200": {"description": "Receipt", "content": {"application/json": {"example": {
          "receipt_id": "receipt_0123456789abcdef",
          "allowance": {"unit": "claude_included_allowance_pct", "window": "seven_day",
            "charged_pct": 1.0, "estimated": false, "window_resets_at": 1787932800}}}}}}
      }
    },
    "/v1/projects/{project_id}/work/release": {
      "post": {
        "tags": ["contributor"], "summary": "Return an unfinished assignment",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {"reason": "reserve reached"}}}},
        "responses": {"200": {"description": "Released"}}
      }
    },
    "/v1/projects/{project_id}/status": {
      "get": {
        "tags": ["contributor"], "summary": "Project-level contributor status",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "responses": {"200": {"description": "Status", "content": {"application/json": {"example": {
          "protocol_version": "0.3.0",
          "project": {"id": "prj_0123456789abcdef", "name": "Synthetic tide study", "purpose": "Exercise coordination with no real project data.", "status": "active"},
          "allowance": {"unit": "claude_included_allowance_pct", "window": "seven_day", "cap_pct": 5,
            "reserve_pct": 20, "estimated_used_pct": 1.0, "estimated_remaining_pct": 4.0, "window_resets_at": 1787932800},
          "latest_outcome": {"at": 1787600300, "result": "accepted", "note": "Meets acceptance."},
          "accepted_results": [{"artifact_uri": "swarm://artifact/64 hexadecimal characters",
            "artifact_sha256": "64 hexadecimal characters", "accepted_at": 1787600300}],
          "active": true, "authorization_current": true, "coordinator_active": true}}}}}
      }
    },
    "/v1/projects/{project_id}/withdraw": {
      "post": {
        "tags": ["contributor"], "summary": "Withdraw the standing authorization",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "responses": {"200": {"description": "Withdrawn", "content": {"application/json": {"example": {"withdrawn": true}}}}}
      }
    },
    "/v1/projects/{project_id}/reviews": {
      "post": {
        "tags": ["manager"], "summary": "Commit a batch of submission reviews",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {"decisions": [
          {"task_id": "survey", "decision": "accept", "notes": "Meets every acceptance check."}
        ]}}}},
        "responses": {"200": {"description": "Reviewed"}}
      }
    },
    "/v1/projects/{project_id}/close": {
      "post": {
        "tags": ["owner"], "summary": "Close a completed project",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {"note": "Project complete"}}}},
        "responses": {"200": {"description": "Closed", "content": {"application/json": {"example": {
          "status": "closed", "closed_at": 1787601000, "note": "Project complete"}}}}}
      }
    },
    "/v1/projects/{project_id}/tasks/{task_id}": {
      "put": {
        "tags": ["manager"], "summary": "Create or replace a task definition",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}, {"$ref": "#/components/parameters/TaskId"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Task"}}}},
        "responses": {"200": {"description": "Defined"}}
      }
    },
    "/v1/projects/{project_id}/tasks/{task_id}/review": {
      "post": {
        "tags": ["manager"], "summary": "Accept or reject a submission",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}, {"$ref": "#/components/parameters/TaskId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {"decision": "accept", "notes": "Meets acceptance."}}}},
        "responses": {"200": {"description": "Reviewed", "content": {"application/json": {"example": {
          "task_id": "survey", "state": "accepted", "review_id": "review_0123456789abcdef", "graph_version": 7}}}}}
      }
    },
    "/v1/projects/{project_id}/tasks/{task_id}/invalidate": {
      "post": {
        "tags": ["manager"], "summary": "Invalidate a result and block its dependents",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}, {"$ref": "#/components/parameters/TaskId"}],
        "requestBody": {"required": true, "content": {"application/json": {"example": {"reason": "Evidence superseded"}}}},
        "responses": {"200": {"description": "Invalidated"}}
      }
    },
    "/v1/projects/{project_id}/snapshot": {
      "get": {
        "tags": ["manager"], "summary": "Project view for the owner or manager",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"}],
        "responses": {"200": {"description": "Snapshot"}}
      }
    },
    "/v1/projects/{project_id}/events/{cursor}": {
      "get": {
        "tags": ["manager"], "summary": "Append-only audit page",
        "parameters": [{"$ref": "#/components/parameters/ProjectId"},
          {"name": "cursor", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 0}}],
        "responses": {"200": {"description": "Events"}}
      }
    }
  },
  "components": {
    "securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer"}},
    "parameters": {
      "ProjectId": {"name": "project_id", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^prj_[A-Za-z0-9_-]+$"}},
      "TaskId": {"name": "task_id", "in": "path", "required": true, "schema": {"type": "string", "maxLength": 80}},
      "ArtifactSha": {"name": "artifact_sha256", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^[0-9a-f]{64}$"}}
    },
    "responses": {
      "Telemetry": {"description": "Allowance telemetry is missing or malformed, so no project work happens",
        "content": {"application/json": {"example": {"error": {"code": "telemetry_required", "message": "Fresh Claude allowance telemetry is required"}}}}},
      "Gate": {"description": "A safety gate stopped the request",
        "content": {"application/json": {"example": {"error": {"code": "reserve_reached", "message": "Your personal reserve protects the rest of this window"}}}}}
    },
    "schemas": {
      "Allowance": {
        "type": "object", "additionalProperties": false,
        "required": ["cap_pct"],
        "properties": {
          "unit": {"const": "claude_included_allowance_pct"},
          "window": {"const": "seven_day"},
          "cap_pct": {"type": "number", "minimum": 1, "maximum": 50},
          "reserve_pct": {"type": "number", "minimum": 5, "maximum": 90, "default": 20}
        }
      },
      "Join": {
        "type": "object", "additionalProperties": false,
        "required": ["display_name", "consent", "boundary_sha256", "allowance"],
        "properties": {
          "display_name": {"type": "string", "maxLength": 80},
          "consent": {"const": true},
          "boundary_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
          "allowance": {"$ref": "#/components/schemas/Allowance"},
          "capabilities": {"type": "array", "items": {"type": "string"}, "maxItems": 24},
          "prohibited_capabilities": {"type": "array", "items": {"type": "string"}, "maxItems": 24}
        }
      },
      "Telemetry": {
        "type": "object", "additionalProperties": false,
        "required": ["five_hour", "seven_day"],
        "properties": {
          "five_hour": {"$ref": "#/components/schemas/Window"},
          "seven_day": {"$ref": "#/components/schemas/Window"}
        }
      },
      "Window": {
        "type": "object", "additionalProperties": true,
        "required": ["used_percentage", "resets_at"],
        "properties": {
          "used_percentage": {"type": "number", "minimum": 0, "maximum": 100},
          "resets_at": {"type": "integer", "minimum": 1}
        }
      },
      "TelemetryEnvelope": {
        "type": "object", "additionalProperties": false, "required": ["telemetry"],
        "properties": {"telemetry": {"$ref": "#/components/schemas/Telemetry"}}
      },
      "ProjectCreate": {
        "type": "object", "additionalProperties": false,
        "required": ["name", "purpose", "owner_name", "coordinator_name", "tasks"],
        "properties": {
          "name": {"type": "string", "maxLength": 120},
          "purpose": {"type": "string", "maxLength": 1200},
          "owner_name": {"type": "string", "maxLength": 120},
          "coordinator_name": {"type": "string", "maxLength": 120},
          "tasks": {"type": "array", "maxItems": 5000, "items": {"$ref": "#/components/schemas/Task"}}
        }
      },
      "Task": {
        "type": "object", "additionalProperties": false,
        "required": ["id", "title", "description"],
        "properties": {
          "id": {"type": "string", "maxLength": 80},
          "title": {"type": "string", "maxLength": 160},
          "description": {"type": "string", "maxLength": 4000},
          "depends_on": {"type": "array", "items": {"type": "string"}, "maxItems": 24},
          "required_capabilities": {"type": "array", "items": {"type": "string"}, "maxItems": 24},
          "prohibited_capabilities": {"type": "array", "items": {"type": "string"}, "maxItems": 24},
          "risk": {"enum": ["low", "medium", "high"], "default": "low"},
          "estimated_credits": {"type": "integer", "minimum": 0, "maximum": 1000000},
          "priority": {"type": "integer", "minimum": 0, "maximum": 100},
          "acceptance": {"type": "array", "items": {"type": "string"}, "maxItems": 16},
          "artifact_types": {"type": "array", "items": {"type": "string"}, "maxItems": 12}
        }
      }
    }
  }
}
