canopy-api defines the shared canopy.v1 Protobuf/gRPC surface between PandaEngine and Canopy. Treating the contract as its own project makes service semantics, generated interfaces and compatibility deliberate engineering concerns.
The contract is a project
A request field, pagination rule, identity requirement or status code is part of the shared behavior. Keeping these decisions outside either implementation makes the seam visible and lets client and server changes be reviewed against the same contract.
Service surface
| Service | Contract responsibility |
|---|---|
CatalogService | Hierarchical browse and search |
PlaybackService | Authorized playback-source resolution |
DiscoveryService | Discovery, For You and recommendation feeds |
AuthService | Accounts, verification, credentials and sessions |
ProfileService | Profile-owned preferences and state |
HistoryService | Playback history |
LibraryService | Saved library relationships |
PlaylistService | Playlists and their items |
SystemService | Health and version information |
Player commands and queue policy remain client-domain concerns in PandaEngine. This service matrix describes the wire-level responsibilities, not private message definitions.
Why a separate repository
The Android/Rust client and the backend should be able to evolve independently without carrying separate copies of the API definition. A dedicated contract project provides one place for service semantics, package/version boundaries and generated SDK distribution.
The public Canopy architecture and PandaEngine host contract show how both sides consume that shared surface.
Compatibility is a design concern
Lint and build
Buf validates the schema surface before it becomes a generated interface consumed by another repository.
Breaking-change checks
Compatibility checks compare contract changes against a baseline, making wire-breaking changes visible during review.
Generated SDK distribution
Generated packages carry the canonical types into client and server builds, reducing handwritten contract duplication.
Immutable version pinning
A label that can move
A consumer follows whatever a branch or mutable reference points to. Rebuilding later may select a different schema revision.
A known contract revision
Client and server consume a specific generated SDK revision. Changes become explicit upgrades that can be reviewed, tested and reproduced.
- Contract change Review semantics
- Compatibility gate Lint + build + breaking
- Immutable SDK revision Known generated artifact
- Consumer upgrade Test both sides
Fail-closed identity semantics
Optional authentication is not permission to ignore invalid authentication.
A request without identity may be allowed on an anonymous surface. A request that supplies invalid identity must fail rather than quietly downgrade. That distinction belongs in the shared semantics so every adapter preserves it.
| Request context | Expected interpretation |
|---|---|
| No identity on an anonymous-capable operation | Apply anonymous policy |
| Valid identity | Apply authenticated policy |
| Supplied invalid, expired or revoked identity | Reject; do not retry anonymously |
This behavior is described in the public Canopy playback contract. No tokens, private proto contents or internal credentials are included in this case study.
What this demonstrates
The interesting part of an API is the agreement it preserves: ownership, failure semantics, compatibility and a repeatable way for independently built components to speak the same language. PandaWave and Canopy show the two sides of that agreement.