Public: anyone can read this; the crew can change it.

An organization always keeps a person who owns it: no agent owns one, and the last person is not removed, nor their account #862

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

Closes #722. **`removeTeamMember` now returns an error (`last_owner`) instead of `removed: false`.**

shipped production is serving it for issue #722 — its issue is already done deploy d5b2fe2

opened this

Closes #722. removeTeamMember now returns an error (last_owner) instead of removed: false.

What changed

  • No agent owns an organization (CLAUDE.md invariant 10). Adding an agent to Owners, or to any team with admin permission, is refused with agent_cannot_own. That covers the action, the API (422), the team page, and the core function as a backstop. An agent also cannot found an organization, because its founder becomes its owner.
  • The last person stays. Protecting the last owner now counts only people: not agents, not removed accounts (personOwners). Removing the last person who owns the organization answers last_owner on the team page (an explicit message), the API (409 with the reason) and in the action. Taking an agent off Owners is always allowed.
  • Account removal: removeAccount is refused with last_owner before anything changes if the account is the only person owning any organization. The API names those organizations in its message. The accounts page shows "only owner of …" on that account's row and explains the refusal. A successor is two steps: make someone else an owner, then remove the account.
  • Migration 61 takes every agent off every admin team and records each removal on the outbox as team.member_removed with its reason. Each event gets a ULID made in SQL, so it sorts after every event before it. The migration can be run again without effect.
  • MCP: there are no team or account tools there, so it has no route to change.
  • Removing the organization along with its repositories is a destructive flow, filed as #859 under #586.

Tests (test/org-owners.test.ts, in the gate; the refusing tests were written first and failed before the change):

  • An agent is refused on Owners and on another admin team, through the action and the API. An agent cannot found an organization.
  • An agent seeded into Owners does not count: the last person cannot be removed, through the action or the API, and stays.
  • Removing the sole person owner's account is refused and changes nothing: not removed, not suspended. The API answer names the organization.
  • The accounts page names the organization.
  • With a second person owning it, the first can be removed.
  • The migration takes a seeded agent off Owners, records one event whose id sorts last, and does nothing more on a second run.

🤖 Generated with Claude Code

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs