# Branding (/docs/branding)



White-label primitives let a host override the brand string, log
prefixes, and error-message text the runtime emits. Output reads as
the host's product instead of as Pleach. The surface is opt-in; with
nothing configured, the runtime's output is byte-identical to running
without branding.

Two consumer types reach for this earliest. **Consultancies** ship the
same runtime to N tenants under N brands — agency-style hosts that
need each deployment to wear a different name. **ISVs** embed
`@pleach/core` inside a product where exposing the underlying runtime
would dilute their own brand. End-user-facing SaaS rarely needs it;
if your users never see a log line or an error string, there is
nothing to rename.

## The contract [#the-contract]

Four functions, all from the top-level `@pleach/core` export.

| Function                              | Role                                                                    |
| ------------------------------------- | ----------------------------------------------------------------------- |
| `configureBranding(config)`           | Installs an override. Every field is optional and defaults to identity. |
| `getBrandingConfig()`                 | Returns the active configuration with defaults filled in.               |
| `resolveLogPrefix(defaultPrefix)`     | The call-site hook log emitters route through.                          |
| `resolveErrorMessage(defaultMessage)` | The call-site hook `throw new Error(...)` sites route through.          |

`configureBranding({ brandName, logPrefix, errorMessage })` is the
whole installation surface. `logPrefix` and `errorMessage` are
transform functions — each receives the default and returns the
branded form, so you rename rather than hard-code.

```ts
import { configureBranding } from "@pleach/core"

configureBranding({
  brandName: "Acme",
  logPrefix: (defaultPrefix) => defaultPrefix.replace("Pleach", "Acme"),
  errorMessage: (defaultMessage) => `[Acme] ${defaultMessage}`,
})
```

## Adoption is incremental [#adoption-is-incremental]

`v0.x` ships the contract. You can call `configureBranding` today and
the resolvers honor it. What's still landing is the substrate
retrofit — replacing every hard-coded `[ToolNode]` / `[SessionRuntime]`
literal with a call through `resolveLogPrefix` — which arrives as part
of the broader logging-refactor track. The override surface widens
transparently as call sites adopt the resolvers; nothing you write
against the contract breaks when they do.

## Why it's multi-call, unlike `@pleach/observe.init` [#why-its-multi-call-unlike-pleachobserveinit]

`@pleach/observe.init` is single-init: it owns infrastructure state —
destinations, sampling decisions, async-local-storage scope — that
would race or leak across reconfigurations. Branding owns none of
that. It's a UX preference, so the constraint is looser.

`configureBranding` MAY be called multiple times. The last call wins,
and partial overrides do **not** merge with the prior config — each
call replaces the whole branding state. A multi-tenant process can
adjust branding at the boundary of a request handler without a process
teardown.

## The `@pleach/core/branding` subpath [#the-pleachcorebranding-subpath]

The same four functions are available at the `@pleach/core/branding`
subpath when you only want this slice in your bundle.

```ts
import { configureBranding } from "@pleach/core/branding"
```

## Where to go next [#where-to-go-next]

<Cards>
  <Card title="Runtime strategies" href="/docs/runtime-strategies" description="The companion config surface — typed host-supplied slots on SessionRuntimeConfig." />

  <Card title="@pleach/observe" href="/docs/observe" description="The single-init observability SDK branding contrasts with — and the destinations it owns." />
</Cards>
