CM AI Docking Port

A standardized entry point for AI agents into the CM Ecosystem — protocol version 0.1

This page documents an interface, not a product. CM (Channel Manager) instances run their own business logic for availability, pricing and reservations. The Docking Port does not duplicate that logic — it is a thin discovery and routing layer that lets any AI agent, speaking plain HTTP and JSON, find out what a CM instance can answer and how to ask.

The one rule that matters most: an AI agent talks only to Reception. It never calls internal business endpoints directly, and it never contacts other CM nodes on its own. Reception is the single point of contact; everything behind it — local lookups, forwarding to nearby nodes, aggregating results — is invisible to the agent.

What is the CM Ecosystem

Each CM installation is an independent node. A node may optionally participate in a decentralized network of other CM nodes ("the Ecosystem"). There is no central server that holds the whole network — each node knows only a small set of geographically relevant neighbours. A request entering through any one node's Docking Port can, within limits, be forwarded through that local network and aggregated back into a single answer.

What is Reception

Reception is the only endpoint an agent ever calls. It:

This node's Reception:

POST /app/public/ai/reception.php
Content-Type: application/json

status: live — local availability, plus fallback-only forwarding through trusted neighbours (geography-gated, depth-limited, loop-safe). Occupied nodes that were actually contacted appear in checked[]; they are not silent gaps. See the full spec for the test record.

How to discover this node

Start with the machine-readable manifest:

GET /.well-known/cm-ai-docking-port.json
GET /app/public/ai/manifest.json

It describes this node's identity, location, capabilities, and the Reception endpoint. Example (this node):

{
  "protocol": "CM-AI-Docking-Port",
  "version": "0.1",
  "service": {
    "name": "CM Ecosystem Reception",
    "type": "ai-entry-point",
    "node_id": "CM-AI-DEMO-058",
    "location": {
      "label": "Lancovo / Radovljica area (Demo 58)",
      "lat": 46.34,
      "lon": 14.17
    }
  },
  "reception": {
    "method": "POST",
    "endpoint": "/app/public/ai/reception.php",
    "content_type": "application/json"
  }
}

Request Envelope

Every request sent to Reception uses this shape:

{
  "protocol": "CM-AI-Docking-Port",
  "version": "0.1",
  "request_id": "req-2026-08-10-abc123",
  "request_expiry": "2026-08-10T12:00:00Z",
  "origin": "ai-agent",
  "target": {
    "location": { "lat": 46.05, "lon": 14.50, "label": "Ljubljana" },
    "radius_km": 30
  },
  "query": {
    "type": "availability",
    "from": "2026-08-10",
    "to": "2026-08-16",
    "guests": 2,
    "units": null
  },
  "limits": {
    "max_depth": 2,
    "max_distance_km": 40,
    "max_results": 10
  },
  "visited": []
}

Response Envelope

Reception always answers with one aggregated response, never raw internal API output. A two-hop example (entry at this node, unit found two hops away; an occupied neighbour recorded separately):

{
  "protocol": "CM-AI-Docking-Port",
  "version": "0.1",
  "request_id": "req-2026-12-01-example",
  "ok": true,
  "partial": false,
  "search_meta": {
    "entry_node": "CM-AI-DEMO-058",
    "target_location": { "lat": 46.4858, "lon": 13.7905, "label": "Kranjska Gora" },
    "nodes_queried": 2,
    "nodes_reached": 2,
    "max_depth_used": 2,
    "entry_ceiling": 2
  },
  "results": [
    {
      "node_id": "CM-AI-STUB-KRGORA",
      "node_location": { "lat": 46.4858, "lon": 13.7905 },
      "depth": 2,
      "source": "stub_test_node",
      "freshness": { "generated_at": "2026-10-02T12:00:00+00:00" },
      "data": { "...": "raw output of that node's own availability API, unmodified" }
    }
  ],
  "checked": [
    {
      "node_id": "CM-AI-STUB-BLED",
      "depth": 1,
      "location": { "lat": 46.3683, "lon": 14.1146 }
    }
  ],
  "errors": []
}
FieldMeaning
search_meta.entry_nodewho delivered this HTTP response to the agent
results[].node_idwho is the source of that available unit
results[].depthhow many hops that entry travelled
results[].node_locationwhere that source node is (travels with the entry; do not look it up yourself)
checked[]nodes successfully contacted that confirmed zero availability — not a failure, not a skip
checked[].locationsame idea as node_location, different key (see spec §27)
partialtrue only if a contacted node failed or timed out — never implied by an empty results[]
search_meta.entry_ceilingthe entry node's own depth ceiling (clamped agent limit vs its own hard max) — not the depth actually reached by the chain as a whole. A response can legitimately show max_depth_used: 3 alongside entry_ceiling: 2: the entry node's own ceiling only bounds how far it is willing to look before giving up, deeper nodes have their own, separate ceilings.

data inside each result is the untouched output of that node's own business API — Reception wraps it with provenance but never reinterprets it. results[] contains only genuine matches (available_count > 0). checked[] never competes for max_results. An empty checked[] does not mean nobody was asked — a node skipped for geography, or a local match that short-circuited forwarding, is not a confirmed zero. If part of the network was unreachable, partial is true; a partial search is never presented as a complete one.

Capabilities of this node

idscopeside effectconsent requireddescription
availabilitylocalnonoCheck unit availability for a date range
accommodation-discoveryecosystemnonoGeographic discovery across participating CM nodes via Reception

Every capability declares whether it changes anything (side_effect) and whether it requires explicit consent. This first version is read/discovery only — nothing an agent does through Reception creates a booking, a block, or any other write.

Limits

limitdefaultpurpose
max_depth2how many hops a request may be forwarded through the network (2 means two hops: A→B→D)
max_distance_km50how far from the target location a node is still considered relevant
max_results20caps results[] only — never checked[]

Rules for agents

How this grows

New capabilities are added to the manifest and the protocol — not by building a new AI system on top of CM. CM stays the source of truth; the Docking Port stays a thin, generic HTTP/JSON door that any AI provider can use without a CM-specific plugin.