Working-group bots: build out as isolated profiles (architecture) #33

Open
opened 2026-10-26 14:46:39 +00:00 by inference-bot · 1 comment
Owner

What we are building

One agent per working group, living in that group's Matrix room: group members watch, stewards
prompt it, and it posts what it did. Limited and appropriate permissions, transparency by
architecture, and no member data on the agent host.

Continues the work in #17 (closed): the steward bot moved onto co-op infrastructure and the
first non-steward agent, infrastructure-bot, is running isolated. This issue is about scaling
that to group bots deliberately rather than by accident.

Isolation model (decided 2026-10-26)

Three tiers, using the cheapest mechanism that is still honest:

  • Tier 1 — the steward bot (inferencebot). Own Unix user. Holds the co-op's master
    credentials (gateway admin, Cloudron, the room-administration account) and is the
    fleet-administration path.
  • Tier 2 — member-facing group bots. One Unix user for the tier (today the
    infrastructure-bot user), one Hermes profile per bot, and one gateway process serving all
    of those profiles. This is where the resource savings come from.
  • Tier 3 — anything with materially different privilege. A bot holding a group's staging-app
    credential, or any bot with member-data access, gets its own Unix user, because its
    credentials must not be readable by its siblings.

The rule that decides the tier: a bot may be a profile only if we would be comfortable with
it holding every other credential in that tier. Profiles of one user share a home, so one bot can
read another's configuration and keys. That is acceptable when the scope is genuinely identical,
and unacceptable when it is not.

Why profiles for tier 2 (measured on the agent host)

  • A separate agent costs ~3 GB of disk (runtime, source, tool installs) plus its own gateway
    process at ~0.3–0.75 GB of RAM.
  • A profile adds only its own state — skills, sessions, logs, database — a few hundred MB, most
    of it disposable cache.
  • One gateway process serves every profile on the host, so N group bots share one process
    instead of needing N.
  • For four bots: separate users would be ~12 GB of disk and ~1.6 GB of RAM on a host with
    ~2.4 GB free, which does not fit. Profiles are ~1–2 GB of disk and one process. On this host
    profiles are close to necessary, not merely cheaper.

Per-bot composition (the permission backplane)

  • Its own inference budget: one gateway team per bot (agent:<group>) with a model allowlist
    and a monthly cap, so spend is attributable and revocable per bot.
  • Its own Matrix identity and room: the group's room, prompting limited to that group's
    stewards, mention-required so it never speaks unprompted, isolated session lanes per steward,
    and read-only digests for members.
  • Tool tiers: read-mostly toolsets in shared rooms; write access only against that group's
    staging app; destructive operations only in operator messages, never in a shared room.
  • No member data on the host: harnesses stay stateless. Confidential member data stays on the
    primary; a compromise here exposes keys, never member records.

The load-bearing control: tool restriction

Credential separation between profiles only means something if a bot cannot read its siblings'
files. A profile with arbitrary shell or filesystem access can read every other profile's
secrets, and a single injected instruction then reaches the whole tier. Tier 2 therefore requires
an explicit toolset allowlist per bot (no arbitrary filesystem or shell access) and a
deliberately small tier. Where we cannot restrict tools for a given deployment, that bot belongs
in tier 3.

Adding a bot (repeatable, ~15 minutes once the pilot proves it)

profile → scoped gateway team and key → Matrix account and group room → per-bot configuration
(room, steward allowlist, toolset) → isolation test (confirm through the bot's own tools that it
cannot read a sibling's credentials) → hand it to the group with the norms in
docs#6.

Accepted trade-offs

  • One gateway serves the whole tier: a restart affects every group bot at once, and compromising
    the tier user exposes all tier-2 credentials. Accepted in exchange for the resource savings,
    with the tier kept small and its credentials low-privilege.
  • Attribution inside a tier rests on configuration rather than the kernel, so we keep per-bot
    identities and steward-only prompting. Anything needing a hard guarantee belongs in tier 3.

First step, before building

Verify profile behavior empirically with a throwaway profile: that profiles share the runtime,
that the tier's gateway serves them, that each profile's environment and credentials are its own,
and that toolsets can be restricted per profile. A configuration that looked correct and was not
cost us a cycle already (#17); these numbers should be measured, not assumed.

Open decisions

  • Which group pilots first.
  • Who counts as a steward for each group, and where that list is maintained.
  • Per-bot budget and model tier.
  • What a group dissolving means for its bot (delete the profile, revoke the key, leave the room).
  • Whether to cap the tier user's memory so one runaway bot cannot starve the host.
## What we are building One agent per working group, living in that group's Matrix room: group members watch, stewards prompt it, and it posts what it did. Limited and appropriate permissions, transparency by architecture, and no member data on the agent host. Continues the work in #17 (closed): the steward bot moved onto co-op infrastructure and the first non-steward agent, `infrastructure-bot`, is running isolated. This issue is about scaling that to group bots deliberately rather than by accident. ## Isolation model (decided 2026-10-26) Three tiers, using the cheapest mechanism that is still honest: - **Tier 1 — the steward bot (`inferencebot`).** Own Unix user. Holds the co-op's master credentials (gateway admin, Cloudron, the room-administration account) and is the fleet-administration path. - **Tier 2 — member-facing group bots.** One Unix user for the tier (today the infrastructure-bot user), **one Hermes profile per bot**, and one gateway process serving all of those profiles. This is where the resource savings come from. - **Tier 3 — anything with materially different privilege.** A bot holding a group's staging-app credential, or any bot with member-data access, gets its own Unix user, because its credentials must not be readable by its siblings. **The rule that decides the tier:** a bot may be a profile only if we would be comfortable with it holding every other credential in that tier. Profiles of one user share a home, so one bot can read another's configuration and keys. That is acceptable when the scope is genuinely identical, and unacceptable when it is not. ## Why profiles for tier 2 (measured on the agent host) - A separate agent costs ~3 GB of disk (runtime, source, tool installs) plus its own gateway process at ~0.3–0.75 GB of RAM. - A profile adds only its own state — skills, sessions, logs, database — a few hundred MB, most of it disposable cache. - One gateway process serves every profile on the host, so N group bots share one process instead of needing N. - For four bots: separate users would be ~12 GB of disk and ~1.6 GB of RAM on a host with ~2.4 GB free, which does not fit. Profiles are ~1–2 GB of disk and one process. On this host profiles are close to necessary, not merely cheaper. ## Per-bot composition (the permission backplane) - **Its own inference budget:** one gateway team per bot (`agent:<group>`) with a model allowlist and a monthly cap, so spend is attributable and revocable per bot. - **Its own Matrix identity and room:** the group's room, prompting limited to that group's stewards, mention-required so it never speaks unprompted, isolated session lanes per steward, and read-only digests for members. - **Tool tiers:** read-mostly toolsets in shared rooms; write access only against that group's staging app; destructive operations only in operator messages, never in a shared room. - **No member data on the host:** harnesses stay stateless. Confidential member data stays on the primary; a compromise here exposes keys, never member records. ## The load-bearing control: tool restriction Credential separation between profiles only means something if a bot cannot read its siblings' files. A profile with arbitrary shell or filesystem access can read every other profile's secrets, and a single injected instruction then reaches the whole tier. Tier 2 therefore requires an explicit toolset allowlist per bot (no arbitrary filesystem or shell access) and a deliberately small tier. Where we cannot restrict tools for a given deployment, that bot belongs in tier 3. ## Adding a bot (repeatable, ~15 minutes once the pilot proves it) profile → scoped gateway team and key → Matrix account and group room → per-bot configuration (room, steward allowlist, toolset) → isolation test (confirm through the bot's own tools that it cannot read a sibling's credentials) → hand it to the group with the norms in [docs#6](https://git.inference.coop/co-op/docs/pulls/6). ## Accepted trade-offs - One gateway serves the whole tier: a restart affects every group bot at once, and compromising the tier user exposes all tier-2 credentials. Accepted in exchange for the resource savings, with the tier kept small and its credentials low-privilege. - Attribution inside a tier rests on configuration rather than the kernel, so we keep per-bot identities and steward-only prompting. Anything needing a hard guarantee belongs in tier 3. ## First step, before building Verify profile behavior empirically with a throwaway profile: that profiles share the runtime, that the tier's gateway serves them, that each profile's environment and credentials are its own, and that toolsets can be restricted per profile. A configuration that looked correct and was not cost us a cycle already (#17); these numbers should be measured, not assumed. ## Open decisions - Which group pilots first. - Who counts as a steward for each group, and where that list is maintained. - Per-bot budget and model tier. - What a group dissolving means for its bot (delete the profile, revoke the key, leave the room). - Whether to cap the tier user's memory so one runaway bot cannot starve the host.
Author
Owner

First step done (2026-10-26): profiles verified on the tier-2 user. The numbers hold, and one control turns out to be mandatory rather than nice-to-have.

  • Cost: ~5 MB per profile, not ~3 GB. A profile has no runtime of its own — it shares the parent's — so it adds only state (a skills copy, empty DBs, logs). A separate agent costs ~3 GB of disk plus ~375 MB of RAM for its own gateway process.
  • Adding or removing a profile needs no restart. The running gateway adopts it live and drops it live ([MULTIPLEX] … serving every profile from this process (no restart), later Profile 'X' unserved), and it re-scans a profile when its config or .env changes. So a new group bot — including its credentials — can be added without touching the gateway at all.
  • Per-profile secrets are its own. Each profile gets its own .env and config.yaml. Cloning deliberately leaves messaging tokens and allowlists behind, so a cloned bot has no Matrix credentials until its own are added — which is what we want anyway.
  • The toolset restriction is the real boundary, and it binds. Defaults grant the full toolset (terminal, file, computer_use…). Restricted to the documented read-only set, a profile asked to read a sibling's secrets could not: it searched for a file-reading tool, found nothing available — the on-demand tool catalog is restricted too — and reported no file access.
  • The weakness it compensates for is confirmed: any process running as that user reads the parent's .env. Profile separation is credential organisation; the toolset allowlist is the control. Every group-bot profile must therefore carry an explicit read-only toolset — a provisioning step, not a nicety.

Consequences for the build-out:

  • The isolation test is now specific: ask a bot, through its own tools, to read another profile's secrets, and confirm it cannot (including via the on-demand catalog).
  • The accepted trade-off narrows: inside a tier, credentials are mutually readable by design of the mechanism, so every tier-2 credential must stay low-privilege and the tier must stay small.
  • Since no restart is needed to add a bot, the operator-only restart constraint does not gate the rollout.
**First step done (2026-10-26): profiles verified on the tier-2 user.** The numbers hold, and one control turns out to be mandatory rather than nice-to-have. - **Cost: ~5 MB per profile, not ~3 GB.** A profile has no runtime of its own — it shares the parent's — so it adds only state (a skills copy, empty DBs, logs). A separate agent costs ~3 GB of disk plus ~375 MB of RAM for its own gateway process. - **Adding or removing a profile needs no restart.** The running gateway adopts it live and drops it live (`[MULTIPLEX] … serving every profile from this process (no restart)`, later `Profile 'X' unserved`), and it re-scans a profile when its config or `.env` changes. So a new group bot — including its credentials — can be added without touching the gateway at all. - **Per-profile secrets are its own.** Each profile gets its own `.env` and `config.yaml`. Cloning deliberately leaves messaging tokens and allowlists behind, so a cloned bot has no Matrix credentials until its own are added — which is what we want anyway. - **The toolset restriction is the real boundary, and it binds.** Defaults grant the full toolset (terminal, file, computer_use…). Restricted to the documented read-only set, a profile asked to read a sibling's secrets could not: it searched for a file-reading tool, found nothing available — the on-demand tool catalog is restricted too — and reported no file access. - **The weakness it compensates for is confirmed:** any process running as that user reads the parent's `.env`. Profile separation is credential *organisation*; the toolset allowlist is the control. Every group-bot profile must therefore carry an explicit read-only toolset — a provisioning step, not a nicety. Consequences for the build-out: - The isolation test is now specific: ask a bot, through its own tools, to read another profile's secrets, and confirm it cannot (including via the on-demand catalog). - The accepted trade-off narrows: inside a tier, credentials are mutually readable *by design of the mechanism*, so every tier-2 credential must stay low-privilege and the tier must stay small. - Since no restart is needed to add a bot, the operator-only restart constraint does not gate the rollout.
inference-admin added the Infrastructure label 2026-11-09 16:23:46 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: co-op/support#33