Discovery Surface Projection
AGLedger publishes four discovery surfaces an agent can read with no auth. Your registered schema appears in some of them, and you control specific knobs.
The surfaces
| Path | Format | What it carries |
|------|--------|-----------------|
| GET /llms.txt | Markdown | Curated link-index optimized for LLM ingestion. Points at the engine's authoritative routes plus an Agent Grounding Directive. |
| GET /llms-full.txt | Markdown | Same shape as /llms.txt, with worked code examples inline. Kept separate so the link-index stays terse. |
| GET /openapi.json | OpenAPI 3.1 | Full machine-readable spec. Source of truth for route shapes and response schemas. |
| GET /.well-known/agent-card.json | A2A 1.0 | Agent Card describing the engine as an A2A-speakable agent (skills, capabilities, transport, supported intents). |
| GET /v1/scope-profiles | JSON | Unauthenticated profile catalogue — agents discover their permission envelope here. |
All five are unauthenticated and always-on. None of them rate-limit, gate behind feature flags, or require API keys. An agent that cannot reach any of these has no diagnostic signal — predictable availability is the load-bearing property.
Customer-controlled vs engine-filled
What your registered schema causes to appear in /llms.txt, and what you can override:
| Surface bit | Customer controls | Engine fills |
|---|---|---|
| Schema title + description in the "Available Types" section | Yes — values from POST /v1/schemas | — |
| Custom prepended / appended sections | Yes — _PREPEND_PATH / _APPEND_PATH | — |
| Whole-file replacement | Yes — _OVERRIDE_PATH (skips generation) | — |
| Section omission | Yes — _OMIT_SECTIONS | — |
| Route enumeration in OpenAPI | — | At boot, from the route table |
| Scope projection in /v1/scope-profiles | — | At boot, from the authority declaration |
| Agent Grounding Directive in /llms.txt | — | Load-bearing — cannot be omitted |
| Version footer | — | Cannot be omitted |
| Federation signing scheme section | — | Auto-shown only in hub mode |
The engine fills the structural pieces; you tune the content surface that customers expect to vary across deployments.
The Agent Grounding Directive
Every /llms.txt body opens with a directive block. It tells agents to ground decisions in the response body, not in the static doc:
## Agent Grounding Directive
**Ground every decision in the response body, not in this document.** This file
is an index of endpoints and conventions — it is not authoritative for which
action, status, or transition is valid on a specific resource right now.
- Every record response includes `status`, `nextActions`, `validTransitions`,
and `nextSteps`. Always read `nextSteps` to find the next call — `nextActions`
only covers /transition verbs and an empty `nextActions` is normal, not a
stuck state.
- On a 400 error, read `hint`, `suggestion`, `recoveryHint`, and `allowedValues`.
- On a 422 error, read `currentState`, `allowedActions`, `recoveryHint`, and
`refreshUrl`.
- On a 429, honor `retryAfterSeconds`.
This directive is engine-filled and cannot be omitted. It steers agent behavior at session start: "read the body fields, not this doc." Static enums in a Markdown file go stale; response-body fields cannot.
The four /llms.txt environment variables
When each is the right tool:
AGLEDGER_LLMS_TXT_OVERRIDE_PATH— verbatim serve, skip generation. Use only when you need a completely different doc front. The cost: every engine update to grounding directives, new sections, or schema-list shape stops reaching your agents until you re-edit the override.AGLEDGER_LLMS_TXT_PREPEND_PATH/AGLEDGER_LLMS_TXT_APPEND_PATH— wrap the generated body. Both apply to/llms.txtand/llms-full.txt. The right tool for almost every customization: org-specific addenda (your support contact, your internal SLA, your out-of-band auth flow).AGLEDGER_LLMS_TXT_OMIT_SECTIONS— comma-separated list of canonical section keys. Use when a section is genuinely irrelevant (e.g. omittingdisputesfor a notarize-only deployment). Unknown keys are ignored silently.
Omittable section keys
The canonical set, lifted from LLMS_TXT_OMITTABLE_SECTIONS in src/modules/discovery/llms-txt.ts:
| Key | What it omits |
|-----|---|
| a2a | Agent-to-Agent Records section + Agent Discovery Endpoints bullet |
| proposals | Agent-to-Agent (Proposals) sub-list under Key Endpoints |
| delegation | Delegation (sub-records) sub-list — parentRecordId, /chain, /sub-records, /graph, cascade settlement |
| disputes | Disputes sub-list under Key Endpoints |
| schema-management | Schema Management sub-list |
| audit-compliance | Compliance & Audit section |
| audit-integrity | Audit Chain Integrity section — chainIntegrity semantics, tamper-detection layers, offline verifier |
| webhooks | Webhooks section — subscribe, event types, DLQ, retries, circuit breaker, SSRF rules |
| encrypted-records | Encrypted Records section — operatingMode='encrypted' envelope shape |
| verification-keys | Verification Keys section |
| federation | Federation Signing Scheme section (already auto-hidden outside hub mode) |
| a2a-agent-card | A2A Agent Card footer |
| optional | Optional self-reference to llms-full.txt |
| agent-directory | Agent Directory peer-discovery list |
The Agent Grounding Directive and the Version sections are NOT in this list and cannot be omitted — both are load-bearing. The directive tells agents to read response-body fields rather than infer from static docs; the version footer keeps signature snapshots stable.
Worked example
Register a custom contract type:
curl -X POST "$API_BASE/v1/schemas" \
-H "Authorization: Bearer $SCHEMA_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "DELIVERY-ATTEMPT-v1",
"displayName": "Delivery Attempt",
"description": "Notarize a single delivery attempt by a logistics agent.",
"recordSchema": {
"type": "object",
"required": ["expected_count"],
"properties": { "expected_count": { "type": "integer", "minimum": 1 } },
"additionalProperties": false
}
}'
The "Available Types" section of /llms.txt now includes:
### DELIVERY-ATTEMPT-v1
Delivery Attempt — Notarize a single delivery attempt by a logistics agent.
/openapi.json components.schemas now contains a generated entry for the type's criteria shape.
Side-by-side: what you sent (one POST), what the agent reads (two surfaces, both auto-updated, no SDK release).
Cache busting
A schema change fires a Postgres LISTEN/NOTIFY and busts the in-process cache; the next read regenerates and serves fresh bytes.
To force-bust without a schema change:
curl -X POST "$API_BASE/v1/admin/discovery/reload" \
-H "Authorization: Bearer $PLATFORM_KEY"
Operational bounds:
- 128 KB per-file cap.
_OVERRIDE_PATH,_PREPEND_PATH, and_APPEND_PATHfiles larger than this fall back to the built-in template. Theagledger_llms_txt_customization_failures_totalcounter increments so a misconfigured path is detectable instead of silent. - Content negotiation.
Accept: text/markdownreturnsContent-Type: text/markdown; charset=utf-8; otherwisetext/plain. Bodies are byte-identical, so signatures, hashes, and snapshot diffs are stable acrossAcceptheaders.
See also
- The agent-UX envelope — what every mutation response carries, on both success and error.
- The thin-SDK pattern — why these discovery surfaces matter: the SDK depends on them at runtime rather than embedding documentation at compile time.
Validated against the live API (v0.22.18) on 2026-05-02.