Leji agent profile frontmatter
Validates the YAML frontmatter of an agent profile document. The markdown body stays free-form.
Fields
-
#
idstring required -
Stable identifier for this profile, e.g. "core" or "reviewer".
Pattern
^[a-z0-9]+(-[a-z0-9]+)*$ -
#
namestring required -
Human-readable name of the role.
-
#
rolestring required -
The role identifier this profile fills, bound in the manifest's agents map.
-
#
purposestring -
One line on what this role is for.
-
#
versionstring -
Optional version of this profile.
-
#
inheritsstring -
id of the profile this one extends, typically the core profile.
-
#
requiredReadarray of strings required -
Paths this role loads before any task.
-
#
defaultContextarray of "domain" · "system" · "practice" · "governance" · "decisions" -
Categories this role loads by default.
-
#
mustAskWhenarray of strings required -
Conditions under which the role must stop and ask a human.
-
#
mustRefuseWhenarray of strings -
Conditions under which the role must refuse outright rather than ask.
-
#
escalationstring -
Who or what to escalate to.
-
#
ownersarray of strings -
Optional owners of this profile.
-
#
freshnessobject -
Review horizon for this profile.
reviewAfterstringISO 8601 date after which the profile should be reviewed for staleness.
-
#
hoststring -
The agent host that runs this agent, e.g. "claude-code", "codex", "cursor". Omit for host-agnostic profiles.
-
#
invocationobject -
How to engage this agent as an external CLI. Omit for the host's own resident agent.
commandstring requiredCommand template to engage this agent from a shell, with <prompt> as the placeholder.
constraintsarray of stringsOperational constraints worth machine-knowing, e.g. prompt length limits, timeouts.
Schema and example
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://leji.org/schemas/v1.0/agent-profile.schema.json",
"title": "Leji agent profile frontmatter",
"description": "Validates the YAML frontmatter of an agent profile document. The markdown body stays free-form.",
"type": "object",
"required": [
"id",
"name",
"role",
"requiredRead",
"mustAskWhen"
],
"additionalProperties": false,
"properties": {
"id": {
"description": "Stable identifier for this profile, e.g. \"core\" or \"reviewer\".",
"type": "string",
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
},
"name": {
"description": "Human-readable name of the role.",
"type": "string",
"minLength": 1
},
"role": {
"description": "The role identifier this profile fills, bound in the manifest's agents map.",
"type": "string",
"minLength": 1
},
"purpose": {
"description": "One line on what this role is for.",
"type": "string"
},
"version": {
"description": "Optional version of this profile.",
"type": "string"
},
"inherits": {
"type": "string",
"description": "id of the profile this one extends, typically the core profile."
},
"requiredRead": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"pattern": "^(?!/)(?!\\./)(?!.*(^|/)\\.\\.(/|$))(?!.*\\\\).+$"
},
"description": "Paths this role loads before any task."
},
"defaultContext": {
"type": "array",
"items": {
"enum": [
"domain",
"system",
"practice",
"governance",
"decisions"
]
},
"description": "Categories this role loads by default."
},
"mustAskWhen": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
},
"description": "Conditions under which the role must stop and ask a human."
},
"mustRefuseWhen": {
"description": "Conditions under which the role must refuse outright rather than ask.",
"type": "array",
"items": {
"type": "string"
}
},
"escalation": {
"type": "string",
"description": "Who or what to escalate to."
},
"owners": {
"description": "Optional owners of this profile.",
"type": "array",
"items": {
"type": "string"
}
},
"freshness": {
"description": "Review horizon for this profile.",
"type": "object",
"additionalProperties": false,
"properties": {
"reviewAfter": {
"description": "ISO 8601 date after which the profile should be reviewed for staleness.",
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
}
}
},
"host": {
"type": "string",
"description": "The agent host that runs this agent, e.g. \"claude-code\", \"codex\", \"cursor\". Omit for host-agnostic profiles."
},
"invocation": {
"type": "object",
"additionalProperties": false,
"required": [
"command"
],
"properties": {
"command": {
"type": "string",
"description": "Command template to engage this agent from a shell, with <prompt> as the placeholder."
},
"constraints": {
"type": "array",
"items": {
"type": "string"
},
"description": "Operational constraints worth machine-knowing, e.g. prompt length limits, timeouts."
}
},
"description": "How to engage this agent as an external CLI. Omit for the host's own resident agent."
}
}
} A conforming agent profile. This schema validates the YAML frontmatter; the markdown body beneath it is free-form prose.
---
id: thought-partner
name: Thought Partner (Codex)
role: thought-partner
purpose: Independent second opinion on copy, design calls, and judgment questions.
host: codex
invocation:
command: codex exec --skip-git-repo-check "<prompt>"
constraints:
- keep prompts compact; very long prompts stall the CLI
- non-interactive; one prompt in, one reply out, no session state
inherits: core
requiredRead:
- docs/boot-profile.md
mustAskWhen:
- the verdict would change a recorded decision
- the question involves confidential material not already in the context layer
---
# Thought Partner (Codex)
Engaged through the `thought-partner` role in `leji.json`, never by name in
protocols. Brief it with self-contained prompts: the relevant copy or decision,
the constraints that bind it, and the exact question. It has no access to this
repository or its history; everything it should weigh goes in the prompt.
Treat its verdicts as one perspective. Disagreements between this partner and
the resident agent go to a person, citing both takes.