Entry Kinds Reference

This page summarizes the available entry kinds and links to their detailed module and system references.

The YAML and Lua blocks are reference fragments, not one application. Registry IDs, credentials, data objects, and helpers such as get_users or delete_user are illustrative; use the linked module pages for complete return and error contracts.

Entries reference one another using namespace:name. The registry uses these references to resolve dependencies and initialization order.

See Also

Lua Runtime

Kind Description
function.lua Lua function entry point
process.lua Long-running Lua process
workflow.lua Temporal workflow (deterministic)
library.lua Shared Lua library
module.lua Lua module surface
function.lua.bc Precompiled function bytecode
library.lua.bc Precompiled library bytecode
process.lua.bc Precompiled process bytecode
workflow.lua.bc Precompiled workflow bytecode
- name: handler
  kind: function.lua
  source: file://handler.lua
  method: main
  modules:
    - http
    - json
  imports:
    utils: app.lib:helpers  # Import another entry as module
Use imports to reference other Lua entries. They become available via require("alias_name") in your code.

HTTP Services

Kind Description
http.service HTTP server (binds port)
http.router Route prefix and middleware
http.endpoint HTTP endpoint (method + path)
http.static Static file serving
# HTTP server
- name: gateway
  kind: http.service
  addr: ":8080"
  lifecycle:
    auto_start: true

# Router with middleware
- name: api
  kind: http.router
  meta:
    server: gateway
  prefix: /api
  middleware:
    - cors
    - ratelimit

# Endpoint
- name: users_list
  kind: http.endpoint
  meta:
    router: app:api
  method: GET
  path: /users
  func: list_handler

Lua API: See HTTP Module

local http = require("http")
local req = http.request()
local resp = http.response()

resp:set_status(200)
resp:write_json({users = get_users()})

Databases

Kind Description
db.sql.sqlite SQLite database
db.sql.postgres PostgreSQL database
db.sql.mysql MySQL database
db.cdc.postgres Postgres Change Data Capture source (see CDC)
db.cdc.sqlite SQLite Change Data Capture source (see CDC)

SQLite

- name: database
  kind: db.sql.sqlite
  file: "./data/app.db"
  lifecycle:
    auto_start: true

# In-memory for testing
- name: testdb
  kind: db.sql.sqlite
  file: ":memory:"

PostgreSQL

- name: database
  kind: db.sql.postgres
  host: localhost
  port: 5432
  database: dbname
  username: user
  password: pass
  options:
    sslmode: disable
  pool:
    max_open: 25
    max_idle: 5
    max_lifetime: "30m"
  lifecycle:
    auto_start: true

MySQL

- name: database
  kind: db.sql.mysql
  host: localhost
  port: 3306
  database: dbname
  username: user
  password: pass
  options:
    parseTime: "true"
  lifecycle:
    auto_start: true

See Database for ${env:NAME} secret references, TLS options, and connection pool tuning. When an env-backed value behind a database entry changes, the pool swaps live — active borrows finish against the old connection settings.

Lua API: See SQL Module

local sql = require("sql")
local db, err = sql.get("app:database")

local rows, err = db:query("SELECT * FROM users WHERE id = ?", {user_id})
db:execute("INSERT INTO logs (msg) VALUES (?)", {message})

Key-Value Stores

Kind Description
store.memory In-memory key-value store
store.sql SQL-backed key-value store
store.kv.raft Cluster-replicated, strongly-consistent KV (shared Raft)
store.kv.crdt Cluster-replicated, eventually-consistent KV (gossip/CRDT)
# Memory store
- name: cache
  kind: store.memory
  lifecycle:
    auto_start: true

# SQL-backed store
- name: persistent_store
  kind: store.sql
  database: app:database
  table_name: kv_store
  lifecycle:
    auto_start: true

# Cluster-replicated store (requires clustering)
- name: deployments
  kind: store.kv.raft
  namespace: deploy

The store.kv.* kinds need clustering enabled. See Store for the consistency tradeoffs.

Lua API: See Store Module

local store = require("store")
local s, err = store.get("app:cache")

s:set("user:123", user_data, 3600)  -- TTL in seconds
local data = s:get("user:123")

Queues

Kind Description
queue.driver.memory In-memory queue driver
queue.driver.amqp AMQP (RabbitMQ) driver
queue.driver.sqs AWS SQS driver
queue.queue Queue declaration
queue.consumer Queue consumer
# Driver
- name: queue_driver
  kind: queue.driver.memory
  lifecycle:
    auto_start: true

# Queue
- name: jobs
  kind: queue.queue
  driver: queue_driver

# Consumer
- name: job_consumer
  kind: queue.consumer
  queue: app:jobs
  func: job_handler
  concurrency: 4
  prefetch: 10
  lifecycle:
    auto_start: true

Lua API: See Queue Module

local queue = require("queue")

-- Publish a message
queue.publish("app:jobs", {task = "process", id = 123})

-- In a consumer handler: the message body is the handler's argument
local function main(data)
    -- access delivery metadata via the current message
    local msg = queue.message()
    local id = msg:id()
    local priority = msg:header("priority")
    msg:ack()
end
The consumer's func is invoked once per message with the message body as its argument. Use queue.message() inside the handler for the delivery's id(), header()/headers(), and ack()/nack().

Process Management

Kind Description
process.host Process execution host
process.service Supervised process (wraps process.lua)
terminal.host Terminal/CLI host
pg.scope Process-group scope (see Process Groups)
# Process host (where processes run)
- name: processes
  kind: process.host
  host:
    workers: 32             # Worker goroutines (default: NumCPU)
    queue_size: 1024        # Global queue capacity
    local_queue_size: 256   # Per-worker queue
  lifecycle:
    auto_start: true

# Process definition
- name: worker_process
  kind: process.lua
  source: file://worker.lua
  method: main

# Supervised process service
- name: worker
  kind: process.service
  process: app:worker_process
  host: app:processes
  input: ["arg1", "arg2"]
  lifecycle:
    auto_start: true
    restart:
      max_attempts: 10

- name: terminal
  kind: terminal.host
  lifecycle:
    auto_start: true
Use process.service when you need a process to run as a supervised service with automatic restart. The process field references a process.lua entry.

Updating a live process.host entry rescales host.workers in place — running processes, PIDs, and queues are preserved. host.queue_size, host.local_queue_size, and lifecycle are fixed at construction: a live update changing them is rejected, as is resizing workers on a host whose workers are affinity-managed.

Process security

process.lua and process.lua.bc entries accept a top-level security: block. It is part of the entry, so it applies to every spawn of that process, on both process.host and terminal.host:

- name: worker_process
  kind: process.lua
  source: file://worker.lua
  method: main
  security:
    actor:
      id: system.worker
      meta:
        tenant: acme
    policies:
      - app.security:worker_policy
    groups:
      - app.security:background_jobs
Field Description
actor.id Actor identity the process runs as; replaces the inherited actor
actor.meta Actor attributes policies evaluate
policies Registry IDs (namespace:name) of policies merged into the scope
groups Registry IDs of policy groups whose policies are merged into the scope

Resolution happens as the process starts and is atomic: if any listed policy or group cannot be resolved, the spawn fails and no partial context is installed. Omitting actor inherits the spawner's actor; omitting both policies and groups inherits the spawner's scope. function.lua, function.lua.bc, process.lua, and process.lua.bc all accept the block.

A command entry can additionally declare meta.command.security, which applies only when the entry is launched as a CLI command — see Command security. It does not affect ordinary spawns.

See Security.

Temporal (Workflows)

Kind Description
temporal.client Temporal client connection
temporal.worker Temporal worker
- name: temporal_client
  kind: temporal.client
  address: "localhost:7233"
  namespace: "default"
  auth:
    type: none  # none, api_key, mtls
  lifecycle:
    auto_start: true

- name: temporal_worker
  kind: temporal.worker
  client: temporal_client
  task_queue: "main-queue"
  lifecycle:
    auto_start: true

Cloud Storage

Kind Description
config.aws AWS configuration
cloudstorage.s3 S3 bucket access
- name: aws
  kind: config.aws
  region: "us-east-1"
  access_key_id: ${env:AWS_ACCESS_KEY_ID}
  secret_access_key: ${env:AWS_SECRET_ACCESS_KEY}

- name: uploads
  kind: cloudstorage.s3
  config: app:aws
  bucket: "my-uploads"
  endpoint: ""  # Optional, for S3-compatible services

Lua API: See Cloud Storage Module

local cloudstorage = require("cloudstorage")
local storage, err = cloudstorage.get("app:uploads")

storage:upload_object("files/doc.pdf", file_content)
local url = storage:presigned_get_url("files/doc.pdf", {expiration = 3600})  -- seconds, default 3600
Use endpoint to connect to S3-compatible services like MinIO or DigitalOcean Spaces.

File Systems

Kind Description
fs.directory Directory access
fs.embed Read-only embedded filesystem
- name: data_dir
  kind: fs.directory
  directory: "./data"
  auto_init: true   # Create if not exists
  mode: "0755"      # Permissions

Lua API: See Filesystem Module

local fs = require("fs")
local filesystem, err = fs.get("app:data_dir")

local file = filesystem:open("output.txt", "w")
file:write("Hello, World!")
file:close()

Environment

Kind Description
env.storage.memory In-memory env storage
env.storage.file File-based env storage
env.storage.os OS environment
env.storage.static Read-only static key-value storage
env.storage.router Env router (multiple storages)
env.variable Environment variable
- name: os_env
  kind: env.storage.os

- name: file_env
  kind: env.storage.file
  file_path: ".env"
  auto_create: true

- name: defaults
  kind: env.storage.static
  values:
    PUBLIC_API_HOST: "https://api.example.com"
    APP_ENV: "production"

- name: app_env
  kind: env.storage.router
  storages:
    - app:os_env
    - app:file_env
    - app:defaults

Lua API: See Env Module

local env = require("env")

local api_key = env.get("API_KEY")
env.set("CACHE_TTL", "3600")
The router tries storages in order. First match wins for reads; writes go to the first storage in the list.

Templates

Kind Description
template.jet Individual Jet template
template.set Template set configuration
# Template set with engine configuration
- name: templates
  kind: template.set
  engine:
    development_mode: false
    extensions:
      - ".jet"
      - ".html.jet"

# Individual template
- name: email_template
  kind: template.jet
  source: file://templates/email.jet
  set: app:templates

Lua API: See Template Module

local templates = require("templates")
local set, err = templates.get("app:templates")

local html = set:render("email", {
    user = "Alice",
    message = "Welcome!"
})

Security

Kind Description
security.policy Security policy with conditions
security.policy.expr Expression-based policy
security.token_store Token storage
# Condition-based policy
- name: admin_policy
  kind: security.policy
  policy:
    actions: "*"
    resources: "*"
    effect: allow
    conditions:
      - field: "actor.meta.role"
        operator: eq
        value: "admin"

# Expression-based policy
- name: owner_policy
  kind: security.policy.expr
  policy:
    actions: "*"
    resources: "*"
    effect: allow
    expression: 'actor.id == meta.owner_id || actor.meta.role == "admin"'
  groups:
    - operators

Policy groups are formed by the policies themselves: a policy lists the group IDs it belongs to under groups:, and a group is the set of policies naming it. There is no separate group entry kind. Group IDs are registry IDs — a bare name resolves in the declaring policy's namespace, so operators above becomes app.security:operators when declared in namespace app.security. Entries reference groups by their full namespace:name.

Lua API: See Security Module

local security = require("security")

-- Check permission before action
if security.can("delete", "users", {user_id = id}) then
    delete_user(id)
end

-- Get current actor
local actor = security.actor()
Every policy in scope is evaluated. A deny from any matching policy wins over every allow; with no deny, a matching allow grants access. Order does not matter.

Contracts (Dependency Injection)

Kind Description
contract.definition Interface with method specifications
contract.binding Maps contract methods to function implementations
# Define the contract interface
- name: greeter
  kind: contract.definition
  methods:
    - name: greet
      description: Returns a greeting message
    - name: greet_with_name
      description: Returns a personalized greeting
      input_schemas:
        - format: "application/schema+json"
          definition: {"type": "string"}
      output_schemas:
        - format: "application/schema+json"
          definition: {"type": "string"}

# Implementation functions
- name: greeter_greet
  kind: function.lua
  source: file://greeter_greet.lua
  method: main

- name: greeter_greet_name
  kind: function.lua
  source: file://greeter_greet_name.lua
  method: main

# Bind contract methods to implementations
- name: greeter_impl
  kind: contract.binding
  contracts:
    - contract: app:greeter
      default: true
      methods:
        greet: app:greeter_greet
        greet_with_name: app:greeter_greet_name

Usage from Lua:

local contract = require("contract")

-- Open binding by ID
local greeter, err = contract.open("app:greeter_impl")

-- Call methods
local result = greeter:greet()
local personalized = greeter:greet_with_name("Alice")

-- Check if instance implements contract
local is_greeter = contract.is(greeter, "app:greeter")

Lua API: See Contract Module

Mark one binding as default: true to use it when opening a contract without specifying a binding ID. A contract may have only one default binding.

Execution

Kind Description
exec.native Native command execution
exec.docker Docker container execution
- name: native_exec
  kind: exec.native
  default_work_dir: "/app"
  command_whitelist:
    - "ls"
    - "cat"

- name: docker_exec
  kind: exec.docker
  image: "python:3.11-slim"
  default_work_dir: "/workspace"
  auto_remove: true
  memory_limit: 536870912  # 512MB
  command_whitelist:
    - "python"

WASM Runtime

Kind Description
function.wat WebAssembly function (WAT text format)
function.wasm WebAssembly function (binary)
process.wasm WebAssembly process
# WAT text is inline source
- name: sum_wat
  kind: function.wat
  source: file://sum.wat
  method: sum
  transport: payload   # or wasi-http

# Binary WASM is loaded from a filesystem entry and verified by hash
- name: sum
  kind: function.wasm
  fs: app:modules
  path: sum.wasm
  hash: sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
  method: sum
  transport: payload

function.wasm and process.wasm take fs, path, and hash — there is no source field on a binary entry; source belongs to function.wat only. hash is required and must be sha256:<hex>; the module is rejected if the bytes do not match.

See WASM Overview.

Networks

Kind Description
network Base network overlay
network.socks5 SOCKS5 proxy overlay
network.i2p I2P network overlay
network.tailscale Tailscale overlay

Referenced by http.service via network:, by funcs/process via the network option, and by http_client via the overlay_network option. See Network.

Registry Primitives

Kind Description
registry.entry Plain data entry with no service behind it (app-specific config)
ns.definition Namespace definition
ns.requirement Namespace requirement declaration
ns.dependency Namespace dependency

The ns.* kinds are authored like any other entry: a component declares ns.definition and ns.requirement, and a host declares ns.dependency. See Building Components.

Lifecycle Configuration

Supervisor-managed service entries expose lifecycle configuration. The block below belongs inside a service entry that supports it:

lifecycle:
  auto_start: true          # Start automatically
  start_timeout: 10s        # Max startup time
  stop_timeout: 10s         # Max shutdown time
  stable_threshold: 5s      # Uninterrupted run time before retry accounting resets
  requires:
    - app:database
  restart:                  # Retry policy
    initial_delay: 1s
    max_delay: 90s
    backoff_factor: 2.0
    max_attempts: 0         # 0 = infinite
Use depends_on to ensure entries start in the correct order. The supervisor starts a dependent entry only after each of its dependencies has completed its own start.

Entry Reference Format

Entries are referenced using namespace:name format:

# Definition
namespace: app.users
entries:
  - name: handler
    kind: function.lua

# Reference from another entry
func: app.users:handler

Overriding Entries

Any entry's fields — including its kind — can be overridden at launch without editing the source YAML, using the override: config section or the -o CLI flag. Keys use namespace:entry:path format:

override:
  app:gateway:addr: ":9090"        # data field (a bare path targets data.*)
  app:worker:meta.priority: high    # meta field
  app:db:kind: db.sql.postgres      # the entry's typed kind
  app:db:data.kind: custom          # a payload field literally named "kind"
Path Targets
kind The entry's typed kind (must be a non-empty string)
data.<field> or bare <field> A field in the entry's data payload
meta.<field> A field in the entry's metadata

The same overrides apply from the CLI:

wippy run -o app:db:kind=db.sql.postgres -o app:gateway:addr=:9090

CLI (-o) values coerce by shape (true/false to bool, numbers to numbers, otherwise string); override: section values keep their YAML type. To override global configuration sections instead of entries, use --set.