kind: InlineAgentSkill
content: |
  ---
  name: agent-author
  description: Write a new capability for this brainstem — either a RAPP agent (agents/<thing>_agent.py, a BasicAgent subclass that becomes a tool) or an Agent Skill (agents/<name>/SKILL.md with instructions, scripts/, references/). Both are called by the model from the user's intent. Use when asked to "add an agent", "make a skill", "teach the brainstem to X", or to convert one into the other.
  argument-hint: "<what the capability should do>"
  ---

  # Author a brainstem capability

  Decide the shape first:

  - **Agent** (`agents/<thing>_agent.py`) when the capability is *code*: it computes, calls an
    API, reads or writes storage, and returns a string. It becomes a tool with its exact JSON
    schema. Hot-loaded on the next request; no restart.
  - **Skill** (`agents/<name>/SKILL.md`) when the capability is *procedure*: steps the model
    should follow, house style, checklists, references. Optional `scripts/` the model can run
    with `run_skill_script` and `references/` it can read with `read_skill_file`.
  - A skill can carry an agent inside it (rapp-skills format, `<!-- agent sha256=... -->`
    block); the brainstem loads that code as a tool automatically.

  ## Agent template

  ```python
  from agents.basic_agent import BasicAgent
  # optional, every agent can use installed skills:
  # from utils.skills import list_skills, get_skill, read_file, render, run_script

  class ThingAgent(BasicAgent):
      def __init__(self):
          self.name = "Thing"                      # tool-safe: letters, digits, _ -
          self.metadata = {
              "name": self.name,
              "description": "One sentence: when the model should call this.",
              "parameters": {"type": "object", "properties": {
                  "text": {"type": "string", "description": "..."}}, "required": ["text"]},
          }
          super().__init__(self.name, self.metadata)

      def perform(self, text="", **kwargs):
          return f"did the thing with {text}"
  ```

  Rules: filename ends in `_agent.py`, one class per concern, `perform` returns a string,
  never raise for user mistakes (return the message). Storage: `from utils.azure_file_storage
  import AzureFileStorageManager` works locally.

  ## Skill template

  ```markdown
  ---
  name: kebab-name
  description: What it does and WHEN to use it (this is all the model sees up front).
  argument-hint: "[optional]"
  ---

  # Title
  1. Step. 2. Step. $ARGUMENTS is replaced with what the user asked for.
  ```

  The frontmatter `name` must equal the directory name. The skill becomes a tool named
  `kebab-name` (a `BasicSkill`, which is a `BasicAgent`); the model
  calls it when the description fits the request, exactly as it calls an agent. To give a skill
  custom parameters or code around it, write an agent that subclasses `agents.basic_skill.BasicSkill`
  with `skill = "kebab-name"` and use `self.instructions()`, `self.read()`, `self.run_script()`. Frontmatter honored: `name`, `description`,
  `argument-hint` (quote it), `disable-model-invocation: true` (agents can still read it via
  `utils.skills`, the model cannot call it), `allowed-tools`, `metadata`.

  ## Verify

  `python brainstem.py list` shows the new agent or skill (and any quarantine reason).
  `python -m pytest -q` stays green. For a live check: `curl -s localhost:7071/chat -d
  '{"user_input":"..."}' -H 'content-type: application/json'`.
