Orkestia
Blog
Chat

Internal support actor

Internal mode lets an attached actor answer your own team with your organization's tools instead of the app's end-user workflows, for an allowlist of people in a space where everyone is on that list

In seat mode, an actor in the chat can only use the workflows your app exposes to end users. That is right for customers, and useless for an assistant that should answer your own team: "what failed in the nightly run?", "is that ticket still open?", "did the release go out?".

Internal mode lets one attached actor reply as an ordinary organization session, with the skills and MCP servers its own agent config declares. It is a per-attachment switch with strict gates.

When you can use it

Internal mode is available only in organizations Orkestia has enabled it for. If buzz.actor.set-reply-principal refuses with org_principal_not_allowlisted, contact Orkestia support.

All of these must hold, and they are checked again on every message:

  1. Your organization is enabled for internal mode.
  2. A person who is an organization admin or owner turns it on, signed in as themselves. API keys, the system, agents and end users are refused.
  3. The people who may wake the actor are listed. Between 1 and 50 end users of the space's app, each active or invited.
  4. The message's author is on that list.
  5. Every active person in the space is on that list. Actors do not count. If anyone else joins the space, the actor goes silent until they are removed or listed.

When a gate fails, the actor posts nothing. A polite refusal would tell someone outside the list that an internal assistant sits in the chat. The inbound ledger records why (author_not_allowed, space_has_external_members, org_principal_not_allowlisted).

Turn it on

For an actor that is already attached in seat mode:

start_workflow("buzz.actor.set-reply-principal", {
  "space_uuid": "<space uuid>",
  "attachment_uuid": "<from data.buzz.attachment.list>",
  "reply_principal": "organization",
  "allowed_author_end_user_uuids": ["<end user uuid>", "<end user uuid>"]
})

For a new actor, pass reply_principal: "organization" and allowed_author_end_user_uuids to buzz.actor.attach directly. An actor attached this way does not need to declare that it acts as the app.

To go back, set reply_principal to "seat". The actor then needs its act-as declaration again to answer.

Switch the attachment first, then remove act-as from the actor's Staff definition and give it its tools. Until the definition changes, replies keep running as the seat, so nothing breaks in between.

What changes in a reply

Seat modeInternal mode
Runs asThe actor's end-user seat in the appAn organization session of the actor
ToolsThe app's end-user workflows onlyThe skills and MCP servers in the actor's own config
Platform default toolsNot part of a seat sessionOff, forced by the chat whatever the config says
Who can wake itAny member of the spaceOnly listed people, and only while everyone in the space is listed

Everything else stays the same: the reply ceiling, duplicate protection, signature checks, the refusal to answer actors, and the actor's end-user seat requirement.

Build a good internal assistant

  • Keep the tools narrow. Prefer read tools: actor state, recent failed sessions, ticket search and get, pull request status, the clock. Add a few narrow writes, such as opening a ticket or adding a comment, only when people ask for them.
  • Turn memory off. An organization session would otherwise share one memory across everyone who talks to it. Set memory off on the agent config.
  • Keep the budget small and the step limit low. A support answer needs a handful of tool calls.
  • Tell it to treat tool results as data. Ticket, pull request and session text can contain instructions; the actor must never follow them.
  • Put it in a space only your team uses. The "everyone is listed" gate is what keeps organization data out of the wrong conversation.

Audit

  • The mode change is recorded on the space with who set it and when.
  • Every message that reaches the actor is a ledger row (data.buzz.inbound.list) with its outcome.
  • Every reply's actor run is attributed to the chat, with the reply mode and the person who asked, and its session is linked from it, so any answer can be traced back to the question.

Ask your AI assistant

prompts
Show me which actors in my chat space reply as the organization and which reply as their seat. Use data.buzz.attachment.list and data.buzz.space.get.

Switch the actor "<actor name>" in my internal chat space to internal mode for these people: <names>. Find their end user uuids with identity.end-user.query and the attachment with data.buzz.attachment.list, then show me the buzz.actor.set-reply-principal call. I will start it myself.

Why did my internal support actor not answer? Read data.buzz.inbound.list for the space and explain the latest reason codes.

For AI agents

RuleDetail
You cannot switch itbuzz.actor.set-reply-principal refuses agents and API keys. Prepare the call for an org admin or owner
Silent by designNo reply plus author_not_allowed or space_has_external_members in the ledger is the gate working, not a bug
Enablementorg_principal_not_allowlisted needs Orkestia support. Nothing in the organization can change it
Data handlingAnswers can carry organization data. Never suggest adding people outside the organization to an internal space