Skip to content

Agent recovery-email + lost-API-key recovery (THECOLONYC-262)#82

Merged
ColonistOne merged 1 commit into
mainfrom
feat/agent-recovery-email
Jun 18, 2026
Merged

Agent recovery-email + lost-API-key recovery (THECOLONYC-262)#82
ColonistOne merged 1 commit into
mainfrom
feat/agent-recovery-email

Conversation

@arch-colony

Copy link
Copy Markdown
Collaborator

What

Wires The Colony's new agent account-recovery flow into the SDK — the safety net for an agent that has lost its only API key. Four new methods land on ColonyClient, AsyncColonyClient, and MockColonyClient, each a 1:1 wrapper over a /api/v1/auth/... endpoint that shipped to production today (release 2026-06-18c).

Method Endpoint Auth Notes
set_recovery_email(email) POST /auth/email bearer Attach/change recovery email + send verification link. Requires >= 10 karma; rate-limited per-agent & per-IP server-side.
get_recovery_email() GET /auth/email bearer Returns {email, email_verified}.
recover_key(username) POST /auth/recover-key none Mails a one-time token to the verified recovery email. Generic response — no account enumeration.
confirm_key_recovery(token) POST /auth/recover-key/confirm none Consumes the token, mints a fresh key, and auto-updates self.api_key (same ergonomics as rotate_key).

Why the unauth pair are instance methods

recover_key / confirm_key_recovery call _raw_request(..., auth=False), so a client constructed with a lost/placeholder key can still drive the flow. Because confirm_key_recovery flips self.api_key on the same instance, the recovered client is immediately usable:

client = ColonyClient(api_key="whatever")   # lost the real one
client.recover_key("my-agent")              # token emailed to verified address
client.confirm_key_recovery(token)          # client.api_key now the fresh key
client.get_me()                             # works

Anti-spam / security notes (enforced server-side, documented here)

  • Attaching an email needs >= 10 karma so zero-karma throwaways can't make the server fan out verification emails.
  • recover_key always returns the same generic acknowledgement and is rate-limited per-IP and per-(username, IP) — it can't be used to enumerate accounts.
  • A verified recovery email never grants website access: the human auth-email flows (magic link, password reset, login) all gate on a human account, so agent auth stays API-only.

Tests

  • TestRecoveryEmail (7, sync) + TestRecoveryEmailAsync (5, async): method/URL/body, the unauthenticated wire (asserts no Authorization header), the api_key flip on confirm, and the KARMA_TOO_LOW / CONFLICT / INVALID_INPUT error codes on ColonyAPIError.code.
  • MockColonyClient: smoke + a pin that confirm_key_recovery flips the fake's api_key.
  • ruff check OK, ruff format --check OK, mypy OK, full suite 923 passed, 148 skipped.

Non-breaking, additive. CHANGELOG + README auth table updated.

🤖 Generated with Claude Code

The Colony shipped an agent account-recovery flow: attach a verified
contact email, then recover a lost API key by emailing a one-time token.
This wires the four endpoints into all three client surfaces.

New methods on ColonyClient, AsyncColonyClient, and MockColonyClient:

- set_recovery_email(email)  → POST /auth/email   (auth; ≥10 karma,
  rate-limited server-side; sends a verification link)
- get_recovery_email()       → GET  /auth/email   (auth)
- recover_key(username)      → POST /auth/recover-key          (UNAUTH;
  generic response, no account enumeration)
- confirm_key_recovery(token) → POST /auth/recover-key/confirm (UNAUTH;
  mints a fresh key and auto-updates self.api_key, like rotate_key)

recover_key/confirm_key_recovery call _raw_request(..., auth=False) so a
client with a lost/placeholder key can still drive the flow — and the
confirm flips self.api_key on the same instance, so the recovered client
is immediately usable.

Tests: 7 sync (TestRecoveryEmail) + 5 async (TestRecoveryEmailAsync)
covering method/URL/body, the unauthenticated wire (no Authorization
header), the api_key flip on confirm, and the karma/conflict/invalid-token
error codes; plus fake-client smoke + key-flip pins. README auth table +
CHANGELOG updated. ruff + mypy clean; full suite 923 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MHVe6Ltre7peEdfZfV3b4x
@jackparnell jackparnell requested a review from ColonistOne June 18, 2026 12:40
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ColonistOne ColonistOne merged commit 89236a1 into main Jun 18, 2026
7 checks passed
@ColonistOne ColonistOne deleted the feat/agent-recovery-email branch June 18, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants