# House-admin cross-account authority

The house account is the operator-owned account that runs the admin assistant. Sub-accounts are isolated: each one's tools read and write only that account's data, which is what keeps tenants separate.

By default the admin assistant is scoped the same way — it acts on the house account. Cross-account authority lets a house-scoped admin session act on a named sub-account by passing that account as a target, while every other session (public visitors, a session already scoped to a sub-account, background specialists) is refused. The refusal is fail-closed: a session that is not house-scoped and names a target is denied, never quietly redirected to its own account.

The operator wants this for two surfaces: the account graph and the account filesystem. Each is a separate adoption; a coverage ledger tracks them and a background check confirms neither silently regresses.

## Creating a sub-account can name a managing admin

A client sub-account may have a responsible house admin, but one is optional. `account_create` takes the `userId` of a current house admin as the managing admin — the admin agent asks the operator which house admin manages the client (the choices come from `admin-list`) — and records it as `managingAdminUserId` on the sub-account; a supplied `userId` that is not a live house admin is refused. Omit it for a client run by its owner rather than a house team member. A WhatsApp requirement that comes in for that sub-account is filed as a task assigned to its managing admin; when the sub-account has no managing admin (or its recorded one is no longer a live house admin), the task is assigned to the install's primary admin (the first house admin) instead, so it always lands with a named owner rather than unassigned.

## Reassigning and removing a managing admin

To hand a client to a different team member — or to record a managing admin on an unmanaged account, or repair one whose admin was removed — use `account_reassign_admin` with the client's `accountId` and the new admin's `userId`. It refuses a target that is not a client sub-account or a `userId` that is not a current house admin. Removing a house admin is guarded so it cannot silently orphan anyone: `admin-remove` refuses to remove an admin who is still the managing admin of one or more client sub-accounts and names those accounts. Reassign each with `account_reassign_admin`, then remove the admin.

## Memory (graph)

The `memory` plugin gives the admin session access to a sub-account's knowledge graph. Its tools whose read or write is scoped solely by the account — search, lookup, write, update, edit, delete, edges, attachments, reports, conversation history, ingest, and graph maintenance — take an optional target. Omit it and the tool acts on the session's own account, exactly as before; pass a sub-account and a house-scoped admin session reads or writes that account's subgraph instead; any other session that names a target is refused.

`profile-read`/`update`/`delete` also take a target. They are keyed to a user as well as the account, so cross-account they cannot use the caller's own user (a house operator has no record inside a sub-account); instead they resolve the sub-account's owner — the single admin identity seeded with every account — and act on that owner's profile. A house-scoped session can therefore read or set a sub-account's profile (its owner's name, role, timezone, locale, and preferences); a target with no owner is refused rather than writing a stray record. Setting a sub-account owner's email or telephone this way is not available yet.

A few memory tools do **not** take a target. `session-compact` acts on the caller's own live session, which belongs to the account the operator is in, so pointing it at a sub-account has no meaning. `graph-prune-denylist-*` and `memory-ingest-extract` are not account-scoped at all (a shared deny-list and a temporary staging step), so a target would mean nothing. These stay on the session's own account.

## Filesystem

The `filesystem` plugin gives the admin session direct access to the account working directory (`data/accounts/<id>/`) — `SOUL.md`, generated documents, screenshots, arbitrary files. It exists because the native file tools (Read, Write, Edit, and the shell) are locked to the session's own account and cannot take a target. Its six tools are `file-read`, `file-write`, `file-edit`, `file-list`, `file-glob`, and `file-grep`.

Omit the target and each tool acts on the session's own account, exactly like the native tools. Pass a sub-account as the target and a house-scoped admin session reads or writes that account's files instead; any other session that names a target is refused. Every path is confined to the resolved account directory — a path that climbs out with `../`, an absolute path outside the account root, or a symlink pointing away is rejected before anything is read or written, so the tools can never reach another account or the platform's own files.

## Signals

A standing background check reconciles live sessions against the account roles and raises an alarm if any session still holds house authority for an account that is no longer the house account, so a stale grant cannot sit unnoticed. Each cross-account tool call also records its decision — who called, which account it targeted, whether it was allowed, and why — before it touches the graph or disk, and a rejected filesystem path escape is recorded on its own line. In normal operation neither an allowed cross-account call from a non-house session nor a path escape ever appears.
