Skip to main content
Version: Next

Lua API

Looking for the cross-language FFI contract? See ./ffi-abi.md for call, the Rust dispatcher, and how client:call(name, args) in this binding routes into kcl_api::call. The kcl_lib.raw_api methods below are thin Lua wrappers over that single C ABI.

The official Lua KCL package is built on mlua and exposes the entire KclService + BuiltinService surface as a single Lua module. Two layers are shipped:

  • kcl_lib.api — high-level facade. Wraps raw_api:exec_program and exposes RunResponse with :object(), :yaml(), :json() accessors.
  • kcl_lib.raw_api — 22 typed methods matching spec/spec.proto, each taking a Lua table whose fields map to protobuf message fields.

Installation​

The following Lua versions are supported:

  • 5.4
  • 5.3
  • 5.2
  • 5.1
  • LuaJIT
git clone --depth 1 https://github.com/kcl-lang/lib.git /tmp/lib
cd /tmp/lib/lua
# change Lua version to the version you want to install for
luarocks --lua-version 5.1 --local make

Quick Start​

With a schema.k file:

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

and a data.k file:

app2: AppConfig {
replicas: 4
}

You can run:

local api = require("kcl_lib.api")

-- Execute a single KCL file and print the YAML output
local result = api:run("./schema.k")
print(result:yaml())

-- Execute multiple KCL files and print JSON output
local result = api:run({
"./schema.k",
"./data.k"
})
print(result:json())

-- Using the raw API to the native service
local raw_api = require("kcl_lib.raw_api")

-- Perform a call to a native service function
local result = raw_api:exec_program({
k_filename_list = { "./schema.k" },
})
print(result.yaml_result)

API Reference​

run​

Execute one or several KCL files and return a RunResponse.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.api")

local result = api:run("./schema.k")
assert(result:yaml() == "app:\n replicas: 2")

RunResponse​

An object representing the response from a call to run().

RunResponse:object()​

The resulting KCL response parsed as a Lua object.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.api")

local result = api:run("./schema.k")
assert(result:object().app.replicas == 2)

RunResponse:yaml()​

The resulting KCL response as a YAML string.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.api")

local result = api:run("./schema.k")
assert(result:yaml() == "app:\n replicas: 2")

RunResponse:json()​

The resulting KCL response as a JSON string.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.api")

local result = api:run("./schema.k")
assert(result:json() == '{"app": {"replicas": 2}}')

Raw API Reference​

ping​

Send a ping request to the backing service.

Example

local api = require("kcl_lib.raw_api")

local result = api:ping({ value = "ping" })
assert(result.value == "ping")

get_version​

Get the version of the KCL backing service.

Example

local api = require("kcl_lib.raw_api")

local result = api:get_version({})
assert(result.version ~= "")
assert(result.git_sha ~= "")
assert(result.checksum ~= "")

(The exact version/checksum/git_sha values vary per release; assert only on non-empty.)

parse_program​

Parse KCL program with entry files.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:parse_program({ paths = { "schema.k" } })
print(result.ast_json)

parse_file​

Parse KCL single file to Module AST JSON string with import dependencies and parse errors.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:parse_file({ path = "schema.k" })
print(result.ast_json)

load_package​

load_package provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:load_package({ parse_args = { paths = { "schema.k" } }, resolve_ast = true })
for _, symbol in pairs(result.symbols) do
print(symbol.name)
end

list_options​

list_options provides users with the ability to parse KCL program and get all option information.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:list_options({ paths = { "schema.k" } })
for _, option in ipairs(result.options) do
print(option.name)
end

list_variables​

list_variables provides users with the ability to parse kcl program and get all variables by specs.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:list_variables({ files = { "schema.k" } })
for name, _vars in ipairs(result.variables) do
print(name)
end

exec_program​

Execute KCL file with arguments and return the JSON/YAML result.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:exec_program({ k_filename_list = { "schema.k" } })
assert(result.yaml_result == "app:\n replicas: 2")

format_code​

Format source code.

Example

local api = require("kcl_lib.raw_api")

local code = "schema AppConfig:\n replicas:int"
local result = api:format_code({ source = code })
assert(result.formatted == "schema AppConfig:\n replicas: int\n")

format_path​

Format KCL file or directory path contains KCL files and returns the changed file paths.

Example

The content of schema.k is

schema AppConfig:
replicas:int

app:AppConfig {
replicas: 2}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:format_path({ path = "schema.k" })
assert(result.changed_path[1] == "schema.k")

After running the program, schema.k will be formatted:

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

lint_path​

Lint files and return error messages including errors and warnings.

Example

The content of schema.k is

import a
import a

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:lint_path({ paths = { "schema.k" } })
for _, res in ipairs(result.results) do
print(res)
end

This will print:

Module 'a' is reimported multiple times
Module 'a' imported but unused
Module 'a' imported but unused

override_file​

Override KCL file with args.

Example

The content of file.k is

app = {
replicas = 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:override_file({ file = "file.k", specs = { "app.replicas=42" } })
assert(result.result)

The modified file will then be:

app = {replicas = 42}

get_schema_type_mapping​

Get schema type mapping.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:get_schema_type_mapping({
exec_args = { k_filename_list = { "schema.k" } },
schema_name = "AppConfig",
})
assert(result.schema_type_mapping.AppConfig.properties.replicas.type == "int")

validate_code​

Validate code using schema and data strings.

Example

local api = require("kcl_lib.raw_api")

local result = api:validate_code({
code = "schema AppConfig:\n replicas: int\n check:\n 0 < replicas < 100",
data = "replicas: 42",
format = "yaml",
})
assert(result.success)

rename​

Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed.

Example

The content of schema.k is

schema AppConfig:
replicas: int

app: AppConfig {
replicas: 2
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:rename({
package_root = ".",
file_paths = { "schema.k" },
symbol_path = "app",
new_name = "other",
})
assert(#result.changed_files == 1)

This will result in the following content for schema.k:

schema AppConfig:
replicas: int

other: AppConfig {
replicas: 2
}

test​

Test KCL packages with test arguments.

Example

The content of test/schema.k is

schema AppConfig:
replicas: int = 42

app: AppConfig {
replicas: 2
}

Moreover, the content of test/schema_test.k is

test_app = lambda {
app = AppConfig
assert app.replicas == 42
}

Lua code

local api = require("kcl_lib.raw_api")

local result = api:test({
exec_args = {
work_dir = "test",
k_filename_list = { "./schema.k" },
},
pkg_list = { "test/..." },
})
assert(result.info[1].name == "test_app")

update_dependencies​

Download and update dependencies defined in the kcl.mod file.

Example

The content of kcl.mod is

[package]
name = "mod_update"
edition = "0.0.1"
version = "0.0.1"

[dependencies]
helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" }
flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" }

Lua code

local api = require("kcl_lib.raw_api")

local result = api:update_dependencies({ manifest_path = "." })
print(result.external_pkgs[1].pkg_name == "helloworld")

list_method​

List the KCL service method names supported by the underlying runtime.

Example

local api = require("kcl_lib.raw_api")

local result = api:list_method({})
for _, name in ipairs(result.method_name_list) do
print(name)
end

get_schema_type_mapping_under_path​

Like get_schema_type_mapping, but returns schema type mappings keyed by package name so that schemas imported from external dependency packages keep their own pkgpath and base schema. See kcl-lang/kcl#1546.

Example

local api = require("kcl_lib.raw_api")

local result = api:get_schema_type_mapping_under_path({
exec_args = { k_filename_list = { "." } },
})
for pkg, schemas in pairs(result.schema_type_mapping) do
for _, s in ipairs(schemas.schema_type) do
print(pkg, s.schema_name)
end
end

load_settings_files​

Load the configuration from kcl.yaml (or its aliases).

Example

The content of kcl.yaml is

kcl_cli_configs:
strict_range_check: true
kcl_options:
- key: key
value: value

Lua code

local api = require("kcl_lib.raw_api")

local result = api:load_settings_files({
work_dir = ".",
files = { "kcl.yaml" },
})
assert(result.kcl_cli_configs.strict_range_check == true)

rename_code​

Rename all occurrences of the target symbol and return the modified code without touching the filesystem. Unlike rename, no files are rewritten.

Example

local api = require("kcl_lib.raw_api")

local result = api:rename_code({
package_root = "/mock/path",
symbol_path = "a",
source_codes = { ["/mock/path/main.k"] = "a = 1" },
new_name = "a2",
})
assert(result.changed_codes["/mock/path/main.k"] == "a2 = 1")

Notes​

The legacy BuildProgram and ExecArtifact RPCs were removed from spec/spec.proto in v0.13.0 (see lib commit 815acac); they are not exposed by kcl_lib.raw_api. If you previously called api:build_program(...) or api:exec_artifact(...), switch to api:exec_program(...) plus a host-side file write — the dispatcher no longer recognises the old RPC names.