Six honest agent-readiness fixes
feat/orank-honest-wins on orchestkit.yonyon.ai. Each change had to be
true on its own terms, independent of any score. Where advertising something
would have required a claim we cannot back, it was not advertised.
Request simulator B3 bot-UA routing, B1 twin existence
Pick a client and a path. This runs the same decision
middleware.ts makes: whether the request wants Markdown, and
whether a Markdown twin actually exists at that path.
Markdown alternate link B1
No rel="alternate" existed anywhere. The link is now emitted,
but only where mdTarget() genuinely maps a twin.
<link rel="canonical"
href="…/docs/foundations/overview">
An agent had to already know the "append .md" convention to find the Markdown at all.
<link rel="canonical"
href="…/docs/foundations/overview">
<link rel="alternate" type="text/markdown"
href="…/docs/foundations/overview.md">
The 13 marketing pages each declare their own alternates,
which shallow-replaces the layout default, so none of them inherit a
link to a twin they do not have.
Markdown frontmatter B2
Served Markdown carried no identity: the title was only recoverable by parsing the first H1, and nothing said which URL the body belonged to. Every value below is the one the HTML twin already publishes.
# Overview Start here. …
--- title: "Overview" description: "Start here." canonical: "https://orchestkit.yonyon.ai/docs/foundations/overview" --- # Overview Start here. …
| Route | title from | description from | canonical |
|---|---|---|---|
/api/md (root) | SITE.name, the doc's H1 | root layout metadata.description | / |
/api/md/* | page.data.title | page.data.description | /docs/<slug> |
/pricing.md | doc H1 | PAGE_SUMMARY.pricing, shared with the HTML page | /pricing |
/auth.md | doc H1 | its own lead (no HTML twin exists) | /auth.md |
/api-policy.md | API_POLICY_TITLE | API_POLICY_LEAD | /api-policy |
A 404 body gets no frontmatter: canonical would have to name a
URL that does not resolve.
trustManifest on catalog entries B4
A host-level manifest already existed. A consumer of the ARD catalog decides per resource, not per publisher, so identity has to travel with the entry it is deciding about.
host ✓ trustManifest entries[0] (none) entries[1] (none) entries[2] (none) entries[3] (none) entries[4] (none)
host ✓ trustManifest entries[0] ✓ entries[1] ✓ entries[2] ✓ entries[3] ✓ entries[4] ✓
Two claims only, both verifiable without asking us: the did:web
resolvable at /.well-known/did.json, and
publishedFrom the public repository. Still absent by design:
signature (no request-signing bot),
attestations (no compliance program),
trustSchema (no external governance).
llms.txt npm links B6
Measured 2026-08-23 with a ClaudeBot/1.0 User-Agent. Every
reader of llms.txt is a non-browser client by definition, so the link it
was handed could never be followed.
| URL | Status to a bot | Body |
|---|---|---|
www.npmjs.com/package/orchestkit | 403 | Cloudflare "Just a moment..." |
www.npmjs.com/package/@orchestkit/hook-contract | 403 | Cloudflare "Just a moment..." |
registry.npmjs.org/orchestkit | 200 | package document (versions, dist-tags, bin) |
registry.npmjs.org/@orchestkit/hook-contract | 200 | package document |
Both packages genuinely exist. Only the host changed, and the guard test
still pins the exact shipping package name from
packages/cli/package.json.
Agent Plugins manifest B5
The tempting move was to add $schema to the manifest Claude
Code already reads. Measured against the canonical schema, that would have
been a false claim. The two specs want the file in two different places,
so ork now ships both and neither compromises.
| File | Read by | Extra keys vs agent-plugins.org | Valid |
|---|---|---|---|
.claude-plugin/plugin.json | Claude Code | skills, commands, workflows | would fail |
plugin.json (plugin root) | agent-plugins.org 1.0.0 | none | valid |
The canonical schema is additionalProperties: false over ten
permitted keys. Spec 4.1 and 5.1 place the Agent Plugins manifest at
plugin.json in the plugin root; Claude Code reads
.claude-plugin/plugin.json. Two paths, two correct files.
$schema ✓ added skills (forbidden) commands (forbidden) workflows (forbidden) => names a schema it fails
plugin.json $schema, name, version, description, author, homepage, repository, license, keywords => 0 violations
Also measured and rejected: moving the three keys under
extensions makes Claude Code warn
"Unknown field 'extensions'. Claude Code ignores it at load time",
trading a false claim for inert data.
Deliberately not done
- Markdown alternates on the 13 marketing pages.
mdTarget()does not map them, so the link would point at a URL that answers with HTML. Worse than no link. - Markdown for search-engine crawlers. Googlebot, bingbot and applebot index the HTML. Swapping it would drop the site out of results it currently earns. "AI bot" is not a synonym for "crawler".
- Markdown for generic HTTP clients. curl, python and node are the same string whether a human or an agent sent them. They still get Markdown the explicit way, by asking for it.
43 test files / 536 tests green in docs/site, 36 of them new.
B5 adds a mutation-tested manifest guard (7 injected defects, 7 caught).
Typecheck adds no new errors; the two pre-existing ones are unchanged.