Lolly
Lancarkan Aplikasi

Choose a deployment

Lolly does its work on each person's device, so deploying it is mostly about how the app reaches people, not where renders run. This page helps an IT or platform team pick one of three ways, then points to the guide for each.

  • 1

    Hand out the app

    People install
    The desktop or mobile app, or the web app for offline use
    You run
    No server. Your device management delivers the app
    Works offline
    Yes Air-gapped too
  • 2

    Host the web app

    People install
    Nothing. They open a link
    You run
    Any static web server, or the container image and Helm chart
    Works offline
    Yes After Available offline
  • 3

    Add Lolly Work

    People install
    Nothing more. They sign in with the organisation
    You run
    The Lolly Work service, a database and blob storage
    Works offline
    Partly Local tools do; shared work needs the service

Three ways to deploy Lolly. All three use the same build, so teams can mix them.

signed by Lollydeployment-three-ways.htmlHTMLpixels, not shapes8 KBAI generatedgenerated by Claude Opus 5.5Semak sendiriDapatkan fail yang ditandatangani

Device management such as Intune, Jamf or Munki can deliver the apps, and IT then owns their update cadence. A hosted web app updates everyone as soon as you publish. Lolly Work adds single sign-on, shared projects, approvals and governed delivery on servers you run.

Pick per team, not per organisation; a hybrid of the first two, pointed at the same tool library, is common. Threat model and Server surface set out what each way runs and what it protects.

People who use the hosted web app need a browser with WebGPU. Check Supported environments before you roll it out.

Hand out the app

The desktop and mobile apps wrap the same engine and web code in a native binary. Build them with the guides for desktop, Android and iOS, which cover signing, notarisation and store steps, or take the published installers from Install Lolly. Distribute the binaries through your device management like any other managed app.

Host the web app

The web build is plain static files, which makes this the simplest and most portable path. Build it with the brand you mean to ship:

LOLLY_PROFILE=lolly-demo pnpm run build:web    # output: shells/web/dist/

Build Guide explains what build:web runs. Then serve shells/web/dist/ from any static host, CDN or internal file server, with three things in place: the routes, the headers and the brand. Without the optional services, those three are all the host needs.

Any static host, including air-gapped

Once loaded, the web app keeps working offline. Settings → Available offline turns that best-effort caching into a guarantee: people download the whole app, their tools, the catalogue (whole or by tag) and the docs ahead of a disconnection, with a progress bar and per-part sizes.

That makes this the air-gapped path too. Put the static bundle behind your firewall, or into an app your device management delivers, and nothing phones home. The build writes dist/precache.json, the app's own file list, and /info/manifest.json, the docs site's. The download manager reads both, so keep them in the deployed bundle.

The routes

One origin serves several kinds of address, and each kind needs its own handling.

One origin lolly.example.com

  • / /d /t/<id> and other app routes

    The app. A clean route gets its prerendered page; anything else falls back to index.html.

    web server

  • /info/… /tools/… /catalog/…

    Real files. A missing file answers 404, never the app.

    web server

  • /any-site/

    The app under a second policy whose frame-src admits any secure web page.

    web server

  • /api/mcp /tool/<id>.<ext> /.well-known/oauth-*

    AI agents, public renders and the image pass-through behind Add from URL.

    MCP service

  • /api/ca

    Signing certificates for verified Content Credentials.

    CA service

  • /api/penpot

    Send to Penpot.

    Penpot pass-through

Shaded rows are the optional services. Route them first, and keep the app fallback last so it cannot swallow them.

How one origin answers each kind of address. Real files 404 when missing; only app routes fall back to the app.

signed by Lollydeployment-route-map.htmlHTMLpixels, not shapes9 KBAI generatedgenerated by Claude Opus 5.5Semak sendiriDapatkan fail yang ditandatangani

The headers you must serve

A static host sends only the headers you configure, so these six are yours to add. Every reference deployment in the repository sends them on every response, and a proxy that terminates TLS and drops them loses their protection:

The two Cross-Origin-* headers keep the app cross-origin isolated. Browsers give shared memory (SharedArrayBuffer) only to an isolated page, and some of the app's on-device models use that memory to run WebAssembly on several threads. The app still loads without the pair, so check for both headers explicitly.

The CSP matters most, and not for the reason you might expect. Tool hooks run through new Function by design, so script-src keeps 'unsafe-eval'; removing it would break shipping tools, and that is a documented, accepted residual. The directive doing the work is connect-src: script that can run still cannot send data to a host outside a fixed allowlist. tests/security-headers.test.ts pins the policy across every shipped copy of the configuration and fails the build if they drift. Threat model sets out what the policy does and does not contain.

deploy/docker/security-headers.conf is the copyable form: six add_header … always lines plus an include of the cache headers in deploy/docker/delivery-headers.conf, ready to translate into whatever your host uses. With nginx, take the whole file rather than retyping the lines. nginx drops all inherited add_header directives inside any location that declares one of its own, so a location that sets Cache-Control ships with no security headers unless it includes them again.

One path gets a second policy. /any-site/ serves the app under the same policy with one change: frame-src admits any https: page and the loopback. A person's Allow pages from any site setting (Settings, Trusted sites) reloads the app at that path, so Design can show pages beyond the few video and map players the base policy allows. The reference nginx configurations express this as a second entry in the $lolly_csp map keyed on $request_uri; the YunoHost package uses conf/any-site-headers.inc with its own location.

Serve the pair together. To withdraw the option, give /any-site/ the base policy: the app reads the policy that path really carries and offers the setting only where frame-src admits https:. Never leave /any-site/ with no policy at all, because a path with no Content-Security-Policy restricts nothing and the app treats the option as offered.

To let the app reach your own storage, such as SharePoint or S3, add those origins to the policy with Configure connector origins.

Which brand ships

Set LOLLY_PROFILE=<name> on the build so the deployment carries the brand you mean, not whichever profile the resolver would pick; a private pack that is not in the clone can never ship. pnpm run build:web writes a real tools/ and catalog/ tree into dist/ from that profile, so the deployed site serves both as plain files and nothing resolves a profile to answer a request.

A service that does read tool source at request time, such as the MCP service's /tool/<id>.<ext> render route, needs the packs in its image and the same LOLLY_PROFILE in its runtime environment, not only at build time. Profiles, brands and tool configuration covers the resolver, and how to change or remove a design system the deployment supplies (see Removing a catalogue design system).

Run it on Kubernetes

The repository ships signed container images and a Helm chart, so running Lolly on your own cluster is a supported way to host the web app, not a recipe to rebuild. A minimal install pins the published web image by digest:

helm install lolly deploy/helm --set web.image.digest=sha256:<digest>

Run on Kubernetes covers the published images, the chart's secure defaults, the optional MCP and CA components, small-cluster and single-node profiles and building your own image.

Add the optional services

None of these is needed for an ordinary local render or download. Server surface is the complete inventory, network pass-throughs included.

ServiceWhat it powersHow to run it
MCP server (services/mcp)The AI-agent endpoint, which lets a model find and run tools over MCP, plus the public render route and the image pass-through behind Add from URLThe published lolly-mcp image (or lolly-mcp-browser for browser formats), or services/mcp as a Node process
CA service (services/ca)Content Credentials identity: short-lived signing certificates for verified C2PAThe published lolly-ca image, or services/ca as a Node process with services/ca/.env
Penpot pass-through (services/penpot)Send to Penpot, which forwards two Penpot API calls the browser cannot make itselfThe published lolly-penpot image, or services/penpot as a Node process

Route the app's /api/mcp, /api/ca and /api/penpot paths to them. MCP also answers the two /.well-known/oauth-* discovery paths, /api/fetch-image and the public GET /tool/<id>.<ext> render route, so route those to the same service. Keep the app's catch-all for everything else, written to exclude the API prefix and listed last so it cannot swallow the service routes. deploy/docker/public.caddy routes all of these and is a working example.

The CA holds policy on the server (certificate-day limits, allowed providers) and never sees a signing key; keys are made and kept on each person's device. Content Credentials identity covers running the CA, and MCP server covers the endpoint and its access rules.

Organisation services with Lolly Work

Choose Lolly Work when a deployment needs organisation single sign-on, SCIM provisioning, access policies, a shared catalog and projects, work collabs, approvals or governed delivery. It is part of the Lolly project, in a separate repository, with its own service and admin console. It serves the same web app and works with connected desktop and mobile apps, and local rendering stays available. It needs a persistent database and blob storage for shared work; its server renders and batches use the same engine, and browser formats need its optional render worker. The Helm chart in this repository does not install Lolly Work.

Review current status and production evidence against the release you deploy. The public demo at lolly.work keeps everything in memory; it is a sandbox to try, not a persistent organisation deployment. A static Lolly image has no organisation identity service of its own, and the standalone MCP service's shared-secret OAuth adapter does not give per-person Lolly Work sign-in.

For the people you serve, link to Use Lolly at your organisation. For what changes in data handling, read Server surface and Privacy.

YunoHost

For a home or team server, install Lolly Work for YunoHost. It includes this same web app plus the Lolly Work server, PostgreSQL, shared projects, permissions and sign-in with your YunoHost accounts. Start with Install Lolly Work, and use the exact package revision and qualification results linked from the Lolly Work release.

PackageChoose it when
Lolly Work (lolly-work_ynh)You want server features, sign-in with host accounts and shared projects. Recommended for most self-hosters.
Static Lolly (lolly_ynh)You only want to serve the app; people work on their own devices with no Lolly Work service or database.

The static package lives in this repository at deploy/yunohost/ and is mirrored to lolly-tools/lolly_ynh. It downloads a prebuilt web archive, serves it through nginx and uses the normal YunoHost app permission. It is public by default and takes a whole domain, and on-device models load from lolli.li when first used. Install it only if that static setup is what you need:

sudo yunohost app install https://github.com/lolly-tools/lolly_ynh

The two are separate apps, not upgrade targets for each other. To move from static Lolly to Lolly Work, install Lolly Work on another domain and check sign-in and project transfer before you retire the static app. Do not upgrade lolly_ynh in place with a lolly-work_ynh package address.

Ship new tools without redeploying

Tools are data, not code: a manifest, a template and optional hooks in a directory. Shipping a tool never redeploys the app. Merge it into the directory your instance reads, rebuild the catalog with the :all commands in Publish and localize a tool, and clients pick it up on their next sync.

Most people never need that step: they save their work as a session and share it as a link, a backup or a collab. Which tools an instance exposes is configuration, and how a team decides what becomes a shared template is in Adoption and governance.

Section links from the earlier guide