Problem or use case
A self-hosted Omnigent server is hardcoded to the "Omnigent" brand ~ the name in the sidebar, tab title, and login screen, and the Otto mascot throughout. Operators deploying it for their own org/company have no supported way to present their own name and logo, so the app always looks like "Omnigent" regardless of who's running it.
Why it matters
Personalization drives adoption. When teams, startups, and partners can put their own name and logo on the app, it stops feeling like a third-party tool and starts feeling like their product: which materially increases uptake:
- Internal deployments land better with end users when the app carries the company's own identity rather than an unfamiliar external brand.
- Resellers / partners / OEM scenarios are only viable if the product can be white-labeled ~ a hardcoded brand is a hard blocker to embedding Omnigent in someone else's offering.
- Trust & fit at the login screen: a branded sign-in page reassures users they're in the right, sanctioned place, reducing drop-off on first contact.
Low-effort branding is a small surface with outsized impact on whether a deployment gets rolled out org-wide versus quietly abandoned.
Proposed solution
Add an optional branding: block to the existing server config (config.yaml, read via omnigent server -c or <data_dir>/config.yaml). Non-secret, operator-editable, applied on server start.
branding:
app_name: "Acme Agent" # tab title, sidebar wordmark, login screen
heading: "How can I help?" # landing hero; "" hides it, omit for the default
logo: # a bare string sets `main`; or per-variant:
main: logo.svg # hero / primary mark
loading: loading.svg # working indicator (falls back to main)
favicon: favicon.svg # browser-tab icon
powered_by: true # "Powered by Omnigent" credit; false to hide
Behavior
- App name → browser-tab title, sidebar wordmark, login subtitle, "Back to …" nav.
- Heading → landing composer hero. An explicit empty string hides it; omitting the key keeps the default ("What should we do?").
- Logos → per-variant (main, loading, favicon), each resolved next to the config file (SVG or PNG). loading falls back to main; any unset variant keeps the Otto mascot / shipped favicon.
- Delivery → surfaced on the unauthenticated GET /v1/info probe plus a public GET /v1/branding/logo/{variant} route, so the login screen is branded before sign-in. The frontend reads it at boot and falls back to built-in defaults for anything unset.
- Powered by Omnigent → a subtle attribution under the landing composer, shown only when custom branding is set; powered_by: false hides it even then. Always renders the real Otto mascot, never the custom logo. (Keeps attribution to the project by default while still allowing full white-labeling.)
- Config plumbing → omnigent server -c points OMNIGENT_CONFIG at that file, so a single config drives branding alongside existing settings.
Out of scope (separate PR)
- Mobile / Desktop apps.
- Admin UI for editing branding (config-file only; restart to apply).
- PWA install-icon / apple-touch-icon and PWA manifest name (browser-tab favicon only).
Problem or use case
A self-hosted Omnigent server is hardcoded to the "Omnigent" brand ~ the name in the sidebar, tab title, and login screen, and the Otto mascot throughout. Operators deploying it for their own org/company have no supported way to present their own name and logo, so the app always looks like "Omnigent" regardless of who's running it.
Why it matters
Personalization drives adoption. When teams, startups, and partners can put their own name and logo on the app, it stops feeling like a third-party tool and starts feeling like their product: which materially increases uptake:
Low-effort branding is a small surface with outsized impact on whether a deployment gets rolled out org-wide versus quietly abandoned.
Proposed solution
Add an optional branding: block to the existing server config (config.yaml, read via omnigent server -c or <data_dir>/config.yaml). Non-secret, operator-editable, applied on server start.
Behavior
Out of scope (separate PR)