Leji agent profile frontmatter

Validates the YAML frontmatter of an agent profile document. The markdown body stays free-form.

Canonical $id: https://leji.org/schemas/v1.0/agent-profile.schema.json
Raw file: agent-profile.schema.json

Fields

# id string required

Stable identifier for this profile, e.g. "core" or "reviewer".

Pattern ^[a-z0-9]+(-[a-z0-9]+)*$

# name string required

Human-readable name of the role.

# role string required

The role identifier this profile fills, bound in the manifest's agents map.

# purpose string

One line on what this role is for.

# version string

Optional version of this profile.

# inherits string

id of the profile this one extends, typically the core profile.

# requiredRead array of strings required

Paths this role loads before any task.

# defaultContext array of "domain" · "system" · "practice" · "governance" · "decisions"

Categories this role loads by default.

# mustAskWhen array of strings required

Conditions under which the role must stop and ask a human.

# mustRefuseWhen array of strings

Conditions under which the role must refuse outright rather than ask.

# escalation string

Who or what to escalate to.

# owners array of strings

Optional owners of this profile.

# freshness object

Review horizon for this profile.

reviewAfter string

ISO 8601 date after which the profile should be reviewed for staleness.

# host string

The agent host that runs this agent, e.g. "claude-code", "codex", "cursor". Omit for host-agnostic profiles.

# invocation object

How to engage this agent as an external CLI. Omit for the host's own resident agent.

command string required

Command template to engage this agent from a shell, with <prompt> as the placeholder.

constraints array of strings

Operational 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.

← All schemas