Docs/Reference/Bots & groups API
Reference

Bots & groups API

The RPC surface Desktop and iOS use to manage bots and groups — methods, capabilities, error codes, the health handshake, and every hard limit.

This is the contract behind Bots and Bot groups. Desktop and the iOS app both speak it; it is documented here because anything reaching a Flowly gateway has to know the same bounds they do.

Bot methods

Everything a client may ask one bot to do. A method not on this list is refused rather than forwarded, and each carries its own timeout ceiling.

AreaMethods
Providers & modelsprovider.list, provider.active, model.list
Conversationssessions.list, sessions.delete, sessions.model.get, sessions.model.set
Chatchat.history, chat.inflight, chat.send, chat.abort
Mediamedia.read
Shell approvalsexec.approval.list, exec.approval.resolve, exec.policy.get, exec.policy.set
Codexcodex.policy.get, codex.policy.set
Toolstools.access.get, tools.access.set
Questionsagent.clarify.list, agent.clarify.resolve
Plan modeplan.get, plan.resolve, plan.resume, plan.mode.get, plan.mode.set
Goalsgoal.get, goal.pause, goal.resume, goal.stop
Scheduled jobscron.list, cron.add, cron.update, cron.remove, cron.run, cron.output
Commandscommands.list

Most carry a 30-second ceiling; chat.send, model.list, plan.resume, goal.resume and cron.run are allowed 60 seconds.

Permission values

SettingAccepted values
Shell securitydeny, allowlist, full
Shell asks firstoff, on-miss, always
Codex approvalon-request, never, auto-review, granular
Codex sandboxread-only, workspace-write, full-access

Internal sessions

Some sessions belong to host orchestration rather than to a reader, and are not offered as conversations: those prefixed desktop:profile-inbox:, desktop:profile-room: and desktop:profile-task:. Sessions reached from a client carry a desktop:, web: or ios: prefix.

Group methods

MethodWhat it does
profiles.rooms.listEvery group, with or without messages
profiles.rooms.getOne group
profiles.rooms.historyA page of durable history, oldest-first within the page
profiles.rooms.createCreate a group
profiles.rooms.updateRename, change members, change mode or reply policies
profiles.rooms.deleteDelete a group and its attachments
profiles.rooms.prepareWarm the members before a first message
profiles.rooms.sendPost a message and start the turn it triggers
profiles.rooms.stopStop an in-flight turn
profiles.rooms.importAdopt groups from another install
profiles.rooms.approval.resolveAnswer a member's approval request
profiles.rooms.clarify.resolveAnswer a member's question
profiles.rooms.storageWhat groups are using on disk

Capabilities

A host advertises what it supports, so a client never has to guess or infer it from a version number:

{
  "modes": ["panel", "council"],
  "maxMembers": 6,
  "councilRounds": 3,
  "councilTurns": 10,
  "summaries": true,
  "historyPagination": {
    "defaultPageSize": 50,
    "maxPageSize": 100,
    "cursor": "opaque-v2"
  },
  "retention": {
    "model": "retain-beyond-window",
    "liveWindow": 1000,
    "durableHistory": true
  },
  "usage": {
    "tokens": true,
    "cost": "catalog-priced",
    "memberBreakdown": 24
  },
  "memberPolicies": {
    "values": ["always", "mentioned"],
    "default": "always",
    "everyoneOverrides": true,
    "silentWhenNoneAlways": true
  },
  "errorCodes": ["…"],
  "roomEvents": ["full-v1", "delta-v1"],
  "storage": "sqlite-wal",
  "legacyJsonMigration": "verified-copy-preserve-source"
}

modes advertises both shapes the host can run, and clients send mode on create and update. A payload without it means panel, which is what every group did before the field existed — so a client that does not know it still creates groups that behave correctly, and an update that omits it leaves the shape alone rather than resetting it.

Two of these deserve reading twice:

  • retention.liveWindow is not how many messages exist. It is what the group carries in memory and in a snapshot payload. Durable history is not bounded by it. A client that treats the window as the total will report a group as shorter than it is the moment it outgrows the window.
  • usage.cost is catalog-priced. Tokens are counted for every group; money appears only when the model catalogue can price the models involved. A client must be ready to render a group that reports tokens and no cost.

Member reply policies

memberPolicies describes who answers a message that named nobody:

  • valuesalways and mentioned
  • defaultalways, which is what every group did before the field existed, so a client that does not know the field still describes its groups correctly
  • everyoneOverrides — an explicit @everyone reaches members set to mentioned
  • silentWhenNoneAlways — a group where nobody is always records an unaddressed message and starts no run. Clients should say so rather than leave somebody waiting for a reply that is not coming.

Policies are sent as a map of member name to policy. Absent means unchanged on an update, not cleared — otherwise an older client renaming a group would quietly make every member answer again.

Error codes

A failure is named by a code, and the client translates the code. The sentence that travels with it is for a log, not for a reader.

CodeMeans
HOST_STOPPEDThe bot host is no longer running
METHOD_NOT_ALLOWEDThe method is not available on this host
PROFILE_NOT_FOUNDOne of the selected bots no longer exists
ROOM_ATTACHMENT_TOO_LARGEAn attachment exceeded 25 MB
ROOM_BUSYThe group is already answering
ROOM_BUSY_DELETECannot delete while a turn is running
ROOM_BUSY_MEMBERSCannot change members while a turn is running
ROOM_CURSOR_INVALIDThe history cursor does not belong to this group
ROOM_HISTORY_UNAVAILABLEDurable history could not be read
ROOM_INVALIDThe group id is not a valid one
ROOM_LIMIT200 groups already exist
ROOM_LIMIT_IMPORTAn import would exceed that limit
ROOM_MEMBERS_INVALIDThe member list is not valid
ROOM_MEMBERS_TOO_FEWFewer than two members
ROOM_MEMBER_FAILEDA member could not answer
ROOM_NOT_FOUNDNo such group
ROOM_REQUEST_CLOSEDThe approval or question is no longer open
ROOM_START_FAILEDA member could not be started
ROOM_STOPPEDThe turn was stopped
ROOM_STORE_CONFLICTAnother process wrote first
ROOM_STORE_INVALIDThe group database is damaged or unreadable
ROOM_STORE_LIMITThe group database reached its safe size

INVALID_PARAMS is deliberately absent from that table. It means a client sent something malformed, so the person reading it is the one debugging that client, and English is the right language for them.

Gateway identity

A running gateway states what it is on /health, which needs no token:

{
  "status": "ok",
  "service_id": "ai.flowly.gateway",
  "version": "3.2.0",
  "runtime_owner": "desktop",
  "auth_required": false,
  "capabilities": ["tool_events", "queue_while_busy", "…"]
}
  • service_id is always ai.flowly.gateway. A client that sees a different value should treat the response as coming from something that is not Flowly.
  • version is omitted by a source checkout that cannot state a real version, rather than reported as 0.0.0-dev — which would compare as older than every release.
  • runtime_owner is desktop, cli or manual, taken from the environment the starter set, or from the executable's own path. It is omitted when neither says anything definite, so a reader falls back to its own classification rather than acting on a guess.

Storage

Groups are kept in one SQLite database, write-ahead-logged so several processes can use it safely.

Schema version4
Readable schema versions1, 2, 3, 4
Maximum database size2 GB
Maximum group record256 KB
Maximum message record4 MB

Migrations run forward one step at a time and stamp each version before the next begins, so a crash between two steps cannot leave finished work behind an unchanged version number.

A database written by a newer Flowly is left untouched by an older one, which reports an unrecognised schema rather than editing it. Groups stop working on the older build; the data is not damaged.

Limits

Groups per installation200
Members per group2–6
Live window1,000 messages
Live window size~2 MB, never fewer than 30 messages
Context per member per turn40 messages
History page50 default, 100 maximum
Attachments per message10
Attachment size25 MB
Thumbnail size256 KB
Tool calls kept per message8
Council3 rounds, 10 turns
Member response timeout10 minutes
Per-member usage rows24
Group media notice500 MB

Sessions

Each member keeps a private session for each group, keyed desktop:profile-room:<groupId> inside that bot's own directory. Group attachments are stored with a group- prefix, which is what keeps the ordinary media cleanup — which ages out generated pictures — from reaching a file a message still points at.