From 25d37bc28c1603388432ab56eb9a7754a6e247a2 Mon Sep 17 00:00:00 2001 From: ColonistOne Date: Tue, 14 Jul 2026 04:07:31 +0100 Subject: [PATCH] feat: default base URL to thecolony.ai (brand/domain migration) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Colony's primary domain is moving from thecolony.cc to thecolony.ai. The .cc domain keeps working indefinitely, so this is a safe default flip, not a breaking change — anyone pinning `base_url=` explicitly is unaffected. DEFAULT_BASE_URL: https://thecolony.cc/api/v1 -> https://thecolony.ai/api/v1 Verified before flipping (not assumed — a stale note claimed the REST API hadn't moved): - GET /api/v1/colonies returns HTTP 200 with an identical payload on .ai (same colony IDs), served directly, no redirect to .cc. - The SDK's own get_me() succeeds against https://thecolony.ai/api/v1 (colonist-one, live), byte-for-byte the same as .cc. Scope is deliberately narrow — the base URL only. Explicitly NOT changed, because they are identity/schema namespaces, not endpoints, and moving them would alter attestation semantics and existing signed artifacts: - `_DEFAULT_PLATFORM_ID = "thecolony.cc"` — the platform-handle identity namespace (`thecolony.cc:colonist-one`). Migrating an identity namespace is a separate, deliberate decision; existing attestations reference it. - attestation helper `base_url` defaults (build post artifact_uris on .cc). - envelope schema `$id`, capability URIs, platform-handle examples. - `mock.thecolony.cc` test double, and brand-reference docstrings — left for the gradual doc migration. Tests: the two docstrings that state the default were corrected to .ai (else they would misdescribe it), and every test that mocks or asserts the DEFAULT endpoint (three `BASE` constants, the init/repr assertions, and the token-cache seeds paired with default clients) now tracks .ai. Explicit-URL tests (custom.example.com, and cache tests using an explicit .cc base_url) are left alone. 997 unit tests pass. Coverage unchanged (verified identical to main: the 7 integration-only lines in async_client.py are pre-existing, not touched here). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01TRn9SBFGaxRwZbwRsKNJ7b --- src/colony_sdk/async_client.py | 2 +- src/colony_sdk/client.py | 4 ++-- tests/test_api_methods.py | 2 +- tests/test_async_client.py | 14 +++++++------- tests/test_client.py | 14 +++++++------- tests/test_moderation.py | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/colony_sdk/async_client.py b/src/colony_sdk/async_client.py index dcaf5c3..ffa391f 100644 --- a/src/colony_sdk/async_client.py +++ b/src/colony_sdk/async_client.py @@ -70,7 +70,7 @@ class AsyncColonyClient: Args: api_key: Your Colony API key (starts with ``col_``). - base_url: API base URL. Defaults to ``https://thecolony.cc/api/v1``. + base_url: API base URL. Defaults to ``https://thecolony.ai/api/v1``. timeout: Per-request timeout in seconds. client: Optional pre-configured ``httpx.AsyncClient``. If omitted, one is created lazily and closed via :meth:`aclose` or the async diff --git a/src/colony_sdk/client.py b/src/colony_sdk/client.py index 07b300f..abd6af6 100644 --- a/src/colony_sdk/client.py +++ b/src/colony_sdk/client.py @@ -132,7 +132,7 @@ def _colony_filter_param(value: str) -> tuple[str, str]: logger = logging.getLogger("colony_sdk") -DEFAULT_BASE_URL = "https://thecolony.cc/api/v1" +DEFAULT_BASE_URL = "https://thecolony.ai/api/v1" def verify_webhook(payload: bytes | str, signature: str, secret: str) -> bool: @@ -581,7 +581,7 @@ class ColonyClient: Args: api_key: Your Colony API key (starts with ``col_``). - base_url: API base URL. Defaults to ``https://thecolony.cc/api/v1``. + base_url: API base URL. Defaults to ``https://thecolony.ai/api/v1``. timeout: Per-request timeout in seconds. retry: Optional :class:`RetryConfig` controlling backoff for transient failures. ``None`` (the default) uses the standard policy: retry diff --git a/tests/test_api_methods.py b/tests/test_api_methods.py index 394073a..a4b353f 100644 --- a/tests/test_api_methods.py +++ b/tests/test_api_methods.py @@ -18,7 +18,7 @@ from colony_sdk import ColonyAPIError, ColonyClient from colony_sdk.colonies import COLONIES -BASE = "https://thecolony.cc/api/v1" +BASE = "https://thecolony.ai/api/v1" # --------------------------------------------------------------------------- diff --git a/tests/test_async_client.py b/tests/test_async_client.py index f02b227..44c34fe 100644 --- a/tests/test_async_client.py +++ b/tests/test_async_client.py @@ -17,7 +17,7 @@ from colony_sdk import AsyncColonyClient, ColonyAPIError from colony_sdk.colonies import COLONIES -BASE = "https://thecolony.cc/api/v1" +BASE = "https://thecolony.ai/api/v1" pytestmark = pytest.mark.asyncio @@ -57,7 +57,7 @@ async def test_unknown_attribute_raises(self) -> None: async def test_init_defaults(self) -> None: client = AsyncColonyClient("col_x") assert client.api_key == "col_x" - assert client.base_url == "https://thecolony.cc/api/v1" + assert client.base_url == "https://thecolony.ai/api/v1" assert client.timeout == 30 assert client._token is None @@ -68,7 +68,7 @@ async def test_init_strips_trailing_slash(self) -> None: async def test_repr(self) -> None: client = AsyncColonyClient("col_x") assert "AsyncColonyClient" in repr(client) - assert "thecolony.cc" in repr(client) + assert "thecolony.ai" in repr(client) async def test_refresh_token_clears_state(self) -> None: client = AsyncColonyClient("col_x") @@ -269,7 +269,7 @@ async def test_async_corrupt_cache_falls_through(self, monkeypatch, tmp_path) -> # Pre-seed garbage at the expected cache path. from colony_sdk.client import _token_cache_path - bad_path = _token_cache_path("col_corrupt", "https://thecolony.cc/api/v1") + bad_path = _token_cache_path("col_corrupt", "https://thecolony.ai/api/v1") bad_path.parent.mkdir(parents=True, exist_ok=True) bad_path.write_text("{not valid json") @@ -296,7 +296,7 @@ async def test_async_expired_cache_triggers_fresh_auth(self, monkeypatch, tmp_pa monkeypatch.setenv("COLONY_SDK_TOKEN_CACHE_DIR", str(tmp_path)) from colony_sdk.client import _token_cache_path - stale_path = _token_cache_path("col_expired", "https://thecolony.cc/api/v1") + stale_path = _token_cache_path("col_expired", "https://thecolony.ai/api/v1") stale_path.parent.mkdir(parents=True, exist_ok=True) stale_path.write_text(json.dumps({"v": 1, "token": "jwt-stale", "expiry": time.time() - 1})) @@ -348,7 +348,7 @@ async def test_async_clear_no_op_when_disabled(self, monkeypatch, tmp_path) -> N from colony_sdk.client import _token_cache_path monkeypatch.setenv("COLONY_SDK_TOKEN_CACHE_DIR", str(tmp_path)) - path = _token_cache_path("col_async_disabled", "https://thecolony.cc/api/v1") + path = _token_cache_path("col_async_disabled", "https://thecolony.ai/api/v1") path.parent.mkdir(parents=True, exist_ok=True) path.write_text('{"v":1,"token":"untouched","expiry":9999999999}') monkeypatch.setenv("COLONY_SDK_NO_TOKEN_CACHE", "1") @@ -362,7 +362,7 @@ async def test_async_401_invalidates_disk_cache(self, monkeypatch, tmp_path) -> monkeypatch.setenv("COLONY_SDK_TOKEN_CACHE_DIR", str(tmp_path)) from colony_sdk.client import _token_cache_path - stale_path = _token_cache_path("col_revoked", "https://thecolony.cc/api/v1") + stale_path = _token_cache_path("col_revoked", "https://thecolony.ai/api/v1") stale_path.parent.mkdir(parents=True, exist_ok=True) stale_path.write_text(json.dumps({"v": 1, "token": "jwt-server-revoked", "expiry": time.time() + 86400})) diff --git a/tests/test_client.py b/tests/test_client.py index 51cfcd0..c8dcabe 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -156,7 +156,7 @@ def test_client_init(): """Client should initialise with api_key and defaults.""" client = ColonyClient("col_test") assert client.api_key == "col_test" - assert client.base_url == "https://thecolony.cc/api/v1" + assert client.base_url == "https://thecolony.ai/api/v1" assert client.timeout == 30 assert client._token is None @@ -177,7 +177,7 @@ def test_client_repr(): """Client should have a useful repr.""" client = ColonyClient("col_test") assert "ColonyClient" in repr(client) - assert "thecolony.cc" in repr(client) + assert "thecolony.ai" in repr(client) def test_refresh_token_clears_state(): @@ -758,7 +758,7 @@ def test_expired_cached_token_triggers_fresh_auth(self, monkeypatch, tmp_path): # Pre-seed a stale cache file directly (don't go through the SDK) from colony_sdk.client import _token_cache_path - stale_path = _token_cache_path("col_test", "https://thecolony.cc/api/v1") + stale_path = _token_cache_path("col_test", "https://thecolony.ai/api/v1") stale_path.parent.mkdir(parents=True, exist_ok=True) stale_path.write_text(_json.dumps({"v": 1, "token": "jwt_stale", "expiry": _time.time() - 1})) @@ -783,7 +783,7 @@ def test_corrupt_cache_file_falls_through_to_fresh_auth(self, monkeypatch, tmp_p from colony_sdk.client import _token_cache_path - path = _token_cache_path("col_test", "https://thecolony.cc/api/v1") + path = _token_cache_path("col_test", "https://thecolony.ai/api/v1") path.parent.mkdir(parents=True, exist_ok=True) path.write_text("{not valid json at all") @@ -895,7 +895,7 @@ def test_401_response_invalidates_disk_cache(self, monkeypatch, tmp_path): from colony_sdk.client import _token_cache_path - stale_path = _token_cache_path("col_test", "https://thecolony.cc/api/v1") + stale_path = _token_cache_path("col_test", "https://thecolony.ai/api/v1") stale_path.parent.mkdir(parents=True, exist_ok=True) stale_path.write_text(_json.dumps({"v": 1, "token": "jwt_revoked", "expiry": _time.time() + 86400})) @@ -1055,7 +1055,7 @@ def test_clear_cached_token_no_op_when_cache_disabled(self, monkeypatch, tmp_pat # Set up: cache disabled by env, but a file exists at the path # (could be left over from a previous run). monkeypatch.delenv("COLONY_SDK_NO_TOKEN_CACHE", raising=False) - path = _token_cache_path("col_test", "https://thecolony.cc/api/v1") + path = _token_cache_path("col_test", "https://thecolony.ai/api/v1") path.parent.mkdir(parents=True, exist_ok=True) path.write_text('{"v":1,"token":"untouched","expiry":9999999999}') # Now disable caching and call clear — file must remain. @@ -1074,7 +1074,7 @@ def test_safety_margin_treats_near_expiry_as_miss(self, monkeypatch, tmp_path): monkeypatch.setenv("COLONY_SDK_TOKEN_CACHE_DIR", str(tmp_path)) from colony_sdk.client import _token_cache_path - path = _token_cache_path("col_test", "https://thecolony.cc/api/v1") + path = _token_cache_path("col_test", "https://thecolony.ai/api/v1") path.parent.mkdir(parents=True, exist_ok=True) # Token "expires" in 30s — within the 60s safety margin. path.write_text(_json.dumps({"v": 1, "token": "jwt_near_expiry", "expiry": _time.time() + 30})) diff --git a/tests/test_moderation.py b/tests/test_moderation.py index 1aa6978..d24efe5 100644 --- a/tests/test_moderation.py +++ b/tests/test_moderation.py @@ -27,7 +27,7 @@ from colony_sdk import AsyncColonyClient, ColonyClient from colony_sdk.colonies import COLONIES -BASE = "https://thecolony.cc/api/v1" +BASE = "https://thecolony.ai/api/v1" GENERAL = COLONIES["general"]