Summary
Send a product identity header (x-sdk-name) on every backend call, defaulting to openhuman and overridable by downstream products that embed this core. This is what lets the backend tell an OpenHuman user apart from an OpenCompany or Medulla user, and drives per-product roles in the TinyHumans Discord.
Problem
OpenHuman, OpenCompany and Medulla all share one login and all reach the backend through code in this repo. The backend therefore cannot attribute any request to a product — it sees three products as one undifferentiated user base.
The backend already parses an x-sdk-name header (src/utils/sdkSource.ts in tinyhumansai/backend) and tinyhumans-sdk already exposes with_default_headers (vendor/tinyhumans-sdk/src/lib.rs:115), but nothing in this repo sets it. So the plumbing exists on both ends with a gap in the middle.
Two client paths here reach the backend and both need to carry the header:
src/api/rest.rs:407 — pub fn new(api_base: &str) builds TinyHumansClient::new(base).with_http_client(client). This is the chokepoint for core API traffic, and by extension for OpenCompany, which embeds openhuman_core.
src/openhuman/medulla/client/ — MedullaClient uses raw reqwest with an authed() helper (types/mod.rs, mod.rs:102) that attaches the Authorization header. Same place the product header belongs.
Constraint: downstream products must be able to override the value without forking this code, and the default must stay openhuman so existing behaviour is unchanged for anyone who does not opt in.
Solution
Introduce a single product-identity value in core — a small enum or newtype with an openhuman default — and apply it as a default header on both client paths. Expose a setter (builder method or config field) that OpenCompany and Medulla can call to override it.
Keeping this in core rather than duplicating it per product means one definition of the header name and one place to change if the backend contract moves.
Acceptance criteria
Related
Part of per-product Discord roles across TinyHumans:
- tinyhumansai/backend#1214 — records attribution and syncs Discord roles (parent issue)
- tinyhumansai/medulla — sets the
medulla identity
- tinyhumansai/opencompany — sets the
opencompany identity
Summary
Send a product identity header (
x-sdk-name) on every backend call, defaulting toopenhumanand overridable by downstream products that embed this core. This is what lets the backend tell an OpenHuman user apart from an OpenCompany or Medulla user, and drives per-product roles in the TinyHumans Discord.Problem
OpenHuman, OpenCompany and Medulla all share one login and all reach the backend through code in this repo. The backend therefore cannot attribute any request to a product — it sees three products as one undifferentiated user base.
The backend already parses an
x-sdk-nameheader (src/utils/sdkSource.tsin tinyhumansai/backend) andtinyhumans-sdkalready exposeswith_default_headers(vendor/tinyhumans-sdk/src/lib.rs:115), but nothing in this repo sets it. So the plumbing exists on both ends with a gap in the middle.Two client paths here reach the backend and both need to carry the header:
src/api/rest.rs:407—pub fn new(api_base: &str)buildsTinyHumansClient::new(base).with_http_client(client). This is the chokepoint for core API traffic, and by extension for OpenCompany, which embedsopenhuman_core.src/openhuman/medulla/client/—MedullaClientuses rawreqwestwith anauthed()helper (types/mod.rs,mod.rs:102) that attaches theAuthorizationheader. Same place the product header belongs.Constraint: downstream products must be able to override the value without forking this code, and the default must stay
openhumanso existing behaviour is unchanged for anyone who does not opt in.Solution
Introduce a single product-identity value in core — a small enum or newtype with an
openhumandefault — and apply it as a default header on both client paths. Expose a setter (builder method or config field) that OpenCompany and Medulla can call to override it.Keeping this in core rather than duplicating it per product means one definition of the header name and one place to change if the backend contract moves.
Acceptance criteria
openhumanas its default, and a documented way for an embedding product to override it.src/api/rest.rssetsx-sdk-nameviawith_default_headersso everyTinyHumansClientcall carries it.MedullaClient'sauthed()helper attachesx-sdk-namealongsideAuthorization, so HTTP and SSE requests both carry it.openhuman, and no existing call site needs modification..github/workflows/ci-lite.yml).Related
Part of per-product Discord roles across TinyHumans:
medullaidentityopencompanyidentity