---
title: "AI labels"
description: "Identify agent-written messages on supported console, chat and connector surfaces, in your tenant's words."
canonical_url: "https://docs.oz0.ai/govern/ai-labels"
---
# AI labels

> Identify agent-written messages on supported console, chat and connector surfaces, in your tenant's words.

For: tenant admins and governance reviewers.

Orchestrator Zero adds an AI label on the supported console, chat and connector surfaces listed below. The label is on by default and says `AI agent` unless a tenant changes its wording. APIs provide label metadata for clients to display; CLI and SDK response text is not prefixed automatically.

## Where the label is

<table>
<thead>
  <tr>
    <th>
      Where
    </th>
    
    <th>
      How it looks
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <a href="https://docs.oz0.ai/build/apps/chat-channels">
        Chat channels
      </a>
      
      : openings, answers, questions, approvals and notices in Slack, Discord or any channel plugin
    </td>
    
    <td>
      In the message itself: <code>
        [AI agent] The deploy is green.
      </code>
      
       Slack and Discord show it in the message's text, not only in the app's name.
    </td>
  </tr>
  
  <tr>
    <td>
      What an agent posts to a chat with a plugin's <code>
        send
      </code>
      
       (<code>
        oz0_slack.send
      </code>
      
      , <code>
        oz0_discord.send
      </code>
      
      )
    </td>
    
    <td>
      The same prefix, from the call's <code>
        _meta
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      What an agent posts by calling a channel's post function itself (<code>
        oz0_slack.post
      </code>
      
      , <code>
        oz0_discord.post
      </code>
      
      ), which the agent's manifest lists
    </td>
    
    <td>
      The same prefix, from the call's <code>
        _meta
      </code>
      
      : a <code>
        label
      </code>
      
       argument the agent passes is not used
    </td>
  </tr>
  
  <tr>
    <td>
      Issues, comments, pull requests and reviews <a href="https://docs.oz0.ai/build/plugins/github">
        ai.oz0/github
      </a>
      
       writes for an agent
    </td>
    
    <td>
      A small first line: <code>
        &lt;sub>[AI agent]&lt;/sub>
      </code>
      
      , on each line comment of a review too
    </td>
  </tr>
  
  <tr>
    <td>
      Mail agents send with <a href="https://docs.oz0.ai/build/plugins/verified/email">
        ai.oz0/email
      </a>
    </td>
    
    <td>
      <a href="#mail-agents-send-with-aioz0email">
        Details
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <a href="https://docs.oz0.ai/build/parts/routines/outputs-and-permissions#safe-outputs">
        Safe outputs
      </a>
      
       the edge posts to their receiver
    </td>
    
    <td>
      <code>
        "ai_label": "AI agent"
      </code>
      
       in the JSON body: a receiver that shows the request to people shows the label with it
    </td>
  </tr>
  
  <tr>
    <td>
      The <a href="https://docs.oz0.ai/build/apps/mcp-server">
        MCP server
      </a>
      
      's answers
    </td>
    
    <td>
      <code>
        _meta["ai.oz0/ai-label"]
      </code>
      
       on each result and task, and a question's elicitation message starts with <code>
        [AI agent]
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <a href="https://docs.oz0.ai/build/apps/a2a">
        A2A
      </a>
      
       tasks
    </td>
    
    <td>
      Messages already say <code>
        ROLE_AGENT
      </code>
      
      ; the task's, its messages' and its artifact's <code>
        metadata
      </code>
      
       carry <code>
        ai.oz0/ai-label
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      The <a href="https://docs.oz0.ai/build/apps/runtime-api">
        runtime API
      </a>
      
      's jobs
    </td>
    
    <td>
      <code>
        ai_label
      </code>
      
       on the job that <code>
        GetJob
      </code>
      
       and <code>
        StartJob
      </code>
      
       answer: the tenant's label for the job's agent, empty when it is off, for an app that shows the agent's words to put it in them
    </td>
  </tr>
  
  <tr>
    <td>
      The <a href="https://docs.oz0.ai/build/apps/ag-ui">
        AG-UI route
      </a>
    </td>
    
    <td>
      At the start of the first <code>
        TEXT_MESSAGE_CONTENT
      </code>
      
       of each of the agent's messages, in the text itself, and in the message start's <code>
        metadata["oz0/ai-label"]
      </code>
      
      ; a question's interrupt <code>
        message
      </code>
      
       starts with it, and every interrupt's <code>
        metadata["oz0/ai-label"]
      </code>
      
       names it
    </td>
  </tr>
  
  <tr>
    <td>
      The <a href="https://docs.oz0.ai/build/apps/chat-app">
        chat app example
      </a>
    </td>
    
    <td>
      At the start of each answer's text, and of each question the agent asks, as the AG-UI route sends them; approvals name it beside their words
    </td>
  </tr>
  
  <tr>
    <td>
      The console
    </td>
    
    <td>
      A badge on each answer of a <a href="https://docs.oz0.ai/agents/conversations">
        conversation
      </a>
      
      , on a job's <strong>
        Answer
      </strong>
      
       tab, and on questions and approvals agents ask
    </td>
  </tr>
</tbody>
</table>

### Mail agents send with ai.oz0/email

A line of its own at the start of the text body, `[AI agent]`, and a paragraph that is the first element of the HTML body.

The edge puts it in, stacks it above the rest of the body and puts the rest in a box that clips what it paints, and refuses HTML that could hide or cover it in a client that reads neither: styles are read as CSS reads them, whatever their spelling (a comment in a property's name, a vendor prefix), and what could paint over the label is refused or bounded (a `<dialog>`, an inline element's top padding and border, a font's size however it is nested, a line's height)

An app on the AG-UI route gets the label in the agent's text, where it stays whatever the app does with the text. How the app shows its own users that they talk to an AI, and what else it must tell them, is the app maker's to decide.

MCP has no field for who wrote a result, so the label goes in `_meta`, the place MCP keeps for what it does not name; the result's text stays the agent's, since a calling model reads it and `structuredContent` must match the agent's output schema. A2A says who wrote a message with its role, and the label adds the tenant's words in `metadata`.

## Word it

```bash [Terminal]
oz0 tenant ai-label show
oz0 tenant ai-label set --text '{agent} (AI)' --reason "brand guide 3"
oz0 tenant ai-label set --language sv='{agent} (AI-agent)' --language de='KI-Agent' --reason "Swedish and German readers"
```

The label is a [governance setting](https://docs.oz0.ai/govern/reviewed-changes#four-eyes-for-governance-changes): every change takes `--reason` (and may take `--decision-ref`), which the audit log keeps.

```text
AI label of tenant default: on, set by user:admin just now
wording {agent} (AI)
reads   [agent (AI)] ...
de  KI-Agent
sv  {agent} (AI-agent)
```

`{agent}` is the agent's name, so `{agent} (AI)` reads `[pr-reviewer (AI)] ...`. A wording is plain text on one line, at most 60 characters, without markup or mentions, and it must say more than `{agent}`: `--text '{agent}'` is refused.

A wording should say that an AI wrote the message. One with no word such as `AI`, `KI`, `IA` or `bot` in it (`Support team`, say) is kept, but `set` and `show` print a warning, **Govern › Policy › AI label** shows it, and the audit log keeps the change as `tenant.ai_label.unmarked` too.

The check knows a handful of words in common languages; if your wording says AI in words it does not know, the warning is the only effect.

A wording per language is used where the reader's language is known: in the console, your browser's. Chat posts, comments and API answers use the tenant's wording.

`--default` goes back to `AI agent`, and `--language sv=` removes one language.

Admins of the tenant set the label under **Govern › Policy**, **More**, **AI label**, too; readers see it there. Edges label with a new wording within seconds, and nodes from their next heartbeat.

## Turning it off

The label is on unless an admin turns it off, with a reason:

```bash [Terminal]
oz0 tenant ai-label set --off --reason 'a test workspace where only bots read'
```

```text
warning: The AI label is off: people who read this tenant's agents in chat systems, on GitHub, through MCP and A2A and in the web UI are no longer told by the platform that an AI agent wrote what they read. Article 50 of the EU AI Act ...
```

`--off` without `--reason` is refused, and with four eyes on, turning it off waits for another admin. The audit log keeps every change as `tenant.ai_label`, and turning it off as `tenant.ai_label.off`, with the reason and the warning the admin was shown; `--on` turns it on again (`tenant.ai_label.on`). While it is off, **Govern › Policy › AI label** says so in a warning. Two admins who change the label at once each get the audit entries of their own change: the setting before a change is read with the tenant's row locked.

## The EU AI Act

Article 50 of the EU AI Act ([Regulation (EU) 2024/1689](https://eur-lex.europa.eu/eli/reg/2024/1689/oj)) has transparency duties that apply from 2 August 2026: AI systems that interact with people are to tell them they interact with an AI system, unless that is obvious from the context; AI-generated text published to inform the public on matters of public interest is to be disclosed; and the information is to be given clearly, at the latest at the first interaction.

What the label does: it tells the people who read your agents' messages, in the message itself, that an AI agent wrote them, from the first message of a thread on.

What it does not do, and what stays yours:

- It is not legal advice, and turning it on does not by itself settle what Article 50 asks of you. Whether and how Article 50 applies to you, as a provider or a deployer, is for you and your counsel to decide.
- It does not mark generated images, audio or video, and it is not a watermark: text that someone copies out of a message loses the label.
- It labels what goes through the platform's surfaces. What a receiver of a safe output, a plugin that is not one of the verified ones, an MCP or A2A client, or your own code does with an agent's text (and whether it shows `ai_label` or `_meta`) is up to them.
- It labels by where a message comes from, not by who chose its words: a [flow](https://docs.oz0.ai/build/parts/flows) step that comments with a fixed template through `ai.oz0/github` is labelled like an agent's comment, and so is a platform notice in a chat thread.
- The CLI and the SDKs give you an agent's text as it wrote it: `oz0 run`, `oz0 job get` and `oz0 approval list` print answers and questions with no label, and so do the admin and runtime APIs they call. You are the one reading there, and you asked the agent. Where your code passes that text on to other people, labelling it is up to your code.
- The three-second acknowledgements a chat plugin's manifest gives (Slack's `On it.`) are the platform's own words, not an agent's, and carry no label.
- Channels that are neither chat plugins nor ai.oz0/email come later. In mail the label holds where the reader's mail client shows the HTML as written. Where a client reads positioned or clipped styles (as browsers and most mail clients do), nothing in the body paints over the label.<br />

In one that reads neither, the bounds on styles and font sizes keep a line's text near its line, but text whose glyphs or stacked accents reach far above it (in any font) can still paint over the label there. What a client's own style sheet adds beyond the HTML standard's is outside what the edge checks.


## Sitemap

See the full [sitemap](https://docs.oz0.ai/sitemap.md) for all pages.
