Skip to main content
cycls.Web configures everything the user sees and the identity behind it. Pass it to @cycls.agent(web=...).
A Cycls agent empty state with brand name, description and composer

The empty-chat screen uses the brand name, description and logo.

Branding

name, description, logo and brand are per locale, so call .brand() again with "ar" for Arabic. Image paths are read at build time, SVGs inlined and rasters embedded as data URIs, so assets do not need to ship with the container.

Pulling copy from a CMS

These are plain GET URLs returning the contract JSON. Anything declared in code wins field by field, so a .brand() call overrides the CMS for exactly that field and no other.

Theme and colors

primary drives highlights and active states, secondary drives chips and bubbles. The _dark variants override dark mode and default to the light values.

The empty-chat screen

Prompt starters, off by default.

SEO and social

.seo() covers the page title and meta description when they should differ from the brand copy. .head() appends raw HTML to <head> and is repeatable. Every agent also serves /og.png, a generated social preview, plus /robots.txt, /sitemap.xml and /llms.txt.

Static files

Served at https://your-agent.cycls.ai/public/logo.png.

Uploads

Enforced server-side and pre-checked in the client so oversized files fail fast.

Analytics and push

.analytics(True) is shorthand for the PostHog default. Providers are plugins over one canonical event pipe, and each can be scoped with an events allowlist. .notifications() adds web push, where the permission card is ours and the trigger is a platform decision.

Reacting to finished runs

Called once when a run reaches any terminal status: done, stopped, interrupted or failed. Use it for push, email, a webhook or a row in a table. Exceptions are logged and never reach the run.

Method reference

Next

Authentication

Clerk, any OIDC provider, and what lands in context.user.