{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://promptprio.com/.well-known/agent-tasks.json",
  "title": "AceSchema v0 — agent-discoverable task queue manifest",
  "description": "Machine-readable manifest declaring this server's agent-task-queue conventions. Any MCP/REST agent can fetch this file, learn the canonical task envelope, agent capabilities, auth model, and discover the OpenAPI spec without trial-and-error. AceSchema is an open standard implemented by AcePilot OS tools (TaskPrio is the reference implementation).",
  "type": "object",
  "x-aceschema-version": "0.1.0",
  "x-acepilot-product": "TaskPrio",
  "x-implementor": {
    "name": "TaskPrio",
    "url": "https://taskprio.com",
    "source": "https://gitlab.com/acevault-lab/promptprio-com",
    "author": {
      "name": "Paulo Michael de Vries",
      "sameAs": [
        "https://www.linkedin.com/in/paulomichaeldevries/",
        "https://acevault.org"
      ]
    },
    "license": {
      "code": "MIT",
      "docs": "CC-BY-4.0"
    }
  },
  "x-discovery": {
    "well_known_uri": "https://promptprio.com/.well-known/agent-tasks.json",
    "openapi_uri": "https://promptprio.com/api/openapi.json",
    "openapi_version": "3.1",
    "llms_txt_uri": "https://taskprio.com/llms.txt",
    "docs_hub_uri": "https://taskprio.com/docs",
    "methodology_uri": "https://taskprio.com/methodology",
    "pricing_uri": "https://taskprio.com/pricing"
  },
  "x-api": {
    "base_url": "https://promptprio.com/api",
    "transport": [
      "rest",
      "mcp"
    ],
    "auth": {
      "model": "bearer",
      "header": "Authorization: Bearer <PROMPTPRIO_API_TOKEN>",
      "obtain": "Sign in at https://taskprio.com → Account → Copy token. Tokens are user-scoped, revocable, and never shown in chat.",
      "scope": "Per-user; reads + writes within the operator's own orgs/projects/tasks."
    },
    "rate_limits": {
      "free_tier_per_minute": 60,
      "pro_tier_per_minute": 600,
      "burst": "no separate burst window; per-minute is hard"
    }
  },
  "x-core-loop": {
    "description": "The 3-call cycle every agent runs against TaskPrio: ask for next, do the work, report back.",
    "steps": [
      {
        "step": 1,
        "verb": "ask",
        "rest": "GET /api/next",
        "mcp_tool": "get_next_task",
        "returns": "{ task: <Task | null>, lease: { expiresAt: <ISO8601>, sessionId: <string> } }",
        "behavior": "Returns the highest-ranked unblocked active task across all projects, leased to caller for 5 min. If nothing actionable, returns { task: null } — agent should stop, not retry."
      },
      {
        "step": 2,
        "verb": "do",
        "agent-side": "Agent reads task.title, task.body, task.subtasks, task.attachments, task.project.agentContext. Works the task. Generates a result string (audit trail)."
      },
      {
        "step": 3,
        "verb": "report",
        "rest": "POST /api/tasks/{id}/complete",
        "mcp_tool": "complete_task",
        "body": {
          "result": "<string · required · what the agent did or returned>"
        },
        "returns": "{ task: <updated Task> }",
        "behavior": "Closes the task, releases the lease, allows the next call to step 1 to pull the next-highest."
      }
    ],
    "edge_cases": {
      "needs_human": "If agent can't complete (missing context, ambiguous spec, requires operator decision), call POST /api/tasks/{id}/flag-needs-human with { reason: <string> }. Task exits the queue until the human resolves.",
      "lease_expiry": "If agent works longer than 5 min, lease auto-expires and task re-enters the pool. Other agents may pick it up. Safe to call POST /api/tasks/{id}/heartbeat to extend.",
      "concurrent_agents": "Multiple agents can call /api/next in parallel; each gets a different task. Lease mechanism prevents double-work."
    }
  },
  "x-entities": {
    "Task": {
      "id": {
        "type": "string",
        "format": "cuid",
        "example": "mpmsj6wsuv3889"
      },
      "title": {
        "type": "string",
        "maxLength": 240,
        "example": "Update fleet/CONCEPT_LIBRARY.md (PromptDesk absorption)"
      },
      "body": {
        "type": "string",
        "format": "markdown",
        "nullable": true
      },
      "status": {
        "enum": [
          "active",
          "completed",
          "trashed",
          "blocked"
        ]
      },
      "rank": {
        "type": "string",
        "description": "Fractional-index string; lexicographic ordering = priority order. Lower = higher priority.",
        "example": "000000Uzzz"
      },
      "ranked": {
        "type": "boolean",
        "description": "false = in Inbox (not yet triaged into the queue); true = in the ranked queue."
      },
      "projectId": {
        "type": "string",
        "format": "cuid",
        "nullable": true
      },
      "assignee": {
        "enum": [
          "human",
          "agent",
          "any"
        ]
      },
      "subtasks": {
        "type": "array",
        "items": {
          "title": "string",
          "done": "boolean"
        }
      },
      "attachments": {
        "type": "array",
        "items": {
          "kind": [
            "file",
            "link",
            "image"
          ],
          "url": "string",
          "name": "string"
        }
      },
      "properties": {
        "type": "object",
        "description": "Operator-defined single-select labels: Stage, Energy, Status, etc."
      },
      "leaseExpiresAt": {
        "type": "string",
        "format": "iso8601",
        "nullable": true
      },
      "leaseSessionId": {
        "type": "string",
        "nullable": true
      },
      "createdAt": {
        "type": "string",
        "format": "iso8601"
      },
      "completedAt": {
        "type": "string",
        "format": "iso8601",
        "nullable": true
      },
      "result": {
        "type": "string",
        "nullable": true,
        "description": "Agent's completion note. Required to close."
      }
    },
    "Project": {
      "id": {
        "type": "string",
        "format": "cuid"
      },
      "name": {
        "type": "string"
      },
      "color": {
        "type": "string",
        "format": "hex-color"
      },
      "agentContext": {
        "type": "string",
        "format": "markdown",
        "description": "Per-project agent instructions inherited by every task in this project. Working directory, code conventions, tone, citations rules, etc."
      },
      "organisationId": {
        "type": "string",
        "format": "cuid",
        "nullable": true
      }
    },
    "Organisation": {
      "id": {
        "type": "string",
        "format": "cuid"
      },
      "name": {
        "type": "string"
      },
      "color": {
        "type": "string",
        "format": "hex-color"
      }
    },
    "NextResponse": {
      "task": {
        "$ref": "#/x-entities/Task",
        "nullable": true
      },
      "lease": {
        "type": "object",
        "properties": {
          "expiresAt": {
            "type": "string",
            "format": "iso8601"
          },
          "sessionId": {
            "type": "string"
          }
        }
      }
    }
  },
  "x-agent-tools": {
    "description": "Canonical tool surface exposed by the MCP server at promptprio.com/mcp-server.js (auto-installed via promptprio.com/install.sh).",
    "tools": [
      {
        "name": "get_next_task",
        "description": "Pull the highest-priority unblocked task with full context + 5-min lease. Auto-scopes to the project (or organisation) matching the agent's working directory unless an explicit project is given.",
        "rest_equivalent": "GET /api/next"
      },
      {
        "name": "create_task",
        "description": "Add a task; lands in Inbox by default, or in the queue if rank is provided.",
        "rest_equivalent": "POST /api/tasks"
      },
      {
        "name": "triage_task",
        "description": "Move a task from Inbox to the ranked queue at a specified position.",
        "rest_equivalent": "POST /api/tasks/{id}/triage"
      },
      {
        "name": "reprioritize_task",
        "description": "Move a task to a new rank (between two other tasks).",
        "rest_equivalent": "PATCH /api/tasks/{id}/rank"
      },
      {
        "name": "schedule_task",
        "description": "Set a future activation time; task auto-promotes to the top at that time.",
        "rest_equivalent": "PATCH /api/tasks/{id}/schedule"
      },
      {
        "name": "complete_task",
        "description": "Close the task with a result string (audit trail).",
        "rest_equivalent": "POST /api/tasks/{id}/complete"
      },
      {
        "name": "flag_needs_human",
        "description": "Pause the task until a human resolves; useful when agent is stuck.",
        "rest_equivalent": "POST /api/tasks/{id}/flag-needs-human"
      },
      {
        "name": "list_tasks",
        "description": "Filtered task list (by status, project, assignee).",
        "rest_equivalent": "GET /api/tasks?filter=..."
      },
      {
        "name": "search_tasks",
        "description": "Full-text search across task title + body.",
        "rest_equivalent": "GET /api/search?q=..."
      },
      {
        "name": "export_queue",
        "description": "Dump the entire ranked queue as a single LLM-ready prompt text.",
        "rest_equivalent": "GET /api/export?format=llm-prompt"
      },
      {
        "name": "add_project",
        "description": "Create a new project (with optional agent-context).",
        "rest_equivalent": "POST /api/projects"
      },
      {
        "name": "update_task",
        "description": "Edit a task's fields (title, body, assignee, project, subtasks, etc.).",
        "rest_equivalent": "PATCH /api/tasks/{id}"
      },
      {
        "name": "list_projects",
        "description": "List all projects with ids + agent-context fields (workingDir, stack, repo, persona, commands, dontDo, definitionOfDone).",
        "rest_equivalent": "GET /api/projects"
      },
      {
        "name": "update_project",
        "description": "Set a project working directory (+ context fields). Set workingDir to the repo path so get_next_task auto-scopes there from then on.",
        "rest_equivalent": "PATCH /api/projects/{id}"
      }
    ]
  },
  "x-conventions": {
    "priority_order": "Single global ranked list across every project. Lower fractional-index rank string = higher priority. Inbox tasks (ranked:false) are not in the order until triaged.",
    "leasing": "5-minute hold per get_next_task call. Heartbeat to extend. Auto-release on expiry or complete.",
    "completion": "Every complete_task requires a non-empty result string. This is the audit trail for fully-autonomous loops.",
    "scheduled_tasks": "Tasks with a future scheduledAt timestamp auto-promote to the top of the queue at that time, ordered among each other by urgency.",
    "humans_and_agents_same_state": "Both call the same endpoints. No separate 'agent view' vs 'human view' — the queue you drag on the board is the queue your agent pulls from.",
    "reversibility": "Completed + trashed tasks are recoverable via status update. No hard deletes from agent surfaces."
  },
  "x-status": "v0 — stable enough for production agents but the spec is under active development. Subscribe to https://gitlab.com/acevault-lab/promptprio-com/-/tags for schema-version changes. Breaking changes will bump x-aceschema-version major.",
  "x-roadmap": [
    "v0.2 — formal JSON Schema definitions extracted into separate $ref files",
    "v0.3 — webhook delivery spec for task state changes",
    "v0.4 — AceProtocol open standard split (decouple AceSchema from taskprio.com)",
    "v1.0 — frozen API surface, semver guarantee on x-entities"
  ]
}
