← Back to Blog
🤖 AI-written, human-guided

How Bots Know What They're Doing: First Contact

Picture this: you spin up a fresh AI agent on a new machine. It’s smart, capable, eager to help. But it has no idea what services are running, what APIs are available, or how to authenticate. It’s like dropping someone in a foreign city with no map, no phone, and no language skills.

This is the cold start problem for AI agents. And until now, most solutions have been embarrassingly manual.

The Old Way: Hardcode Everything

The traditional approach to agent integration looks something like this:

# Don't do this
CREWHUB_URL = "http://localhost:8091"
CREWHUB_API_KEY = "sk-abc123"
ENDPOINTS = {
    "rooms": "/api/rooms",
    "chat": "/api/chat",
    "tasks": "/api/tasks",
}

Hardcoded URLs. Hardcoded endpoints. Hardcoded assumptions about what the service can do. It works — until it doesn’t. The service moves to a different port. A new version renames an endpoint. A capability gets added and your agent never knows about it.

This approach is fragile, high-maintenance, and fundamentally at odds with how AI agents should work. Agents are supposed to be adaptive. Hardcoding makes them brittle.

The Manifest Pattern

What if a service could simply describe itself? What if an agent could ask “Hey, what are you and what can you do?” and get a structured answer?

That’s the manifest pattern. It’s a single, public endpoint that returns a JSON document describing the service’s identity, capabilities, authentication requirements, and constraints. Think of it as a business card and instruction manual rolled into one.

The concept isn’t entirely new — OpenAPI specs, .well-known endpoints, and service discovery protocols all touch on this idea. But manifests are specifically designed for agent consumption: minimal, structured, and actionable.

CrewHub’s Implementation

Here’s what CrewHub’s manifest endpoint actually returns:

curl http://localhost:8091/api/discovery/manifest
{
  "manifest_schema_version": "1.0",
  "service": "CrewHub",
  "version": "0.12.0",
  "capabilities": {
    "rooms": {
      "endpoints": ["/api/rooms", "/api/rooms/{id}"],
      "description": "Organize agents into project rooms"
    },
    "chat": {
      "endpoints": ["/api/chat"],
      "constraints": {
        "main_session_only": true
      }
    },
    "modding": {
      "endpoints": ["/api/blueprints"],
      "description": "Custom 3D environments via JSON blueprints"
    }
  },
  "auth": {
    "required": true,
    "methods": ["api_key"],
    "default_key_location": "~/.crewhub/agent.json"
  }
}

Let’s break this down:

  • manifest_schema_version — Versioning for the manifest format itself. If we change the structure, agents can detect it and adapt (or gracefully degrade).
  • service + version — Basic identity. The agent now knows it’s talking to CrewHub v0.12.0, not some random API.
  • capabilities — The meat of the manifest. Each capability lists its endpoints, a description, and any constraints. Notice how chat has main_session_only: true — the agent immediately knows not to try chatting from a sub-session.
  • auth — How to authenticate, what methods are supported, and where to find credentials. No guessing.

The endpoint requires no authentication. This is intentional — you can’t authenticate if you don’t know how to authenticate. The manifest is the bootstrap.

The Onboarding Flow

With a manifest endpoint in place, agent onboarding becomes a clean, deterministic sequence:

1. DISCOVER  →  Probe known ports/paths for /health or /api/discovery/manifest
2. READ      →  Fetch the manifest, parse capabilities and auth requirements
3. AUTH      →  Authenticate using the method specified in the manifest
4. IDENTIFY  →  Register via /api/self/identify (name, type, session info)
5. USE       →  Start calling capability endpoints

In pseudocode, the agent’s logic looks like this:

# Agent onboarding flow
async def onboard(service_url: str):
    # Step 1: Fetch the manifest (no auth needed)
    manifest = await fetch(f"{service_url}/api/discovery/manifest")

    # Step 2: Read auth requirements
    auth_config = manifest["auth"]
    if auth_config["required"]:
        key = load_key(auth_config["default_key_location"])
        headers = {"Authorization": f"Bearer {key}"}

    # Step 3: Identify ourselves
    await post(f"{service_url}/api/self/identify", headers=headers, json={
        "name": "claude-code",
        "type": "coding_agent",
        "session": current_session_id()
    })

    # Step 4: We're in. Check what we can do.
    for name, capability in manifest["capabilities"].items():
        register_capability(name, capability["endpoints"])

    print(f"Onboarded to {manifest['service']} v{manifest['version']}")
    print(f"Available: {list(manifest['capabilities'].keys())}")

The entire flow is self-guided. The agent doesn’t need a README, a setup guide, or a human to walk it through. The service tells it what to do.

Why This Matters

This might seem like a small API design choice, but it has compounding effects:

Zero configuration. No config files to write, no environment variables to set, no documentation to read. The agent discovers everything at runtime.

Version safety. When CrewHub v0.13.0 ships with a new capability — say, analytics — every agent that fetches the manifest will automatically see it. No code changes, no redeployment.

Constraint awareness. Agents learn about limitations before hitting them. Instead of getting a cryptic 403 on the chat endpoint from a sub-session, they read main_session_only: true and don’t even try.

Extensibility. Any service can implement a manifest endpoint. It’s just JSON over HTTP. If your monitoring tool, your CI pipeline, or your home automation server exposes a manifest, agents can discover and integrate with all of them — automatically.

Composability. An agent that discovers multiple services can reason about their combined capabilities. “I have access to CrewHub for project management and Grafana for metrics — let me correlate task velocity with deployment frequency.”

The Bigger Picture

The manifest endpoint solves first contact — the moment an agent encounters a service for the first time. But what happens after that? How does the agent stay aware of its current context — which room it’s in, what tasks are active, who else is working?

That’s a different problem, and it’s one we’ve already solved with context envelopes. If you’re curious about how agents maintain situational awareness after they’ve onboarded, check out the next post in this series: How Bots Know What They’re Doing: Reading the Room.

First contact is about discovery. Reading the room is about awareness. Together, they form the foundation of truly autonomous agent collaboration.


CrewHub’s manifest endpoint ships in v0.12.0. Want to try it? Check out the GitHub repo or join us on Discord.