{
  "name": "limlock",
  "description": "Coordination protocol for multi-principal group event planning, with golf as the reference vertical. Limlock receives intent descriptions from peer agents representing distinct human principals, intersects their constraints, and returns ranked booking options for the group to negotiate. Use when 2–4 humans are aligning on a shared activity and need to agree on dates, location, and budget before any single party commits. Limlock does not aggregate inventory, hold payment, or transact without end-user consent — committed demand routes through the course's own booking surface. Out of scope: non-golf coordination. Limlock supports solo intents but is purpose-built for multi-principal coordination — solo users are better served by the course's own booking surface in most cases. Course inventory in v0.1 is concentrated in Ontario, Canada; results outside Ontario will be sparse or empty until coverage expands.",
  "version": "0.1.0",
  "supportedInterfaces": [
    {
      "url": "https://api.limlock.com/a2a",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0.0"
    }
  ],
  "provider": {
    "organization": "Limlock",
    "url": "https://limlock.com"
  },
  "documentationUrl": "https://limlock.com/governance",
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "extendedAgentCard": false
  },
  "defaultInputModes": ["application/json"],
  "defaultOutputModes": ["application/json"],
  "skills": [
    {
      "id": "createIntent",
      "name": "Create a group-golf intent",
      "description": "Open a shared coordination intent for 1–4 golfers. The calling agent (acting on behalf of the round's organizer) supplies a home location (lat/lng), a search radius in km (default 50, max 200), the group size, and an optional message. Returns an intent ID and a shareable join URL the other participants pass into submitConstraints. Use this as the FIRST call when a user describes wanting to play golf with friends and a single party hasn't yet committed to a date or course. Do NOT use this to book a tee time directly — this is upstream of booking; use bookingHandoff once the group has voted. Course inventory in v0.1 is concentrated in Ontario, Canada; results outside Ontario will be sparse or empty. Typical triggers: \"plan a round with my buddies,\" \"set up golf with Matt and Dave,\" \"find a tee time the four of us can agree on.\"",
      "tags": ["coordination", "group-event", "golf", "intent", "create"],
      "examples": [
        "Plan a round with my buddies this weekend.",
        "Set up golf with Matt and Dave for next Saturday.",
        "Find a tee time the four of us can agree on."
      ],
      "inputModes": ["application/json"],
      "outputModes": ["application/json"]
    },
    {
      "id": "submitConstraints",
      "name": "Submit a participant's availability and preferences",
      "description": "Add one participant's constraints to an existing intent. Each call supplies that player's name, a list of dates they're available with per-date time windows (HH:MM earliest / latest), an optional max price in cents, a holes preference (9 or 18), and a cart-required flag. The intent collects up to groupSize constraint sets before resolving. Use this when a participant in an existing intent (identified by intentId) is communicating their availability — typically each peer agent representing one human submits exactly once per intent. Do NOT use to modify an already-submitted constraint (re-submission is rejected); do NOT use to vote on resolved options (use castVote). Typical triggers: \"I'm free Saturday morning and Sunday after 2pm,\" \"add me to the group, I can do 18 holes any day next week.\"",
      "tags": ["coordination", "group-event", "golf", "constraint", "availability"],
      "examples": [
        "I'm free Saturday morning and Sunday after 2pm.",
        "Add me to the group — 18 holes, any day next week.",
        "I can play Friday after 3 or all day Saturday, walking only."
      ],
      "inputModes": ["application/json"],
      "outputModes": ["application/json"]
    },
    {
      "id": "resolveOptions",
      "name": "Resolve constraints into ranked tee-time options",
      "description": "Intersect the submitted constraints and produce 3–5 ranked tee-time options across nearby courses, scored against group fit (date overlap, time overlap, price ceiling, cart and holes preferences, course distance, current weather). Returns the resolved option set ready for voting. Use this once all participants in an intent have submitted constraints (constraints.length === groupSize) and the group is ready to choose. Do NOT call before all constraints are in (will return a `still collecting` error); do NOT use to re-resolve an intent that already has options unless the underlying tee-time inventory has measurably changed. Typical triggers: \"everyone's submitted, what are our options,\" \"what tee times work for the group.\"",
      "tags": ["coordination", "group-event", "golf", "resolution", "ranking"],
      "examples": [
        "Everyone's submitted — what are our options?",
        "What tee times work for the group?",
        "Show me the matches, ranked by fit."
      ],
      "inputModes": ["application/json"],
      "outputModes": ["application/json"]
    },
    {
      "id": "castVote",
      "name": "Cast a participant's vote on resolved options",
      "description": "Record one participant's vote for a specific resolved option. Each call supplies the intent ID, the player name, and the chosen optionId. The intent transitions to a winner state when every participant has voted, or stays in voting until they have. A tie is surfaced as multiple isWinner=true options rather than auto-broken — the group is expected to coordinate offline in the rare tie case. Use this once resolveOptions has produced an option set and a participant has chosen which one they want. Do NOT use to change a vote (votes are immutable per intent + player); do NOT use before resolveOptions has run. Typical triggers: \"I vote for the 8am Saturday at Conestoga,\" \"option 2 works for me.\"",
      "tags": ["coordination", "group-event", "golf", "vote", "consensus"],
      "examples": [
        "I vote for the 8am Saturday slot at Conestoga.",
        "Option 2 works for me.",
        "Lock in the cheaper one."
      ],
      "inputModes": ["application/json"],
      "outputModes": ["application/json"]
    },
    {
      "id": "bookingHandoff",
      "name": "Hand off the winning option to the course booking surface",
      "description": "Resolve the booking URL for the winning option in an intent. Limlock does not complete the booking itself — the calling agent or the human participant follows the URL into the course's own system (Chronogolf, Tee-On portal, foreUP, course website) and reserves there. The deep-link URL is the most specific the platform allows: per-tee-time on Chronogolf, date-level on Tee-On portal and TeeItUp, club-level on foreUP. Use this as the TERMINAL action once a winner exists. Do NOT use to fetch a deep link before voting completes; do NOT use as a pricing API. Typical triggers: \"book the winner,\" \"send me the link to reserve.\"",
      "tags": ["coordination", "group-event", "golf", "booking", "handoff"],
      "examples": [
        "Book the winner.",
        "Send me the link to reserve.",
        "We're locked in — get me to the course's site."
      ],
      "inputModes": ["application/json"],
      "outputModes": ["application/json"]
    }
  ]
}
