Problem
POST /v2/projects/resolve accepts one opaque identifier string and resolves it by trying external ID, permalink, and case-insensitive name. If that misses, it parses an MCP-suggested workspace/project value and retries the project segment.
That compatibility contract makes identifier meaning implicit. Cloud authorization and API-key scope enforcement must mirror the same lookup order before forwarding the request, and UUID-shaped names cannot be understood from string syntax alone.
The route is retained for now because MCP callers begin with human project references and existing disambiguation hints tell models to retry with workspace/project. This compatibility behavior is explicit and temporary; it should not spread to path authorization.
The Core app also registers the v2 project router under the obsolete /proxy/projects prefix, producing duplicate /proxy/projects/projects/... routes. A read-only Logfire audit found zero uses of that alias across four consecutive 14-day windows ending 2026-08-16. Cloud #1763 denies the alias at its gateway edge while its pinned Core revision still contains it.
Desired design
- Introduce an explicit project lookup contract, either separate routes or a closed request shape such as
{ "kind": "name" | "permalink" | "external_id", "value": "..." }.
- Keep workspace selection in the workspace routing context instead of encoding it into a project identifier string.
- Migrate MCP project resolution and Cloud authorization/API-key scope callers to the explicit contract.
- Instrument remaining use of the polymorphic compatibility route.
- Deprecate and remove the external-ID → permalink → name lookup chain and
workspace/project retry.
- Delete the unused
/proxy/projects/projects/... router alias; /v2/projects/... is the only project path contract.
Acceptance criteria
- UUID-shaped project names are resolved as names without probing external IDs.
- External-ID lookups perform one exact external-ID lookup and never retry as another identifier kind.
- Workspace-qualified input is represented by separate workspace and project fields.
- The legacy polymorphic route and Cloud's mirrored resolver can be deleted after callers migrate.
- The duplicate
/proxy/projects/projects/... route registration is removed.
Related Cloud cleanup: https://github.com/basicmachines-co/basic-memory-cloud/issues/1761
Related PR: https://github.com/basicmachines-co/basic-memory-cloud/pull/1763
Problem
POST /v2/projects/resolveaccepts one opaqueidentifierstring and resolves it by trying external ID, permalink, and case-insensitive name. If that misses, it parses an MCP-suggestedworkspace/projectvalue and retries the project segment.That compatibility contract makes identifier meaning implicit. Cloud authorization and API-key scope enforcement must mirror the same lookup order before forwarding the request, and UUID-shaped names cannot be understood from string syntax alone.
The route is retained for now because MCP callers begin with human project references and existing disambiguation hints tell models to retry with
workspace/project. This compatibility behavior is explicit and temporary; it should not spread to path authorization.The Core app also registers the v2 project router under the obsolete
/proxy/projectsprefix, producing duplicate/proxy/projects/projects/...routes. A read-only Logfire audit found zero uses of that alias across four consecutive 14-day windows ending 2026-08-16. Cloud #1763 denies the alias at its gateway edge while its pinned Core revision still contains it.Desired design
{ "kind": "name" | "permalink" | "external_id", "value": "..." }.workspace/projectretry./proxy/projects/projects/...router alias;/v2/projects/...is the only project path contract.Acceptance criteria
/proxy/projects/projects/...route registration is removed.Related Cloud cleanup: https://github.com/basicmachines-co/basic-memory-cloud/issues/1761
Related PR: https://github.com/basicmachines-co/basic-memory-cloud/pull/1763