# The package catalog is deployed as a ConfigMap in the operator namespace. # To update packages, edit the catalog data below and upgrade the Helm release. # # Categories: # - core — toggles platform-level OpenClaw behaviour (heartbeat, cron, # active-memory, voice) via config_patch. No channel bindings, # no skills. # - channel — adds a messaging channel (Telegram, Discord, …). # - skill — adds a ClawHub or pack: skill ref to the OpenClawInstance. # # Quiet hours are not exposed as a separate package — in OpenClaw they live # under the heartbeat config (via the active-window setting and via # HEARTBEAT.md content rules). When we expose a tenant-tunable time range # in the portal, it will become additional fields on core-heartbeat rather # than its own package. apiVersion: v1 kind: ConfigMap metadata: name: pieced-package-catalog namespace: {{ .Release.Namespace }} labels: app.kubernetes.io/name: pieced-operator data: catalog.yaml: | packages: # ===================================================================== # CORE — platform behaviour toggles. Patched into OCI config.raw via # config_patch (deep-merged on top of the operator's safe defaults). # ===================================================================== core-heartbeat: name: Heartbeat (Proactive Checks) category: core description: > Periodic agent run (default every 30 min) that lets the assistant check inbox, calendar, and other configured sources and message you proactively when something needs attention. Without this, the assistant only responds when you message it first. # OpenClaw 2026.x ships heartbeat ON by default (30m, or 1h on # Anthropic OAuth) when agents.defaults.heartbeat is absent — # see issues openclaw/openclaw#64293, #19445, #8123. The builder # accordingly writes `every: "0m"` (the known off-switch) into # the baseline configRaw. core-heartbeat's config_patch below # overlays the 30m cadence on top of that. The actual checklist # the heartbeat reads lives in workspace HEARTBEAT.md (seeded # separately via spec.workspaceFiles); without a HEARTBEAT.md # the heartbeat fires harmlessly and replies HEARTBEAT_OK. # # Quiet hours: OpenClaw supports both a config-level activeHours # window under agents.defaults.heartbeat (skipped outside the # window) and in-content rules inside HEARTBEAT.md. Neither is # exposed in the portal yet — when added, they become extra # fields on this package, not a separate core-quiet-hours # package. config_patch: agents: defaults: heartbeat: every: "30m" core-cron: name: Scheduled Tasks (Cron) category: core description: > Allow the assistant to run scheduled tasks (daily briefings, recurring reminders, periodic reports). Off by default. When off, the agent's cron tool stays available but no scheduled job ever fires. # Flips the cron scheduler on. Default base configRaw sets # cron.enabled=false (see builder.go), so this overlay only # writes true when the package is enabled. Job storage lives on # the tenant PVC at ~/.openclaw/cron/jobs.json by default. config_patch: cron: enabled: true core-active-memory: name: Active Memory category: core description: > Lets the assistant recall stable preferences, recurring habits, and long-term context from past conversations during a chat. Uses an extra sub-agent turn per inbound message to query the memory store. Direct-message sessions only — group and channel sessions stay deterministic. Trades a small amount of token cost for continuity and personalisation. # OpenClaw 2026.5.x ships Active Memory as a plugin under # plugins.entries.active-memory with a two-gate activation model: # (1) the plugin must be enabled, (2) the request must be an # eligible direct-chat session. Scoped to "main" agent and # "direct" chat types for safe-default behaviour. The recall # model inherits the session's chat model when available; the # modelFallback is used only when nothing else resolves and # should be present in LiteLLM. Adjust as needed for the # platform's default cheap model. config_patch: plugins: entries: active-memory: enabled: true config: enabled: true agents: ["main"] allowedChatTypes: ["direct"] modelFallback: "pieced-mini" queryMode: "recent" promptStyle: "balanced" timeoutMs: 15000 maxSummaryChars: 220 persistTranscripts: false logging: false core-voice: name: Voice Interaction category: core description: > Speech-to-text on incoming voice notes, automatic text-to-speech on replies, and interactive Talk mode. Audio is routed through PieCed's LiteLLM gateway so STT/TTS spend is tracked per-tenant alongside chat usage. Inbound TTS uses kani-tts; Talk mode uses kokoro-fastapi; STT uses self-hosted Whisper (faster-whisper- large-v3). All three are private to the cluster. # PHASE B — wired in. Toggling this package now installs the full # voice surface into the tenant's OpenClawInstance config: # # - messages.tts: auto TTS on inbound replies, routed to # `pieced-tts-inbound` (kani-tts behind LiteLLM). # - talk: interactive Talk mode, routed to `pieced-tts-talk` # (kokoro-fastapi behind LiteLLM). `interruptOnSpeech: true` # so the agent stops talking when the user starts talking. # - tools.media.audio: STT for inbound voice notes, capped at # 20 MiB per message, routed to `pieced-stt` (whisper-openai # behind LiteLLM). # # Provider config notes # --------------------- # `models.providers.openai` is declared here with no chat models # (`models: []`) — its only role is to give the STT block under # `tools.media.audio` a place to resolve its apiKey/baseUrl from. # The agent's primary chat model still lives under # `models.providers.litellm` (set in builder.go base) and is # unaffected by this patch — deep-merge adds `openai` as a # sibling provider, not a replacement. # # `allowPrivateNetwork: true` on the openai provider is required # because the LiteLLM endpoint is a `http://*.svc` private- # network address. Without it OpenClaw refuses the outbound # call as a private-network destination. # # `${LITELLM_API_KEY}` is supplied via the tenant's envFrom # secretRef (see builder.go), populated by ESO from # secret/data/tenants//litellm. # # Network policy # -------------- # Audio traffic shares the existing LiteLLM egress hole in the # per-tenant CiliumNetworkPolicy (toEndpoints inference ns, # port 4000). No additional CNP rule needed — voice routes # through the same gateway as chat completions. config_patch: models: providers: openai: apiKey: "${LITELLM_API_KEY}" baseUrl: "http://litellm.inference.svc:4000/v1" models: [] request: allowPrivateNetwork: true messages: tts: auto: "inbound" provider: "openai" providers: openai: apiKey: "${LITELLM_API_KEY}" baseUrl: "http://litellm.inference.svc:4000/v1" model: "pieced-tts-inbound" voice: "alloy" talk: provider: "openai" providers: openai: apiKey: "${LITELLM_API_KEY}" baseUrl: "http://litellm.inference.svc:4000/v1" model: "pieced-tts-talk" voice: "af_bella" interruptOnSpeech: true tools: media: audio: enabled: true maxBytes: 20971520 models: - provider: "openai" model: "pieced-stt" baseUrl: "http://litellm.inference.svc:4000/v1" # ===================================================================== # CHANNELS — messaging integrations. Each ships a Channels map that # the builder copies into config.channels, env_vars for credentials, # and bindings so messages route to the default agent. # ===================================================================== telegram: name: Telegram category: channel description: Telegram bot messaging channel channels: telegram: enabled: true env_vars: - name: TELEGRAM_BOT_TOKEN secret_key: bot-token vault_path_suffix: telegram required: true bindings: - match: channel: telegram egress_rules: - host: api.telegram.org port: 443 customer_instructions: | 1. Open Telegram and message @BotFather 2. Send /newbot and follow the prompts 3. Copy the bot token disclaimer: > Messages are relayed through Telegram servers outside Switzerland. discord: name: Discord category: channel description: Discord bot messaging channel channels: discord: enabled: true env_vars: - name: DISCORD_BOT_TOKEN secret_key: bot-token vault_path_suffix: discord - name: DISCORD_APP_ID secret_key: app-id vault_path_suffix: discord bindings: - match: channel: discord egress_rules: - host: discord.com port: 443 - host: gateway.discord.gg port: 443 customer_instructions: | 1. Go to https://discord.com/developers/applications 2. Create app, add bot, copy token and app ID 3. Invite bot to server with messages scope # Threema via the central PieCed gateway (pieced-threema-gateway in # `threema-gateway` namespace). Differs from a typical channel # package in two important ways: # # 1. No customer-supplied secret. The token + HMAC secret used # by the openclaw-channel-threema-relay plugin are minted by # the relay's /admin/tokens endpoint when the portal enables # the package, then written to the same vault path suffix # below. So `secret_key` here lists the keys the plugin reads; # the WRITER is the portal (POST /api/tenants/:name/threema), # not a customer wizard step. # # 2. Cross-namespace egress to `threema-gateway:8080`. The new # `namespace` field on egress_rules emits a Cilium toEndpoints # rule scoped to that namespace; in-cluster traffic to a # sibling namespace would otherwise be blocked by the # cluster-wide tenant isolation policy. # # The matching cross-namespace INGRESS rule (relay → OpenClaw 18789) # is added by the builder when it sees `channels: { threema: ... }` # in any enabled package. threema: name: Threema category: channel description: Threema messaging via the PieCed central gateway channels: threema: enabled: true env_vars: - name: THREEMA_RELAY_URL default: "http://pieced-threema-gateway.threema-gateway.svc:8080" - name: THREEMA_RELAY_TOKEN secret_key: token vault_path_suffix: threema-relay - name: THREEMA_RELAY_HMAC_SECRET secret_key: hmac-secret vault_path_suffix: threema-relay bindings: - match: channel: threema egress_rules: - namespace: threema-gateway port: 8080 # OpenClaw 2026.5.x loads external plugins from # /data/extensions//openclaw.plugin.json. Three gates must # be open for the runtime to register an external plugin: # 1. plugins.enabled: true — feature flag # 2. plugins.allow contains the id — security allowlist # 3. plugins.entries..enabled: true — per-plugin toggle # Cedric's personal instance.yaml hand-codes the same three gates # for his direct `openclaw-channel-threema` plugin; this patch # generates them automatically for every tenant that enables # threema. The init container that copies the plugin onto the # PVC is emitted by the operator (plugin_image below). config_patch: plugins: enabled: true allow: - "threema" entries: threema: enabled: true config: {} plugin_image: repository: registry.c5ai.ch/pieced/openclaw-channel-threema-relay tag: "0.1.1" target_dir: openclaw-channel-threema-relay customer_instructions: | 1. Once enabled, register the Threema IDs you want to receive messages from under "Authorized Users → threema". 2. PieCed will route messages between those Threema IDs and your assistant via the central gateway — no Gateway account of your own required. 3. Each Threema ID can only belong to one PieCed tenant. If a registration fails, that ID is already claimed elsewhere. disclaimer: > Messages are end-to-end encrypted at the Threema boundary by the PieCed central gateway. Inbound and outbound message counts are logged per tenant for billing. # ===================================================================== # SKILLS — ClawHub skill installs. Operator passes each entry through # to spec.skills on the OpenClawInstance. # ===================================================================== git-cli: name: Git CLI category: skill description: > Use git from the assistant's shell (clone, commit, push, pull, diff, log, status). For private repositories, configure credentials in your workspace. skills: - "openlang-cn/git-cli" egress_rules: - host: github.com port: 443 - host: gitlab.com port: 443 github: name: GitHub (gh CLI) category: skill description: > Interact with GitHub repositories via the gh CLI — issues, PRs, CI runs, releases, gists. Requires a personal access token. skills: - "steipete/github" env_vars: - name: GH_TOKEN secret_key: token vault_path_suffix: github required: true egress_rules: - host: api.github.com port: 443 - host: github.com port: 443 - host: codeload.github.com port: 443 customer_instructions: | 1. Open https://github.com/settings/tokens 2. Generate a fine-grained personal access token with the repo scopes you want the assistant to use. 3. Copy the token (it is shown only once). gitea: name: Gitea category: skill description: > Interact with a Gitea instance — repositories, issues, PRs, releases. Defaults to the PieCed-platform Gitea at git.c5ai.ch; supply your own GITEA_URL if you host elsewhere. skills: - "ericxliu1990/gitea" env_vars: - name: GITEA_URL default: "https://git.c5ai.ch" - name: GITEA_TOKEN secret_key: token vault_path_suffix: gitea required: true egress_rules: - host: git.c5ai.ch port: 443 customer_instructions: | 1. Log in to your Gitea instance (default https://git.c5ai.ch). 2. Go to Settings → Applications → Generate New Token. 3. Grant the scopes you want the assistant to use (repo, issue, user — minimum needed for most workflows). 4. Copy the token. whisper-self-hosted: name: Whisper (Self-Hosted Transcription) category: skill description: > Transcribe audio files via the platform's self-hosted Whisper ASR instance. Useful for ad-hoc transcription tasks initiated from chat; channel-level voice intake is handled separately by the Voice CORE feature. skills: - "xavjer/openclaw-self-hosted-whisper" env_vars: - name: WHISPER_URL default: "http://whisper-asr.whisper-asr.svc.cluster.local:9000" searxng-local-search: name: Web Search (SearXNG) category: skill description: > Privacy-respecting web search via the platform's internal SearXNG instance. Search the web, images, news, and more without external API calls or trackers. skills: - "noblepayne/searxng-local-search" env_vars: - name: SEARXNG_URL default: "http://searxng.searxng.svc.cluster.local:8080" gog: name: Google Workspace (Gog) category: skill description: > Bundled access to Gmail, Calendar, Drive, Docs, Sheets, and Contacts via Google OAuth. Setup requires a Google Cloud project and an OAuth client. NOTE: OAuth flow is not yet self-service in the portal — contact PieCed support for credentials onboarding. skills: - "steipete/gog" env_vars: - name: GOG_CLIENT_ID secret_key: client-id vault_path_suffix: gog required: true - name: GOG_CLIENT_SECRET secret_key: client-secret vault_path_suffix: gog required: true - name: GOG_REFRESH_TOKEN secret_key: refresh-token vault_path_suffix: gog required: true egress_rules: - host: oauth2.googleapis.com port: 443 - host: www.googleapis.com port: 443 - host: gmail.googleapis.com port: 443 - host: calendar.googleapis.com port: 443 - host: drive.googleapis.com port: 443 - host: docs.googleapis.com port: 443 - host: sheets.googleapis.com port: 443 - host: people.googleapis.com port: 443 customer_instructions: | Google Workspace integration uses OAuth and requires manual onboarding for now. Please open a support ticket to start the setup process — we will exchange the client credentials and a refresh token offline, then enable this package on your tenant. disclaimer: > By enabling Google Workspace integration you authorize PieCed to access Gmail, Calendar, Drive, Docs, Sheets, and Contacts on your behalf. Data flows through Google's APIs subject to Google's terms. mail: name: Email (IMAP / SMTP) category: skill description: > Read, search, and manage email via IMAP; send via SMTP. Works with Gmail (with an app password), Outlook, Fastmail, and any standard IMAP/SMTP host. Replaces the previous Gmail-only channel. skills: - "ivangdavila/mail" env_vars: - name: IMAP_HOST secret_key: imap-host vault_path_suffix: mail required: true - name: IMAP_USER secret_key: imap-user vault_path_suffix: mail required: true - name: IMAP_PASS secret_key: imap-pass vault_path_suffix: mail required: true - name: SMTP_HOST secret_key: smtp-host vault_path_suffix: mail required: true - name: SMTP_USER secret_key: smtp-user vault_path_suffix: mail required: true - name: SMTP_PASS secret_key: smtp-pass vault_path_suffix: mail required: true # The mail skill connects to tenant-supplied IMAP/SMTP servers on # ports 993 / 465 / 587. The hostnames are not known at catalog # time, so we open these ports to "world" rather than declaring # FQDNs. Trade-off accepted for pilot — see catalog.EgressRule # for the rule shape and rationale. egress_rules: - port: 993 world: true - port: 465 world: true - port: 587 world: true customer_instructions: | 1. For Gmail: enable 2-Step Verification, then create an App Password at https://myaccount.google.com/apppasswords and use it as both IMAP and SMTP password. 2. For Outlook/Microsoft 365 with MFA: generate an app password under your account's security settings. 3. For other providers: refer to their IMAP/SMTP documentation for host names and ports. 4. Typical IMAP_HOST values: imap.gmail.com, outlook.office365.com. 5. Typical SMTP_HOST values: smtp.gmail.com, smtp.office365.com. disclaimer: > The assistant gains read/write access to the mailbox you configure. Use a dedicated address rather than a personal inbox if you want to limit scope.