Skip to content

Python API Reference

Service

LackpyService(workspace=None, config=None)

Unified service layer orchestrating the lackpy pipeline.

Both the MCP server and CLI are thin adapters over this class. Initialize with a workspace path to set the working directory for tool execution.

When kibitzer is installed, the service automatically creates a KibitzerSession for mode enforcement, tool tracking, and coaching.

Parameters:

Name Type Description Default
workspace Path | None

Root directory for tool execution. Defaults to cwd.

None
config LackpyConfig | None

Override configuration. Loaded from .lackpy/config.toml if not provided.

None

validate(program, kit=None, rules=None, param_names=None, extra_tools=None)

Validate a lackpy program against a kit's allowed names.

Parameters:

Name Type Description Default
program str

The lackpy program source to validate.

required
kit str | list[str] | dict | None

Kit name, list of tool names, or dict mapping. Defaults to config default.

None
rules list | None

Additional validation rules to apply beyond core checks.

None
param_names set[str] | None

Extra names (e.g. parameter names) to allow in the program.

None

Returns:

Type Description
ValidationResult

A ValidationResult indicating whether the program is valid.

generate(intent, kit=None, params=None, rules=None, mode=None, interpreter=None, extra_tools=None) async

Generate a lackpy program from a natural language intent.

Parameters:

Name Type Description Default
intent str

Natural language description of the desired program.

required
kit str | list[str] | dict | None

Kit name, list of tool names, or dict mapping.

None
params dict[str, Any] | None

Named input values available to the generated program.

None
rules list | None

Additional validation rules the generated program must satisfy.

None
mode str | None

Inference strategy mode (e.g. '1-shot', 'spm'). Defaults to config or '1-shot'.

None
interpreter Any

An interpreter instance whose system_prompt_hint() is forwarded to the prompt builder. When present, the inference prompt uses interpreter-specialized framing instead of the generic Jupyter-cell template.

None

Returns:

Type Description
GenerationResult

A GenerationResult with the generated program and provider metadata.

Raises:

Type Description
RuntimeError

If all inference providers fail to produce a valid program.

run_program(program, kit=None, params=None, sandbox=None, rules=None, extra_tools=None) async

Validate and execute a lackpy program.

Validates the program before running it; returns a failed ExecutionResult immediately if validation fails rather than raising.

Parameters:

Name Type Description Default
program str

The lackpy program source to execute.

required
kit str | list[str] | dict | None

Kit name, list of tool names, or dict mapping.

None
params dict[str, Any] | None

Named input values injected into the execution namespace.

None
sandbox Any

Reserved for future sandbox configuration (unused).

None
rules list | None

Additional validation rules to apply before execution.

None

Returns:

Type Description
ExecutionResult

An ExecutionResult with output, trace, and success status.

delegate(intent, kit=None, params=None, sandbox=None, rules=None, _program_override=None, mode=None, interpreter=None, extra_tools=None) async

Generate and execute a program from a natural language intent in one step.

Combines generate and run_program: generates a program from intent, then executes it, returning a combined result dict with timing and trace details.

Parameters:

Name Type Description Default
intent str

Natural language description of the desired program.

required
kit str | list[str] | dict | None

Kit name, list of tool names, or dict mapping.

None
params dict[str, Any] | None

Named input values available to the program.

None
sandbox Any

Reserved for future sandbox configuration (unused).

None
rules list | None

Additional validation rules for generation and execution.

None
interpreter Any

An interpreter instance whose system_prompt_hint() is forwarded to the prompt builder for interpreter-specialized framing. When omitted, the default Jupyter-cell prompt is used.

None

Returns:

Type Description
dict[str, Any]

A dict with keys: success, program, grade, generation_tier,

dict[str, Any]

generation_time_ms, execution_time_ms, total_time_ms, trace,

dict[str, Any]

files_read, files_modified, output, error.

Raises:

Type Description
RuntimeError

If all inference providers fail to produce a valid program.

create(program, kit=None, name='', pattern=None, extra_tools=None) async

Validate a program and save it as a named template.

Parameters:

Name Type Description Default
program str

The lackpy program source to save.

required
kit str | list[str] | dict | None

Kit name, list of tool names, or dict mapping used for validation.

None
name str

Template name (used as the filename stem).

''
pattern str | None

Optional intent pattern string for template matching.

None

Returns:

Type Description
dict[str, Any]

A dict with keys: success (bool), path (str) on success,

dict[str, Any]

or errors (list) on validation failure.

kit_info(kit, extra_tools=None)

Return metadata for a resolved kit.

Parameters:

Name Type Description Default
kit str | list[str] | dict

Kit name, list of tool names, or dict mapping.

required

Returns:

Type Description
dict[str, Any]

A dict with keys: tools (mapping of tool name to spec dict),

dict[str, Any]

grade (w and d values), and description (formatted namespace string).

Raises:

Type Description
KeyError

If the kit references an unknown tool.

FileNotFoundError

If a named kit file does not exist.

kit_list()

List all kit files in the workspace configuration directory.

Returns:

Type Description
list[dict[str, str]]

A list of dicts with keys: name (stem) and path (absolute path string).

list[dict[str, str]]

Returns an empty list if the kits directory does not exist.

kit_create(name, tools, description=None)

Create a new kit file in the workspace configuration directory.

Parameters:

Name Type Description Default
name str

Kit name used as the filename stem.

required
tools list[str]

List of tool names to include in the kit.

required
description str | None

Optional human-readable description written to the kit frontmatter.

None

Returns:

Type Description
dict[str, Any]

A dict with keys: name, path (absolute path string), and tools.

toolbox_list()

List all registered tools across all providers.

Returns:

Type Description
list[dict[str, Any]]

A list of dicts with keys: name, provider, description,

list[dict[str, Any]]

grade_w, and effects_ceiling for each registered tool.

docs_index(kit=None, extra_tools=None)

Return documentation references for a kit's tools.

Returns a dict with tool_docs (tool name → relative doc path) and kit_docs (list of kit-level doc paths). Paths are relative to the package/workspace root — callers resolve them on demand.

resolve_doc(doc_path)

Read a documentation file by its relative path.

Resolves the path against the workspace root and returns the content, or None if the file does not exist.


Validation

validate(program, allowed_names=None, extra_rules=None)

Validate a lackpy program string against the language grammar and namespace.

Parses the program and runs a multi-step pipeline: AST node allowlist, forbidden name check, namespace check, for-loop iter check, dunder string check, and any extra custom rules.

Parameters:

Name Type Description Default
program str

The lackpy program source code to validate.

required
allowed_names set[str] | None

Set of callable names permitted beyond the core builtins. Typically the tool names from a resolved kit.

None
extra_rules list | None

Additional rule callables (ast.Module) -> list[str] applied after the built-in checks.

None

Returns:

Type Description
ValidationResult

A ValidationResult with valid=True if no errors were found.

ValidationResult(valid, errors=list(), calls=list(), variables=list()) dataclass

Result of validating a lackpy program.

Attributes:

Name Type Description
valid bool

Whether the program passed all checks.

errors list[str]

List of validation error messages.

calls list[str]

Function names called in the program.

variables list[str]

Variable names assigned in the program.


Grading

Grade(w, d) dataclass

Security grade for a tool kit.

Attributes:

Name Type Description
w int

World coupling (0=pure, 1=pinhole read, 2=scoped exec, 3=scoped write).

d int

Effects ceiling.

compute_grade(tools)

Compute the aggregate security grade for a set of tools.

Takes the maximum grade_w and effects_ceiling across all tools, defaulting to 3 for tools that omit either field.

Parameters:

Name Type Description Default
tools dict[str, dict]

Mapping of tool name to a dict containing optional keys grade_w and effects_ceiling.

required

Returns:

Type Description
Grade

A Grade with the maximum w and d values across all tools.

Grade

Returns Grade(w=0, d=0) for an empty tool set.


Grammar constants

grammar

AST node sets defining the lackpy restricted Python subset.

ALLOWED_NODES = {ast.Module, ast.Expr, ast.Assign, ast.AugAssign, ast.AnnAssign, ast.For, ast.If, ast.With, ast.withitem, ast.Call, ast.Name, ast.Attribute, ast.Subscript, ast.List, ast.Dict, ast.Tuple, ast.Set, ast.ListComp, ast.DictComp, ast.SetComp, ast.Compare, ast.BoolOp, ast.UnaryOp, ast.BinOp, ast.JoinedStr, ast.FormattedValue, ast.Constant, ast.Starred, ast.Slice, ast.comprehension, ast.IfExp, ast.Lambda, ast.arguments, ast.arg, ast.keyword, ast.Load, ast.Store, ast.Del, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod, ast.FloorDiv, ast.Eq, ast.NotEq, ast.Lt, ast.LtE, ast.Gt, ast.GtE, ast.Is, ast.IsNot, ast.In, ast.NotIn, ast.And, ast.Or, ast.Not, ast.USub, ast.UAdd} module-attribute

FORBIDDEN_NODES = {ast.Import, ast.ImportFrom, ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.While, ast.Try, ast.ExceptHandler, ast.Raise, ast.Global, ast.Nonlocal, ast.Yield, ast.YieldFrom, ast.Await, ast.AsyncFor, ast.AsyncWith, ast.Assert, ast.Delete, ast.Match} module-attribute

FORBIDDEN_NAMES = frozenset({'__import__', 'open', 'globals', 'locals', 'vars', 'dir', 'getattr', 'setattr', 'delattr', 'hasattr', '__builtins__', '__build_class__', 'breakpoint', 'exit', 'quit', 'type', 'super', 'classmethod', 'staticmethod', 'property', 'memoryview', 'bytearray', 'bytes', 'map', 'filter', 'reduce', 'input', 'os', 'sys', 'pathlib', 'subprocess', 'shutil'}) module-attribute

ALLOWED_BUILTINS = frozenset({'len', 'sorted', 'reversed', 'enumerate', 'zip', 'range', 'min', 'max', 'sum', 'any', 'all', 'abs', 'round', 'str', 'int', 'float', 'bool', 'list', 'dict', 'set', 'tuple', 'isinstance', 'print', 'sort_by'}) module-attribute


Toolbox

Toolbox()

Registry of tool providers and their resolved tool specs.

Tools are registered via providers (plugin objects with a name attribute and a resolve method). Individual tools can also be registered directly via register_tool.

register_provider(provider)

Register a tool provider plugin and load its tools into the registry.

Parameters:

Name Type Description Default
provider Any

A provider object with a name attribute. The provider's tools are made available for resolution via resolve.

required

register_tool(spec)

Register a single tool spec directly.

Parameters:

Name Type Description Default
spec ToolSpec

The ToolSpec to add. Overwrites any existing spec with the same name.

required

Warns:

Type Description
UserWarning

If the tool name masks a Python stdlib module or builtin, which causes small language models to generate incorrect code.

resolve(name)

Return the callable implementation for a named tool.

Parameters:

Name Type Description Default
name str

The tool name to resolve.

required

Returns:

Type Description
Callable[..., Any]

A callable that implements the tool.

Raises:

Type Description
KeyError

If the tool name is not registered or its provider is not loaded.

resolve_docs(name, docs_root)

Return the absolute path to a tool's documentation file, or None.

Parameters:

Name Type Description Default
name str

Tool name to look up.

required
docs_root Path

Root directory to resolve relative docs paths against.

required

docs_index()

Return a mapping of tool name to docs relative path for all tools.

list_tools()

Return all registered tool specs.

Returns:

Type Description
list[ToolSpec]

A list of all ToolSpec objects in registration order.

format_description(tool_names)

Build a formatted namespace description string for a subset of tools.

Each tool is rendered as name(args) -> return_type: description. Tools not found in the registry are silently skipped.

Parameters:

Name Type Description Default
tool_names list[str]

Names of the tools to include in the description.

required

Returns:

Type Description
str

A newline-joined string of tool signatures, suitable for inference prompts.

ToolSpec(name, provider, provider_config=dict(), description='', args=list(), returns='Any', grade_w=3, effects_ceiling=3, examples=list(), docs=None) dataclass

Specification for a registered tool.

Attributes:

Name Type Description
name str

Unique tool name used in lackpy programs.

provider str

Name of the provider plugin that implements this tool.

provider_config dict[str, Any]

Provider-specific configuration dict.

description str

Human-readable description shown in the inference prompt.

args list[ArgSpec]

Ordered list of argument specifications.

returns str

Return type annotation string.

grade_w int

World coupling level (0–3).

effects_ceiling int

Effects ceiling level (0–3).

examples list[dict]

Tagged examples for retrieval-augmented prompting. Each example is a dict with keys: intent, code, tags. At inference time, relevant examples are selected from the pool of all kit tool examples and injected into the prompt.

docs str | None

Path to a markdown documentation file, relative to the provider's package root. Resolved lazily at query time via the provider's resolve_docs method.

ArgSpec(name, type='Any', description='') dataclass

Specification for a single tool argument.

Attributes:

Name Type Description
name str

Argument name as it appears in the function signature.

type str

Type annotation string (e.g. "str", "int").

description str

Human-readable description of the argument.


Kit registry

resolve_kit(kit, toolbox, kits_dir=None, extra_tools=None)

Resolve a kit specification into a ResolvedKit ready for execution.

Accepts four forms for kit:

  • str: name of a .kit file in kits_dir
  • list[str]: explicit list of tool names
  • dict: alias-to-tool mapping; values may be a tool name string or a dict with a "tool" key
  • None: not yet supported (raises NotImplementedError)

Parameters:

Name Type Description Default
kit str | list[str] | dict[str, str | dict] | None

Kit specification — name, list of names, dict mapping, or None.

required
toolbox Toolbox

The Toolbox instance from which to resolve tools.

required
kits_dir Path | None

Directory containing .kit files. Defaults to .lackpy/kits relative to cwd.

None
extra_tools list[str] | None

Additional tool names to merge into the resolved kit. Duplicates of tools already in the kit are silently ignored.

None

Returns:

Type Description
ResolvedKit

A ResolvedKit with tools, callables, grade, and description populated.

Raises:

Type Description
NotImplementedError

If kit is None (Quartermaster not implemented).

FileNotFoundError

If a named kit file is not found in kits_dir.

KeyError

If a tool name is not registered in the toolbox.

TypeError

If kit is an unsupported type or contains an unsupported entry type.

ResolvedKit(tools, callables, grade, description, docs=list()) dataclass

A fully resolved kit with callables ready for execution.

Attributes:

Name Type Description
tools dict[str, ToolSpec]

Mapping of tool name (or alias) to spec.

callables dict[str, Callable[..., Any]]

Mapping of tool name (or alias) to callable implementation.

grade Grade

Aggregate security grade (join of tool grades).

description str

Formatted namespace description for inference prompts.


Runner

RestrictedRunner

Execute validated lackpy programs via AST compilation.

Programs are compiled from validated ASTs and run with empty __builtins__ and a controlled namespace. Each tool call is wrapped to record timing and results in the trace.

run(program, namespace, params=None, kibitzer_session=None)

Compile and execute a lackpy program in a restricted namespace.

The program's last expression (if any) is captured as the output. All other top-level assignments are returned in variables.

Parameters:

Name Type Description Default
program str

The lackpy program source to execute.

required
namespace dict[str, Callable]

Mapping of tool names to callables, injected into the execution globals alongside allowed builtins.

required
params dict[str, Any] | None

Named parameter values to inject into the namespace.

None
kibitzer_session Any

Optional KibitzerSession for per-call tracking.

None

Returns:

Type Description
ExecutionResult

An ExecutionResult with success, output, trace, and variables.

ExecutionResult

Returns a failed result on parse errors or runtime exceptions.

ExecutionResult(success, output=None, error=None, trace=Trace(), variables=dict()) dataclass

Result of executing a lackpy program.

Attributes:

Name Type Description
success bool

Whether execution completed without error.

output Any

The last expression's value, or None.

error str | None

Error message if execution failed.

trace Trace

Execution trace with tool call records.

variables dict[str, Any]

Variables assigned during execution (excluding params and internals).


Trace

Trace(entries=list(), files_read=list(), files_modified=list()) dataclass

Execution trace accumulating tool call records and file side-effects.

Attributes:

Name Type Description
entries list[TraceEntry]

Ordered list of TraceEntry records, one per tool call.

files_read list[str]

Paths of files read during execution (populated by tools).

files_modified list[str]

Paths of files written or modified during execution.

TraceEntry(step, tool, args, result, duration_ms, success, error) dataclass

A single tool call record in an execution trace.

Attributes:

Name Type Description
step int

Zero-based index of this call within the program execution.

tool str

Name of the tool that was called.

args dict[str, Any]

Keyword argument mapping captured at call time.

result Any

Summarized return value, or None if the call failed.

duration_ms float

Wall-clock time for the call in milliseconds.

success bool

Whether the call completed without raising.

error str | None

Error message string if the call raised, otherwise None.

make_traced(name, fn, trace, kibitzer_session=None)

Wrap a callable to record each invocation in a Trace.

The wrapper captures positional and keyword arguments, measures wall-clock duration, appends a TraceEntry to trace, and re-raises any exception after recording it.

If a kibitzer_session is provided, each call is also reported to Kibitzer via after_call() for mode tracking and coaching.

Parameters:

Name Type Description Default
name str

Tool name to record in each TraceEntry.

required
fn Callable

The callable to wrap.

required
trace Trace

The Trace instance to append entries to.

required
kibitzer_session Any

Optional KibitzerSession for per-call tracking.

None

Returns:

Type Description
Callable

A wrapper callable with the same signature as fn.


Inference

InferenceDispatcher(providers)

Priority-ordered dispatcher that tries inference providers in sequence.

Iterates through providers in order, attempts generation with each available provider, and returns the first result that passes validation. If the first attempt from a provider fails validation, the CorrectionChain is invoked (deterministic cleanup, few-shot retry, fresh fixer) before moving on.

Parameters:

Name Type Description Default
providers list[Any]

Ordered list of provider plugin instances. Each must have name, available(), and generate() attributes.

required

generate(intent, namespace_desc, allowed_names, params_desc=None, extra_rules=None, interpreter=None, kibitzer_session=None) async

Generate a valid lackpy program from a natural language intent.

Tries each available provider in priority order, validating the output after each attempt. On validation failure, the CorrectionChain is invoked (deterministic cleanup → few-shot retry → fresh fixer) before moving to the next provider.

Parameters:

Name Type Description Default
intent str

Natural language description of the desired program.

required
namespace_desc str

Formatted tool namespace string for the prompt.

required
allowed_names set[str]

Set of allowed callable names for validation.

required
params_desc str | None

Optional description of pre-set parameter variables.

None
extra_rules list | None

Additional validation rules beyond the core checks.

None
interpreter Any

An interpreter instance whose system_prompt_hint() is forwarded to build_system_prompt(). When present, the prompt uses interpreter-specialized framing.

None

Returns:

Type Description
GenerationResult

A GenerationResult from the first provider that produces valid output.

Raises:

Type Description
RuntimeError

If all available providers fail to produce a valid program.

GenerationResult(program, provider_name, generation_time_ms, correction_strategy=None, correction_attempts=0, attempts_log=None) dataclass

Result of generating a lackpy program from an intent.

Attributes:

Name Type Description
program str

The generated and validated lackpy program source.

provider_name str

Name of the provider that produced the program.

generation_time_ms float

Total wall-clock time for generation in milliseconds.

correction_strategy str | None

The correction strategy used, or None if no correction needed.

correction_attempts int

Number of correction attempts made (0 if none needed).

attempts_log list | None

Full log of correction attempts, or None if no correction was run.

build_system_prompt(namespace_desc, params_desc=None, intent=None, example_pool=None, n_examples=6, interpreter=None)

Build the system prompt for inference providers.

When interpreter is provided and has a system_prompt_hint() method, the prompt uses interpreter-specialized framing instead of the generic Jupyter-cell template. This typically produces 3–5× higher pass rates on local models (empirically validated across qwen2.5 0.5b–7b, smollm2, and granite models).

When no interpreter is provided, falls back to the original Jupyter-cell framing for backward compatibility.

Parameters:

Name Type Description Default
namespace_desc str

Formatted string of available tools and their signatures.

required
params_desc str | None

Optional description of pre-set parameter variables.

None
intent str | None

Natural language intent. Required for example retrieval.

None
example_pool list[Example] | None

Candidate examples to retrieve from. If None or empty, no examples section is added.

None
n_examples int

Maximum number of examples to include. Default 6 — tested as the sweet spot for qwen2.5-coder models on structured output.

6
interpreter Any

An interpreter instance (or any object with a system_prompt_hint() method). When present and the method exists, the prompt uses interpreter-specialized framing.

None

Returns:

Type Description
str

The complete system prompt string ready to send to an inference provider.

format_params_description(params)

Format a parameters dict into a human-readable description string.

Each parameter is rendered as name: type optionally followed by a description when the value is a metadata dict.

Parameters:

Name Type Description Default
params dict

Mapping of parameter name to either a raw value or a metadata dict with "value", optional "type", and optional "description" keys.

required

Returns:

Type Description
str

A newline-joined string of parameter descriptions.

sanitize_output(raw)

Strip model artifacts from a raw generated code string.

Removes leading preamble lines containing common model hedge phrases, and unwraps markdown code fences (``` blocks) if present.

Parameters:

Name Type Description Default
raw str

Raw string output from an inference provider.

required

Returns:

Type Description
str

Cleaned program source with preamble and code fences removed.

str

Returns an empty string if the input is blank.


Built-in rules

no_loops(tree)

Reject any for-loop in the program.

Parameters:

Name Type Description Default
tree Module

The parsed AST module to check.

required

Returns:

Type Description
list[str]

A list of error strings, one per for-loop found.

max_depth(limit)

Return a rule that rejects programs exceeding a block-nesting depth.

Depth is incremented for if, for, and with blocks only.

Parameters:

Name Type Description Default
limit int

Maximum allowed nesting depth.

required

Returns:

Type Description
Rule

A Rule callable that reports errors for nodes exceeding the limit.

max_calls(limit)

Return a rule that rejects programs with more than limit total calls.

Parameters:

Name Type Description Default
limit int

Maximum number of function calls permitted.

required

Returns:

Type Description
Rule

A Rule callable that reports an error if the call count exceeds the limit.

no_nested_calls(tree)

Reject call expressions used directly as arguments to other calls.

Encourages assigning intermediate results to variables before passing them to another function.

Parameters:

Name Type Description Default
tree Module

The parsed AST module to check.

required

Returns:

Type Description
list[str]

A list of error strings, one per nested call site found.


Configuration

LackpyConfig(inference_order=(lambda: ['templates', 'rules'])(), inference_providers=dict(), kit_default='debug', sandbox_enabled=False, sandbox_timeout=120, sandbox_memory_mb=512, inference_mode=None, tool_providers=dict(), config_dir=(lambda: Path('.lackpy'))()) dataclass

load_config(workspace=None)