Skip to content

AI Application ​

First, let's understand the following concepts:

  1. lzc-cli is the scaffolding used to develop LazyCat LCMD applications. With lzc-cli, you can quickly package, install, debug, and release applications.
  2. The package generated by lzc-cli uses the lpk format, the application format of the LCMD ecosystem.
  3. The LazyCat AI Browser supports plugin installation for both PC and Android platforms.

AI 应用 refers to applications built on top of LCMD applications by importing an AIApp resource. These applications follow the same download and installation process as regular LCMD applications, with the following key differences:

  • Supports AI service integration: After installation, the app automatically deploys the matching device model's AI service onto the AI Pod.
  • Supports AI Browser plugin integration: After installation, the AI Browser automatically loads the corresponding plugin.
  • Supports defining AI Browser shortcuts and dependencies: Configuration for shortcuts, upstream services, and storage aliases is defined in the resource via config/aipod.yml.

Resource Import Declaration ​

LCMD applications import AIApp resources through lzc-manifest.yml, using its import_resources declaration:

yml
import_resources:
  - kind: aipod

After the platform installs an application, the AIApp resource is expanded to the following runtime directory:

text
/lzcapp/run/resources/aipod/<package-id>/

Among them, <package-id> is the application package ID. The platform reads the AI Pod configuration, service compose file, browser plugin, and fallback metadata from this directory.

Resource Directory Structure ​

The recommended AIApp resource directory structure is as follows:

text
aipod/
├── package.yml
├── lzc-manifest.yml
├── icon.png
├── config/
│   └── aipod.yml
├── agxorin/
│   └── docker-compose.yml
├── thor/
│   └── docker-compose.yml
└── extensions/
    ├── desktop.zip
    └── android.crx

Field Description:

  • config/aipod.yml: AI Pod configuration file, without outer aipod:.
  • agxorin/docker-compose.yml: Service definition for AGX Orin and default Jetson devices.
  • thor/docker-compose.yml: Service definition for Thor devices.
  • extensions/*.zip|*.crx: AI browser plugin file, supporting one or more.
  • package.yml, lzc-manifest.yml, icon.png: fallback sources for metadata and icons.

When compatible with old packages, the platform will still recognize the following legacy paths:

  • ai-pod-service/docker-compose.yml: legacy service definition. Used only as fallback when the compose file is missing under the device model directory.
  • browser-extensions/extension.zip: legacy browser plugin. Used only as fallback when the plugin under extensions/ is missing.

config/aipod.yml ​

config/aipod.yml contains only the AI Pod configuration itself, without an outer aipod:. For example:

yml
shortcut:
  disable: false
  title: ComfyUI
  url: /_lzc/aipod_backend/startup/gate/cloud.lazycat.aipod.comfyui?redirect=https%3A%2F%2Fcomfyui-ai
  favicon: /icon.png

locales:
  en:
    shortcut:
      title: ComfyUI

depends_on_others:
  - ollama-ai

depends_on_hosts:
  - comfyui-ai

storage_alias:
  models: /ssd/models

shortcut ​

AI applications installed in the LCMD are displayed by default in the AI Browser shortcut. This can be disabled via shortcut.disable, or the shortcut's title, entry URL, and icon can be overridden:

  • shortcut.disable: Whether to hide the shortcut, default is false.
  • shortcut.title: Shortcut title.
  • shortcut.url: Shortcut entry URL. It is recommended to use the platform startup gate for long initialization services.
  • shortcut.favicon: Shortcut icon URL.

locales ​

locales is used to configure multi-language metadata. The platform selects appropriate titles, descriptions, or shortcut fields based on the browser's language setting, falling back to default configurations if missing.

depends_on_others ​

depends_on_others declares the other AI hosts that the current AI application depends on. The platform considers these dependencies during entry and startup checks.

depends_on_hosts ​

depends_on_hosts declares the AI hosts that the current AI application itself needs to check. Typically, this is filled with the Host(...) value exposed via Traefik in the compose file. storage_alias

storage_alias Declare storage aliases used in the service to enable the platform to mount models, caches, or user data to stable paths.

Add AI Services ​

AI services are described via the docker-compose.yml in the resource. The platform selects the service directory based on device model:

  1. Thor devices prefer thor/docker-compose.yml.
  2. Other devices default to agxorin/docker-compose.yml.
  3. If the model-specific directory is missing, fallback to the legacy ai-pod-service/docker-compose.yml.

If agxorin, thor, and legacy services coexist, the AI host exposed to the AI browser must remain consistent across devices to prevent the same application from generating different access addresses on different devices.

Service Access Rules ​

Services within the AI Pod use traefik combined with Host forwarding rules. Compose files must include resolvable Traefik Host(...) labels and have host values ending with -ai.

yml
services:
  comfyui:
    image: registry.lazycat.cloud/demo/comfyui:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.${LZC_SERVICE_ID}-comfyui.rule=Host(`comfyui-ai`)"

networks:
  default:
    external: true
    name: traefik-shared-network

Rule Description:

  • The value in Host(...) is the AI host that the microservice and AI Browser use to access this service.
  • Only services joined in traefik-shared-network can be managed by Traefik.
  • The AI host must be exposed consistently across multiple device directories' compose files.
  • Long initialization services must configure healthcheck, using container health status to control the ready state. The platform's installation progress and startup loading will reuse this status.

For more usage of traefik, see Host Rule.

Info

The docker in the AI Pod defaults to nvidia-runtime. The container can directly use gpus without explicitly configuring gpus. For more details, click here.

Service Environment Variables ​

The following environment variables are provided by the AI Pod when the service runs:

  1. Data Persistence Path

    • Definition: /ssd/lzc-ai-agent/data/<service_id>
    • Environment Variable: LZC_AGENT_DATA_DIR
    • Example: /ssd/lzc-ai-agent/data/cloud.lazycat.aipod.ai
    yml
    services:
      ollama:
        volumes:
          - ${LZC_AGENT_DATA_DIR}/data:/root/.ollama
  2. Data Caching Path

    • Definition: /ssd/lzc-ai-agent/cache/<service_id>
    • Environment Variable: LZC_AGENT_CACHE_DIR
    • Example: /ssd/lzc-ai-agent/cache/cloud.lazycat.aipod.ai
    yml
    services:
      ollama:
        volumes:
          - ${LZC_AGENT_CACHE_DIR}/cache:/root/.cache
  3. Service ID

  • Definition: The value of <appId> minus .

  • Environment variable: LZC_SERVICE_ID

  • Example: cloudlazycataipodfishspeech

    yml
    services:
      ollama:
        labels:
          - "traefik.http.routers.${LZC_SERVICE_ID}-ollama.rule=Host(`ollama-ai`)"

Add AI Browser Plugin ​

The AI browser plugin is placed in the resource directory under extensions/, supporting zip and crx:

text
extensions/
├── desktop.zip
└── android.crx

zip For browser-compatible plugin formats. If the plugin is developed using wxt, it can be directly packaged as a zip file; alternatively, the plugin directory can be manually zipped.

When supporting legacy packages, the platform will still read browser-extensions/extension.zip as a fallback.

Metadata and Icon Fallback ​

The platform prioritizes reading config/aipod.yml from the resource. If missing metadata such as title, description, or icon is found, the following fallback order is applied:

  1. package.yml
  2. lzc-manifest.yml
  3. icon.png

If metadata is present in both the LCMD application manifest and the AIApp resource, the AI Browser displays the resource configuration.

Startup Entry and Loading ​

It is no longer recommended to include a built-in caddy within each AI application for health checks during long initialization of AI services. Instead, it is recommended to reuse the startup gate provided by the platform.

text
/_lzc/aipod_backend/startup/gate/:appid?redirect=<url>

Quick access to directly enter gate ​

If the application entry point is an AI host, you can directly access the gate via the shortcut:

yml
shortcut:
  title: ComfyUI
  url: /_lzc/aipod_backend/startup/gate/cloud.lazycat.aipod.comfyui?redirect=https%3A%2F%2Fcomfyui-ai

Rule Description:

  • :appid is the AI application package ID.
  • redirect is the target URL to redirect to after the service becomes ready, which must be URL encoded and is typically the AI host or microservice page address exposed by compose.
  • Static frontend can directly use the LCMD platform routing.
  • API or model service access routes through Traefik upstream.
  • Reuse platform capabilities for loading, health checks, and failure alerts; no need to implement these repeatedly for each application.

Static Frontend Integration with Startup Gate ​

If the AI application itself has an LCMD static frontend, follow the approach in cloud.lazycat.aipod.imgtrans: use lzc-manifest.yml and application.injects to intercept page requests. Users then enter the platform startup loading phase before any frontend page; once the service is ready, they return to the original page with deep links and query parameters preserved.

yml
application:
  subdomain: imgtrans
  injects:
    - id: aipod-startup-gate
      'on': request
      auth_required: false
      when:
        - /*
      unless:
        - /api/*
        - /debug/backend/*
        - /assets/*
        - /favicon.ico
        - /icon.png
        - /robots.txt
        - /manifest.json
        - /_lzc/*
      do:
        - src: >
            const appid = "cloud.lazycat.aipod.imgtrans";

            const cookieName = "aipod_startup_ready_" +
            appid.replace(/[^A-Za-z0-9]/g, "_");

            const cookies = String(ctx.headers.get("Cookie") || "");

            if (cookies.split(";").map((item) => item.trim()).some((item) =>
            item === cookieName + "=1")) {
              return;
            }

            const boxDomain = String(ctx.request.host || "").replace(/^[^.]+\./,
            "");

            const query = ctx.request.raw_query ? "?" + ctx.request.raw_query :
            "";

            const redirect = "https://" + ctx.request.host + ctx.request.path +
            query;

            const location = "https://" + boxDomain +
            "/_lzc/aipod_backend/startup/gate/" + encodeURIComponent(appid) +
            "?redirect=" + encodeURIComponent(redirect);

            ctx.response.send(307, "", { location });
  routes:
    - /=file:///lzcapp/pkg/content/dist
  upstreams:
    - location: /api/
      backend: http://backend:3000
      disable_trim_location: true
  public_path:
    - /debug/backend/
    - /api/

Key points of this example:

  • when: /* intercepts all page entry points, unless allows access to APIs, debugging interfaces, static resources, icons, and /_lzc/* internal platform paths, to prevent resource requests and the gate itself from being repeatedly redirected.
  • appid must be filled with the current AI application package ID; the startup gate will use it to query the installation and service ready status.
  • After the gate becomes ready, it writes a value to the aipod_startup_ready_<appid> cookie. The inject module first checks this cookie; if ready, it directly allows the request, avoiding the loading state on every page open.
  • boxDomain derives the host by removing the first subdomain segment from the current host, e.g., from imgtrans.13gxg.heiyu.space to obtain 13gxg.heiyu.space.
  • redirect preserves the user's original access address and query parameters, and passes them to the gate via encodeURIComponent. After the service becomes ready, the platform redirects back to this original address.
  • Static frontend files continue to be exposed via routes, while application-specific APIs are forwarded via upstreams. The startup gate only handles ready/loading states and does not replace business routing.

In the AIApp resource, dependencies can be declared, and the platform will include these dependencies in the ready check:

yml
shortcut:
  disable: false
depends_on_others:
  - trans
  - ocr

Access a Service on a Specific AI Pod ​

When there are multiple AI Pods, access can be achieved via f-{算力舱的序列号}-{服务名称}-ai.{微服名称}.heiyu.space. For example:

text
https://f-1420225016421-dozzle-ai.catdog.heiyu.space