# Publish Agent

Use this workflow to publish an agent to ITINAI through the ITINAI Agent Submit Proxy A2A agent.

This is the default path for users and bots. It does not require GitHub keys, repository write access, a local clone, or a direct GitHub pull request from the submitter. The proxy creates the catalog pull request.

## Canonical Submit Proxy Agent

Agent Card URL:

```text
https://itinai.com/.well-known/agent-card.json
```

Direct submission endpoint exposed by the Agent Card:

```text
https://itinai.com/wp-json/itinai/v1/submit
```

Use this rule to avoid ambiguity:

- Fetch the Agent Card from `https://itinai.com/.well-known/agent-card.json`.
- Read the direct submission endpoint from the Agent Card `url` field.
- Submit catalog payloads to that `url` endpoint.
- Do not POST to the Agent Card URL.
- Do not use `https://itinai.com/itinai-submit-agent-card.json` in new manifests or docs. Keep it only as a legacy alias or redirect if already published.

## Required Input

Collect these values from the user, the current agent configuration, or a remote Agent Card:

- `agent_id`: unique identifier.
- `name`: human-readable agent name.
- `description`: concise description of what the agent does.
- `agent_card_url`: public HTTPS Agent Card URL for the submitted agent.
- `protocol_version`: A2A protocol version. Default to `1.0.0` when not provided.
- `skills`: at least one skill with `id`, `name`, and non-empty `tags`.

Optional fields:

- `version`: default to `1.0.0`.
- `contact.email`
- `contact.url`
- `health_check.url`
- `dynamic_data.*`
- `openclaw.*`

## Normalize Before Submitting

LLM agents may submit inconsistent casing, spacing, and version formats. Normalize these values before blocking the request.

Required normalization:

- Trim all strings.
- Convert `agent_id`, `skills[].id`, and `skills[].tags` to lowercase kebab-case.
- Convert spaces and underscores in IDs and tags to hyphens.
- Convert `version` and `a2a_config.protocol_version` to three-part semver:
  - `1` -> `1.0.0`
  - `1.0` -> `1.0.0`
  - `v1.2` -> `1.2.0`
  - `A2A 0.3` -> `0.3.0`

## Strict Validation

Block only if these fields are invalid after normalization:

- `agent_id`: empty after normalization.
- `name`: empty after trimming.
- `a2a_config.agent_card_url`: missing, non-HTTPS, or not a URL.
- `a2a_config.protocol_version`: no recoverable numeric version.
- `skills[]`: empty or no skill has `id`, `name`, and at least one tag after normalization.

Do not block on optional fields:

- `contact.email`
- `contact.url`
- `health_check.url`
- `dynamic_data.*`
- `openclaw.*`

## Proxy Payload Shape

Send JSON to the endpoint exposed by the proxy Agent Card `url` field.

```json
{
  "agent_id": "my-agent",
  "name": "My Agent",
  "description": "What the agent does.",
  "version": "1.0.0",
  "a2a_config": {
    "agent_card_url": "https://example.com/.well-known/agent-card.json",
    "protocol_version": "1.0.0"
  },
  "skills": [
    {
      "id": "search",
      "name": "Search",
      "tags": ["search"]
    }
  ]
}
```

For users that only provide an Agent Card URL, submit at minimum:

```json
{
  "agent_card_url": "https://example.com/.well-known/agent-card.json"
}
```

The proxy may fetch the Agent Card and derive manifest fields.

## Expected Proxy Result

A successful response should include a pull request URL or equivalent catalog submission reference.

```json
{
  "success": true,
  "agent_id": "my-agent",
  "pr_url": "https://github.com/aihlp/itinai/pull/123"
}
```

## Maintainer Fallback

Only maintainers who intentionally bypass the proxy should create `agents/<agent_id>.yaml` in a local clone of `https://github.com/aihlp/itinai`, validate with `python scripts/validate.py agents/<agent_id>.yaml`, run the Agent Card health check, and open a GitHub pull request manually.
