Proposal: one identity rule each for hosts, commands, tools and approvals

Status accepted
Author Claude Code for the maintainer. Written after the change landed (DR-184, task 2.2)
Date 2026-10-05
Issue the second contract review, 5 October 2026; DR-183 D2 ("Hosts: refuse IP literals, or admit them")
Lands in PR #15, task/2.1-lease-identity, merged 2026-10-05; released in 1.2.0

Summary

A host, a command, a tool and an approval each get one pattern, enforced by the schemas, with caps on agent.name (120 characters) and intent.purpose (500), so two implementations cannot disagree about what an entry names.

Motivation

Before 1.2 the schemas stated no identity rule for these lists. https://api.example.com, API.EXAMPLE.COM, api.example.com. and api.example.com:443 could all be written, and whether a parent's *.example.com contained each was an implementation's choice; a command could be /usr/bin/git or git status, which authorise different things. The reference egress proxy matches hostnames and the governor compares executable basenames, so the schemas said less than the code did.

Design

SPEC §4.4: a host is ^(\*|(\*\.)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*)$ of at most 253 characters, which admits IPv4 literals and localhost; a command is ^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$; a tool or approval is ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$, never *. Applied to allow and deny, to the inlined copies in agent-lease and lease-record, and to the plugin schemas' capabilities. agent.name is capped at 120 and described as never a person's name; intent.purpose at 500. Every pattern is an ECMA-262 regular expression without lookaround or backreferences, applied as an unanchored search, and compiles under RE2 in CI.

Backward compatibility

A tightening, allow-listed entry by entry with the exact after value. Evidence fixtures/evidence/2026-10-05-lease-identity.md: every lease and declared manifest in the reference journal validates (4 validated, 0 rejected; hosts and commands empty, tools cdf_ names, longest name 22 characters, longest purpose 29); the ten built-in providers' hosts and the eight default deny commands all match. Eighteen invalid fixtures, one valid (agent-lease-manifest.identity-forms.json). stability: stable.

Security

Tighter: a host with a scheme or a port, a command with arguments, a wildcard tool can no longer be granted by a conformant issuer. Nothing new enters a record.

Alternatives

DNS names only, refusing IP literals: rejected in DR-183 D2, because two built-in providers sit at 127.0.0.1 and the root policy derives its hosts from provider URLs. A host:port form: a separate proposal, rejected (2026-10-05-host-ports.md).

Decision

Accepted, 2026-10-05, by the maintainer in DR-183 (D2 for the host rule). Shipped in 1.2.0: SPEC §4.2 to §4.4 and §13; schemas/agent-lease-manifest.schema.json, its inlined copies in agent-lease and lease-record, and capabilities in plugin-manifest and plugin-marketplace; tooling/inline-granted-manifest.mjs; the allow-list entries dated 2026-10-05; the fixtures above.