Manifest v2
The manifest is the contract between your app and the platform. Both
SDKs validate it at load with extra="forbid" / .strict() — unknown
fields fail loudly so typos don’t silently disable features.
Minimal example
Section titled “Minimal example”apiVersion: linkworld.ai/v2app_id: my-botversion: 0.1.0name: My Botruntime: image: ghcr.io/you/my-bot:0.1.0That’s it. No tools, no scopes, no schedules — your app boots, exposes
/health, and idles.
Full example
Section titled “Full example”apiVersion: linkworld.ai/v2
app_id: tax-botversion: 1.2.3name: Tax Botdescription: Triages inbound emails into tax categoriesicon: receiptcategory: finance
runtime: image: ghcr.io/you/tax-bot:1.2.3 port: 8080 # optional, default 8080 resources: memory_mb: 512 # 64..4096 cpu_cores: 1.0 # 0.1..4 env: DEBUG: "true"
network: egress_hosts: # advisory; runtime CNI rules in Phase 3 - api.openai.com
required_scopes: - mail.send - files.read - odoo.read
tools: - name: classify_invoice description: Categorize text as invoice/receipt/payroll/other scopes_required: [] agent_visible: true # optional, default true
lifecycle: on_install: true on_uninstall: true on_inbound: true on_user_added: false schedules: - name: daily-summary cron: "0 8 * * *"
pricing: # Phase-3 placeholder model: freeFields
Section titled “Fields”apiVersion
Section titled “apiVersion”Required. Must be linkworld.ai/v2.
app_id
Section titled “app_id”Required. URL-safe slug, immutable across versions. Lowercase alphanumeric + hyphens, 3–64 chars, must start with a letter.
version
Section titled “version”Required. Semantic version (X.Y.Z or X.Y.Z-pre). Each value is a
distinct, immutable artifact — bump it on every publish.
name, description, icon, category
Section titled “name, description, icon, category”Display fields shown in the marketplace and the dev console. name
is required; the rest are optional. category is a free-form string
(common values: finance, productivity, support, general).
runtime.image
Section titled “runtime.image”Required. The OCI image the platform pulls when provisioning a container. Must be reachable by the platform’s pull credentials — GHCR public images work out of the box.
runtime.port
Section titled “runtime.port”Optional, default 8080. Must be 1024–65535.
runtime.resources.memory_mb
Section titled “runtime.resources.memory_mb”Optional, default 256. Range 64–4096. Hard cap enforced by the platform.
runtime.resources.cpu_cores
Section titled “runtime.resources.cpu_cores”Optional, default 0.5. Range 0.1–4.0.
runtime.env
Section titled “runtime.env”Optional. Environment variables baked into the container image at run.
Use this for non-secret config (region, debug flags, feature
toggles). For secrets, use ctx.secrets.get(...).
network.egress_hosts
Section titled “network.egress_hosts”Optional. Hostnames your app needs outbound access to. Today this is advisory — runtime CNI enforcement ships in Phase 3.
required_scopes
Section titled “required_scopes”Required for any app calling platform tools. List every scope your
app’s ctx.tools.call(...) paths might need. The tenant must grant
these on install. See Scope catalog.
Optional. Custom tools your app exposes to the tenant agent.
| Field | Required | Notes |
|---|---|---|
name | yes | Lowercase alphanumeric + underscores, 3–64 chars |
description | yes | One-line; shown to the agent’s planner |
scopes_required | yes | Subset of top-level required_scopes |
agent_visible | no, default true | If false, only your own handlers can call it |
lifecycle
Section titled “lifecycle”Optional. Declares which lifecycle hooks your app subscribes to. The
SDK refuses to register a handler whose corresponding lifecycle.<hook>
isn’t true — fast feedback when you forget to flip the flag.
| Field | Type | Notes |
|---|---|---|
on_install | bool | Fires on first activation |
on_uninstall | bool | Fires on deactivation |
on_inbound | bool | Subscribes to tenant inbound channel events (opt-in fan-out) |
on_user_added | bool | Fires when a new user joins the tenant |
schedules[] | list | Named cron entries; minute precision |
lifecycle.schedules[]
Section titled “lifecycle.schedules[]”schedules: - name: daily-summary cron: "0 8 * * *"name is the handle you pass to app.onSchedule(...). cron is
standard 5-field cron (minute precision). The platform’s leader-elected
scanner ticks every 60s.
pricing
Section titled “pricing”Phase-3 placeholder. Today the platform stores it but ignores it.
pricing: model: free | paid tier: starter | pro | ... # opaque to the platformValidation behavior
Section titled “Validation behavior”- Both SDKs use
extra="forbid"semantics — a misspelled field rejects the manifest. - The platform re-validates on deploy; CI catches most drift before publish.
- The shared fixture pool at
packages/sdk-spec/fixtures/is the single source of truth for what’s accepted.