This file provides guidance to AI coding agents when working with code in this repository.
Keep comments short and to the point — one line where possible. Only comment on the why (a non-obvious constraint, a workaround, a rationale that isn't clear from the code itself); don't restate what the code already says. Avoid multi-paragraph docstrings or comments stacking several justifications with --/; asides.
# Build registry (validates all agents and outputs to dist/)
uv run --with jsonschema .github/workflows/build_registry.py
# Dry run (validate without writing to dist/)
uv run --with jsonschema .github/workflows/build_registry.py --dry-run
# Build without schema validation (if jsonschema not available)
python .github/workflows/build_registry.py# Run workflow tests in the Dockerized local environment (recommended)
.github/workflows/scripts/run-workflows-tests.sh
# Run workflow tests natively on the host (CI-style debugging only)
cd .github/workflows && uv run --with pytest --with jsonschema pytest tests/ -v
# Lint check
cd .github/workflows && uv run --with ruff ruff check .
# Format check
cd .github/workflows && uv run --with ruff ruff format --check .
# Auto-fix formatting
cd .github/workflows && uv run --with ruff ruff format .GitHub Actions runs the nightly protocol matrix natively on the runner (uv + Node.js installed in the workflow), but local verification can still use Docker to keep downloads, caches, and auth-related state isolated from your host machine:
# Run workflow tests in the Dockerized local environment
.github/workflows/scripts/run-workflows-tests.sh
# Validate schema/build output in a container
.github/workflows/scripts/run-registry-docker.sh uv run --with jsonschema .github/workflows/build_registry.py
# Verify registered agents in a container
.github/workflows/scripts/run-registry-docker.sh python3 .github/workflows/verify_agents.py --auth-check
# Generate the protocol feature matrix in a container
.github/workflows/scripts/run-protocol-matrix.sh
# Generate a capabilities-only matrix table in a container
.github/workflows/scripts/run-protocol-matrix.sh --table-mode capabilities
# Reuse unchanged agent versions from the previous snapshot
.github/workflows/scripts/run-protocol-matrix.sh --table-mode capabilities --changed-onlyrun-protocol-matrix.sh mirrors the scheduled GitHub Actions defaults: it uses --table-mode capabilities and creates ephemeral isolated Docker state plus a fresh protocol sandbox by default so agents cannot reuse local login/keychain state or stale install artifacts across runs. Set ACP_PROTOCOL_MATRIX_KEEP_STATE=1 if you intentionally want to keep the container state and .matrix-sandbox for debugging.
The generic Docker wrapper keeps state under .docker-state/ in the repo, defaults to linux/amd64 to match ubuntu-latest, injects a passwd entry for the current UID inside the container, and disables Python keyring backends to avoid host keychain prompts during local verification. It reuses an existing local Docker image when the requested platform and image inputs still match, and rebuilds automatically when they do not; set ACP_REGISTRY_BUILD_IMAGE=1 to force a rebuild. Treat the Docker wrappers as the canonical local path; use host-native uv run ... commands only when you intentionally want to debug outside the container. Set ACP_REGISTRY_DOCKER_PLATFORM= to opt out of the default platform override when you explicitly want native-architecture debugging.
Set ACP_PROTOCOL_MATRIX_SKIP_AGENTS=crow-cli to skip specific agents during matrix generation.
This is a registry of ACP (Agent Client Protocol) agents. The structure is:
<id>/
├── agent.json # Agent metadata and distribution info
└── icon.svg # Icon: 16x16 SVG, monochrome with currentColor (required)
Build process (.github/workflows/build_registry.py):
- Scans directories for
agent.jsonfiles - Validates against
agent.schema.json(JSON Schema) - Validates icons (16x16 SVG, monochrome with
currentColor) - Aggregates into three views:
dist/registry.json,dist/registry-for-jetbrains.jsonanddist/registry-for-jetbrains-preview.json - Copies icons to
dist/<id>.svg
CI/CD (.github/workflows/build-registry.yml):
- PRs: Runs validation only
- Push to main: Validates, then publishes versioned +
latestGitHub releases
id: lowercase, hyphens only, must match directory nameversion: semantic versioning (e.g.,1.0.0)distribution: at least one ofbinary,npx,uvxbinarydistribution: builds for all operating systems (darwin, linux, windows) are recommended; missing OS families produce a warningbinaryarchives must use supported formats (.zip,.tar.gz,.tgz,.tar.bz2,.tbz2, or raw binaries); installer formats (.dmg,.pkg,.deb,.rpm,.msi,.appimage) are rejectedbinaryarchives should pin the archive SHA-256 checksum withsha256fieldicon.svg: must be SVG format, 16x16, monochrome usingcurrentColor(enables theming)preview(optional): exactlyversion+distribution;versionmatchesX.Y.Z-preview.Nor a plainX.Y.Z;distributionisnpx/uvxonly. Checked offline only — see Preview Channel- URL validation: All distribution URLs must be accessible (binary archives, npm/PyPI packages). Preview distributions are exempt
Set SKIP_URL_VALIDATION=1 to bypass URL checks during local development.
An agent may declare an optional preview block in its agent.json, holding exactly two fields — version and distribution:
"preview": {
"version": "1.9.0-preview.1",
"distribution": {
"npx": { "package": "@agentclientprotocol/codex-acp@1.9.0-preview.1" }
}
}See FORMAT.md for the full contract. Key points when working in this repo:
- Three build outputs.
registry.jsonandregistry-for-jetbrains.jsonalways carry the stableversion/distributionwith thepreviewkey stripped.registry-for-jetbrains-preview.jsonis a complete, drop-in replacement for the JetBrains registry where a previewed agent appears as an ordinary entry withversionanddistributionsubstituted by the preview values (and still nopreviewkey). Agents without apreviewblock appear there at their stable version. - Version scheme
X.Y.Z-preview.N. Valid semver;1.9.0-preview.Nranks below1.9.0, andpreview.10ranks abovepreview.2. The rootversionmust stay a plainX.Y.Zrelease. - Highest of both channels wins.
preview.versionmeans "the newest version we know about", so it may legitimately hold a plain release. Apreview.versionat or below the stableversionis not an error — the build simply serves the stable entry, and the hourly checker rewrites the block on the next run. Never add an ordering constraint between the channels. - Preview is deliberately unverified. Preview distributions are never launched (
verify_agents.pyandprotocol_matrix.pystay stable-only), their URLs are never probed, and they add no CI jobs. The only preview-specific check is offline: the package spec's pinned version must equalpreview.version. binarypreview distributions are not supported — the schema restrictspreview.distributiontonpx/uvx.- Wrapper-repo prerequisite: preview artifacts must be published as
npm publish --tag preview. Publishing a prerelease without--tag previewmovesdist-tags.latestonto it, which the stable checker's fallback path guards against but should not be relied on.
Shared helpers live in .github/workflows/registry_utils.py: semver_sort_key, resolve_preview_entry (the single definition of "what a preview entry is") and strip_preview.
update_versions.py owns all verification, comparison, and apply logic; its dependencies are split into flat, cycle-free modules:
common.py: shared data types with no local dependencies (CHANNELS,UpdateError,LatestRelease,PublishedVersions,ResolvedAsset,VersionUpdate)registry_utils.py: version-string helpers (is_prerelease,normalize_release_version,semver_sort_key, etc.), also dependency-freegithub_api.py: the shared HTTP fetch primitive (make_request) plus GitHub Releases lookups (get_github_release_versions,get_github_release_digests,is_github_repo)jsonl_feed.py: a generic fetch of the tail of an append-only.jsonlfeed (fetch_jsonl_tail) — no assumption about record field namescustom_agent_sources/: per-(agent_id, channel)overrides for agents whose releases aren't discoverable through npm, PyPI, or GitHub Releases
Custom agent sources. Some agents publish releases somewhere the standard npm/PyPI/GitHub-releases checkers can't reach — e.g. Junie's preview (nightly) channel, which appends one JSON line per platform per release to a growing .jsonl file. For these, update_versions.py declares a visible CUSTOM_AGENT_SOURCES: dict[tuple[str, str], CustomSourceFn] table mapping (agent_id, channel) to an override function. Each override takes the agent's parsed agent.json and returns (LatestRelease | None, UpdateError | None) — it only reports the latest release it can find; it never compares that against the agent's current version or decides whether it counts as an update. resolve_update() in update_versions.py does that comparison identically for every source, standard or custom, so the "is this newer" logic lives in exactly one place.
To add a new custom source: write custom_agent_sources/<agent_id>.py with a function matching CustomSourceFn (see custom_agent_sources/junie.py for a worked example), then register it in CUSTOM_AGENT_SOURCES.
Agent versions are automatically updated via .github/workflows/update-versions.yml:
- Schedule: Runs hourly (cron:
0 * * * *) - Scope: Checks all agents in the root directory
- Supported distributions:
npx(npm),uvx(PyPI),binary(GitHub releases only — non-GitHubrepositoryURLs are skipped)
# Dry run - check for available updates (both channels)
uv run .github/workflows/update_versions.py
# Apply updates locally
uv run .github/workflows/update_versions.py --apply
# Check specific agents only
uv run .github/workflows/update_versions.py --agents gemini,github-copilot
# Check a single release channel
uv run .github/workflows/update_versions.py --channels previewBoth channels are checked from a single fetch per distribution source. Stable updates rewrite the root version and distribution specs; preview updates rewrite only preview.version and the preview specs. Each entry in the --json payload carries a channel field, and only stable bumps are auth-verified.
The workflow can also be triggered manually via GitHub Actions with options to apply updates and filter by agent IDs.
To update agents manually:
- For npm packages (
npxdistribution): Check latest version athttps://registry.npmjs.org/<package>/latest - For GitHub binaries (
binarydistribution): Check latest release athttps://api.github.com/repos/<owner>/<repo>/releases/latest. Note: automated version checking only works for agents with a GitHubrepositoryURL. Proprietary agents with non-GitHub or missingrepositoryURLs must be updated manually.
Update agent.json:
- Update the
versionfield - Update version in all distribution URLs (use replace-all for consistency)
- For npm: update
packagefield (e.g.,@google/gemini-cli@0.22.5) - For binaries: update archive URLs with new version/tag
Run build to validate: uv run --with jsonschema .github/workflows/build_registry.py
binary: Platform-specific archives (darwin-aarch64,linux-x86_64, etc.). Supported archive formats:.zip,.tar.gz,.tgz,.tar.bz2,.tbz2, or raw binaries. Supporting all operating systems (darwin, linux, windows) is recommended.npx: npm packages (cross-platform by default)uvx: PyPI packages (cross-platform by default)
Icons must be:
- SVG format (only
.svgfiles accepted) - 16x16 dimensions (via width/height attributes or viewBox)
- Monochrome using
currentColor- all fills and strokes must usecurrentColorornone
Using currentColor enables icons to adapt to different themes (light/dark mode) automatically.
Valid example:
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="currentColor" d="M..."/>
</svg>Invalid patterns:
- Hardcoded colors:
fill="#FF5500",fill="red",stroke="rgb(0,0,0)" - Missing currentColor:
fillorstrokewithoutcurrentColor
Agents must support ACP authentication. The CI verifies auth via .github/workflows/verify_agents.py --auth-check.
Requirements:
- Return
authMethodsarray ininitializeresponse - At least one method must have type
"agent"or"terminal"
See AUTHENTICATION.md for details on implementing auth methods.