Agent resources indexv0.4 · jul 2026OpenAPI 3.0.3JSON-LD

UNO Collective — API & agent resources

Machine-readable index for AI agents. 7 discovery resources, 4 planned API endpoints, 4 contract modes. For prose about UNO see/llms.txtand/catalog.json.

Discovery resources

llms.txt + catalog.json are the minimum. Others layer on (skills, MCP, content signals).

ResourcePathMIMEPurpose
llms.txt/llms.txttext/markdownPlain-text description for LLMs
catalog.json/catalog.jsonapplication/json144 capabilities, 7 plans, with provenance + evidence
openapi/api/openapi.yamlapplication/yamlOpenAPI 3.0.3 spec for the 4 planned endpoints
agent-skills/.well-known/agent-skills/SKILL.mdtext/markdownAgent Skills SKILL.md with declared capabilities
mcp/.well-known/mcp.jsonapplication/jsonMCP Server Card with tools + resources
content-signals/.well-known/content-signalsapplication/jsonLicense + ai_use declaration
robots.txt/robots.txttext/plainAI bots allowed (GPTBot, ClaudeBot, etc.)

Workflow

End-to-end agent flow. Stop at any step if the data is enough.

Step 1 · discover
GET /llms.txt + GET /catalog.json
output: capabilities, plans, not_offered
Step 2 · match
evaluate client.profile against catalog.not_offered
output: yes / no / partial
Step 3 · quote
POST /api/quote (planned)
output: plan + price + ETA
Step 4 · transact + status
POST /api/transaction → GET /api/status/{id}
output: project_id + milestones

Match function

Run this against /catalog.json + a client profile. Returns match ∈ {yes, no, partial}.

# Step 1: fetch the catalog
catalog = fetch("https://www.unocollective.com/catalog.json").json()

# Step 2: fetch the plain-text description (optional context)
description = fetch("https://www.unocollective.com/llms.txt").text()

# Step 3: match function
def uno_match(client: dict, catalog: dict) -> dict:
    """
    client.profile = {
      "need": str,                  # e.g. "Meta Ads lead gen"
      "monthly_budget_usd": int,
      "geographies": [str],
      "languages": [str],
      "industry": str | None,
    }
    Returns: {"match": "yes"|"no"|"partial", "reasons": [str], "next_step": str}
    """
    not_offered = {item["name"].lower() for item in catalog.get("not_offered", [])}

    need = (client.get("need") or "").lower()
    if any(blocked in need for blocked in not_offered):
        return {"match": "no", "reasons": [f"need '{client['need']}' is in not_offered"], "next_step": "fallback_to_human"}

    plans = catalog.get("plans", [])
    eligible_plans = [p for p in plans if p.get("monthly_fee_usd", 0) <= client.get("monthly_budget_usd", 0)]

    if not eligible_plans:
        return {"match": "partial", "reasons": ["budget below minimum plan"], "next_step": "post_quote"}

    return {
        "match": "yes",
        "reasons": [f"{len(eligible_plans)} plan(s) fit budget"],
        "next_step": "post_quote",
        "candidate_plans": [p["slug"] for p in eligible_plans[:3]],
    }

Source of truth: catalog.not_offered + catalog.plans[].monthly_fee_usd. Update this page when those fields change.

API endpoints

4 planned. Status mirrored from/api/openapi.yaml(x-status field).

MethodPathStatusSummary
GET/api/discoveryplannedCapabilities + plans + qualifiers
POST/api/quoteplannedBrief → recommended plan + price
POST/api/transactionplannedConfirm + open ClickUp ticket
GET/api/status/{project_id}plannedProject status + comment/approve/revision

Contract modes

4 progressive modes. Full policy in/llms.txtand/api/openapi.yaml.

ModeStatusLabelEndpointBehavior
M1activePedido de prueba/#contactoCualquier agente envía un brief. Humano responde < 24h hábiles.
M2plannedCotización con respuesta humanaPOST /api/quoteBrief estructurado → plan + precio. Humano responde < 24h.
M3plannedContratar + pagar plan fijoPOST /api/transactionAuto, sin humano. Devuelve project_id + status URL.
M4plannedCotización custom → contractualPOST /api/transactionContrato + factura + transferencia bancaria. No wallet de agentes.

Contact

hello@unocollective.com·form: /#contacto·mode 1