Context
We're implementing GNAP in Overlord v2 and are currently writing our own validation schemas (using Zod in TypeScript) by reverse-engineering the README spec and the example files. This works, but we had to make judgment calls on several ambiguities — which fields are required vs. optional, what formats are expected, what value constraints exist.
Having official, machine-readable schemas would eliminate this guesswork for us and for any future GNAP implementer.
What Would Help
A schemas/ directory in the repo with formal definitions for the four core entities. These could be in any standard format:
- JSON Schema (most universal — works across all languages)
- TypeScript types (great for the JS/TS ecosystem)
- Both (JSON Schema as source of truth, TypeScript generated from it)
Specific Ambiguities We Encountered
While building our Zod schemas, we ran into these questions that a formal schema would answer:
agents.json
- Is
heartbeat required or optional? What's the valid range? (Minimum seconds? Maximum?)
- Is
runtime a free-form string or an enum?
- Is
active required? What's the default?
- Are there constraints on
id format? (Slugs only? UUIDs? Any string?)
- Can custom fields be added to an agent entry, or is the schema closed?
tasks/{id}.json
- Which fields are required at creation vs. populated later? (e.g.,
result is presumably empty at creation)
- What's the valid range for
priority? (1-5? 1-10? Unbounded?)
- Are status transitions constrained? (Can a task go from
backlog directly to done? From done back to in_progress?)
- Is
due_date ISO 8601? What about timezone handling?
- What are the valid
status values? (The README lists backlog, ready, in_progress, review, done, blocked, cancelled — is this exhaustive?)
runs/{task-id}-{attempt}.json
- Is the filename format
{task-id}-{attempt} enforced, or just a convention?
- Are
input_tokens, output_tokens, cost_usd required? (Presumably optional for human agents)
- What's the expected format for
artifacts? (Array of strings? Array of objects with paths?)
- Is
duration_minutes always minutes, or could it be seconds for short runs?
messages/{id}.json
- Is
to required to have at least one entry? What does an empty to array mean?
- (Also noting the field name discrepancies from the separate bug report)
- Is
type required or optional? What happens if omitted — does the message have no type, or is there an implicit default?
- Is
channel a free-form string or are there conventional values?
- What's the
id format? Auto-incrementing integers (as in the example)? UUIDs? Slugs?
Proposed Schema (Draft)
Here's what we're building on our side as a starting point — happy to contribute this back if it's useful:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GNAP Message",
"type": "object",
"required": ["id", "from", "to", "text", "at"],
"properties": {
"id": {
"type": "string",
"description": "Unique message identifier"
},
"from": {
"type": "string",
"description": "Sender agent ID (must exist in agents.json)"
},
"to": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"description": "Recipient agent IDs, or [\"*\"] for broadcast"
},
"text": {
"type": "string",
"description": "Message content"
},
"at": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp"
},
"type": {
"type": "string",
"enum": ["directive", "status", "request", "info", "alert"],
"description": "Message category for routing/prioritization"
},
"channel": {
"type": "string",
"description": "Topic channel for grouping (e.g., 'sales', 'infra')"
},
"thread": {
"type": "string",
"description": "Parent message ID for threading"
},
"read_by": {
"type": "array",
"items": { "type": "string" },
"default": [],
"description": "Agent IDs that have read this message"
}
},
"additionalProperties": false
}
Context
We're implementing GNAP in Overlord v2 and are currently writing our own validation schemas (using Zod in TypeScript) by reverse-engineering the README spec and the example files. This works, but we had to make judgment calls on several ambiguities — which fields are required vs. optional, what formats are expected, what value constraints exist.
Having official, machine-readable schemas would eliminate this guesswork for us and for any future GNAP implementer.
What Would Help
A
schemas/directory in the repo with formal definitions for the four core entities. These could be in any standard format:Specific Ambiguities We Encountered
While building our Zod schemas, we ran into these questions that a formal schema would answer:
agents.jsonheartbeatrequired or optional? What's the valid range? (Minimum seconds? Maximum?)runtimea free-form string or an enum?activerequired? What's the default?idformat? (Slugs only? UUIDs? Any string?)tasks/{id}.jsonresultis presumably empty at creation)priority? (1-5? 1-10? Unbounded?)backlogdirectly todone? Fromdoneback toin_progress?)due_dateISO 8601? What about timezone handling?statusvalues? (The README listsbacklog,ready,in_progress,review,done,blocked,cancelled— is this exhaustive?)runs/{task-id}-{attempt}.json{task-id}-{attempt}enforced, or just a convention?input_tokens,output_tokens,cost_usdrequired? (Presumably optional for human agents)artifacts? (Array of strings? Array of objects with paths?)duration_minutesalways minutes, or could it be seconds for short runs?messages/{id}.jsontorequired to have at least one entry? What does an emptytoarray mean?typerequired or optional? What happens if omitted — does the message have no type, or is there an implicit default?channela free-form string or are there conventional values?idformat? Auto-incrementing integers (as in the example)? UUIDs? Slugs?Proposed Schema (Draft)
Here's what we're building on our side as a starting point — happy to contribute this back if it's useful:
{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "GNAP Message", "type": "object", "required": ["id", "from", "to", "text", "at"], "properties": { "id": { "type": "string", "description": "Unique message identifier" }, "from": { "type": "string", "description": "Sender agent ID (must exist in agents.json)" }, "to": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "Recipient agent IDs, or [\"*\"] for broadcast" }, "text": { "type": "string", "description": "Message content" }, "at": { "type": "string", "format": "date-time", "description": "ISO 8601 timestamp" }, "type": { "type": "string", "enum": ["directive", "status", "request", "info", "alert"], "description": "Message category for routing/prioritization" }, "channel": { "type": "string", "description": "Topic channel for grouping (e.g., 'sales', 'infra')" }, "thread": { "type": "string", "description": "Parent message ID for threading" }, "read_by": { "type": "array", "items": { "type": "string" }, "default": [], "description": "Agent IDs that have read this message" } }, "additionalProperties": false }