Two bugs found during manual testing:
- `AuthsomeError.__str__` already prepends the class name, but
`app.py` was passing `str(exc)` as the `message` field in error
responses. The client then reconstructed the exception with that
string as its args[0], causing `str()` to prepend the class name a
second time (e.g. "ProviderNotFoundError: ProviderNotFoundError: …").
Fixed by using `Exception.__str__(exc)` so the server sends the raw
message without the class-name prefix.
- `daemon stop` returned a no-op message when no PID file existed,
leaving an orphaned daemon (e.g. after `rm -rf ~/.authsome`) running
on port 7998. Added `_find_pid_by_port` as a fallback: if there is
no PID record but a process is listening on the daemon port, it is
terminated through the normal SIGTERM→SIGKILL path.
Also updates the manual-testing guide to reflect the secure local
browser bridge used by all login flows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 37d02f2f4c99
Phases A–I of TODOS.md:
- Move all five registry classes (IdentityRegistry, PrincipalRegistry,
VaultRegistry, IdentityClaimRegistry, PrincipalVaultBindingRegistry) from
identity/ to server/registries.py. Domain model types stay in identity/.
- Break identity/local.py → cli/ coupling: inline _read/_write_active_identity_handle
helpers so identity/ imports nothing from cli/.
- Remove VaultRegistry + get_server_home imports from auth/service.py; refactor
revoke() to accept explicit vault_ids from the server layer.
- Move proxy_routes() and _build_route_entry() out of AuthService into
server/proxy_catalog.py; proxy route delegates to build_proxy_routes().
- Move AuthService from auth/service.py to server/credential_service.py so
auth/ becomes a true leaf (no vault/, audit/, or server/ imports). Update
all 10+ import sites in server/, cli/ test files, and the top-level __init__.
- Remove global AuthService(identity="server") from app.py. Refactor /ready
to resolve the local identity at request time and use app.state.vault directly.
- Remove vault.home property from Vault; replace all callers with store.home.
- Update AGENTS.md architecture table to reflect new file locations.
All 293 tests pass. ruff and ty clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 5c8526a4e7d2
Replace authsome.actors with authsome.identity, splitting into four
focused sub-modules:
identity/local.py — IdentityMetadata, keys, DID helpers, create_identity
identity/proof.py — PoP JWT creation and validation
identity/registry.py — daemon IdentityRegistry (Handle → DID)
identity/principal.py — ClaimStatus, PrincipalRegistry, VaultRegistry,
IdentityClaimRegistry, PrincipalVaultBindingRegistry
Update all imports across src/ and tests/. Move tests/actors/test_registry.py
to tests/identity/test_registry.py. Delete the actors/ package.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 88222782ec3b
- Add ClaimStatus enum (PENDING/ACCEPTED/REJECTED) to IdentityClaimRecord
with accept_claim() and reject_claim() on IdentityClaimRegistry
- HostedOwnershipResolver.resolve() now gates vault access on ACCEPTED;
PENDING raises 403, REJECTED raises 403 with distinct message
- ensure_claimed_identity() auto-accepts on UI form submission — the form
IS the approval act in this release; PENDING is transit state only
- Remove AuthService vault_id fallback (vault_id or identity); _coll now
raises ValueError if vault_id is None, making missing wiring explicit
- /ready endpoint resolves vault_id via ownership_resolver instead of
constructing AuthService with the identity handle as a stopgap
- create_auth_service() requires explicit vault_id parameter
- Rewrite ADR 0003 and update UBIQUITOUS_LANGUAGE.md to reflect opaque
VaultId design (single segment, not principal_handle/vault_handle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 8f56337e3615
- Fix `health.py` import from non-existent `authsome.identity` to
`authsome.actors` where `current_from_home` is defined
- Add missing `ConnectionRecord`, `AuthType`, `ConnectionStatus` imports
in test_pop_auth.py
- Use `vault=` (not `identity=`) in `build_store_key` so the stored key
matches the `vault:` prefix that `list_connections` searches
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: f4892f79b920
Two classes of bugs corrected, both verified against main at 69a0cb9.
Skill (skills/authsome/references/adding-provider.md):
- OAuth redirect URL was http://localhost:7999/callback. Source truth
is http://127.0.0.1:7998/auth/callback/oauth (server/urls.py:8-9
and the matching user-facing doc in custom-providers.mdx). Agents
following the skill would tell users to register OAuth apps with
a redirect URI that does not match what authsome actually serves,
causing every PKCE login to fail.
- Step numbering had two "3." entries and no "4."; renumbered.
- Provider registration link pointed at the stale
raw.githubusercontent.com/manojbajaj95/authsome fork; repointed
to agentrhq.
Stale repo owner in actively-rendered surfaces:
- CONTRIBUTING.md: git clone URL.
- docs/site/README.md: link to the repo.
- docs/site/reference/bundled-providers.mdx: "open a pull request
against" link in the upstream contribution section.
- docs/site/concepts/credential-storage.mdx: replaced
"manojbajaj95" example label with "octocat" so the sample
connection record reads as a generic GitHub username.
- src/authsome/ui/templates/_layout.html: dashboard sidebar
"Support" link and topbar "GitHub" button.
- src/authsome/ui/templates/overview.html: dashboard "Contact Us"
button on the overview page.
Out of scope:
- pyproject.toml author attribution stays as Manoj Bajaj; that is
the actual maintainer's name, not a stale fork reference.
- CHANGELOG.md has ~100 manojbajaj95 commit URLs but release-please
regenerates it; manual edits would be overwritten on next release.
- doctor: fix spec_version always showing FAIL — server returned the version
number "3" instead of "ok", so the CLI check `val == "ok"` always failed
on healthy installs
- register --force: was not skipping the confirmation prompt; --force now
implies --yes so a single flag covers both server-side overwrite and client
prompt bypass (matching gh/fly/docker convention)
- --quiet: was silencing ALL output including primary data rows; add emit()
to ContextObj (never quiet-suppressed) and use it for list table rows and
doctor check lines — informational headers remain quiet-suppressible
- log: switch from raw loguru client log to structured server audit log
(NDJSON); display as human-readable table with timestamp/event/provider/
status columns; --raw flag retains access to the client debug log
- add CLI design review report at docs/internal/cli-design-review.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: e28262984429