AIPACK

API Documentation

The aip top module provides a comprehensive set of functions for interacting with files, paths, text, markdown, JSON, web services, Lua value inspection, agent control flow, command execution, semantic versioning, Handlebars templating, code formatting, Git, Rust code processing, and HTML processing within the AIPACK environment.

Getting Started Video Tutorial

AIPACK Lab Repo

The available submodules are:

File Path supported

AIPACK supports several types of file paths:

Type Example Notes
Relative some/file.txt Relative to the workspace directory
Absolute /absolute/path/file.txt Absolute path (C:/ on Windows)
Pack Ref my_org@my_pack/path/file.txt Finds the closest pack (in custom workspace, custom base, or install base) and uses this as a directory
Home Tilde ~/path/to/file.txt User home directory; ~ is replaced by the home directory (or / if no home directory is found)
Session TMP $tmp/some/file.txt Located in .aipack/.sessions/_uid_/ within the workspace; unique per session (until command stops)
Workspace Pack Support my_org@my_pack$workspace/some/file.txt Maps to .aipack/support/pack/my_org/my_pack/some/file.txt in the workspace
Base Pack Support my_org@my_pack$base/some/file.txt Maps to .aipack-base/support/pack/my_org/my_pack/some/file.txt in the base directory

Important notes:

Common Data Types:

AI Response

An ai_response variable will be injected into the scope in the # Output Lua code block if an instruction was given and an AI request occurred (otherwise, it will be nil).

{
  // The final text response from the AI, if available.
  content?: string,
  // A formatted string capturing essential details like usage, price, model, and duration of the request, using the fields below.
  info: string,
  // e.g., `gpt-4.1-mini`
  model_name: string,
  // e.g., `openai`
  adapter_kind: AdapterKind,
  // Token usage details.
  usage: {
    prompt_tokens: number,
    completion_tokens: number
  },
  // The approximate price in USD, if available.
  price_usd?: number,
  // Duration in seconds (with millisecond precision).
  duration_sec: number,
  // Reasoning content, if available (e.g., from deepseek or some groq models).
  reasoning_content?: string,
}

Global and Injected Variables:

NOTE

All of the type documentation is noted in "TypeScript style" as it is a common and concise type notation for scripting languages and works well to express Lua types. However, it is important to note that there is no TypeScript support, just standard Lua. For example, Lua properties are delimited with = and not :', and arrays and dictionaries are denoted with { }`.

aip.file

File manipulation functions for loading, saving, listing, and managing files and their content, including specialized functions for JSON and Markdown.

Functions Summary

aip.file.load(rel_path: string, options?: {base_dir: string}): FileRecord

aip.file.save(rel_path: string, content: string)

aip.file.append(rel_path: string, content: string)

aip.file.delete(path: string): boolean

aip.file.ensure_exists(path: string, content?: string, options?: {content_when_empty?: boolean}): FileInfo

aip.file.exists(path: string): boolean

aip.file.list(include_globs: string | list<string>, options?: {base_dir?: string, absolute?: boolean, with_meta?: boolean}): list<FileInfo>

aip.file.list_load(include_globs: string | list<string>, options?: {base_dir?: string, absolute?: boolean}): list<FileRecord>

aip.file.first(include_globs: string | list<string>, options?: {base_dir?: string, absolute?: boolean}): FileInfo | nil

aip.file.info(path: string): FileInfo | nil

aip.file.load_json(path: string): table | value

aip.file.load_ndjson(path: string): list<table>

aip.file.append_json_line(path: string, data: value): FileInfo

aip.file.append_json_lines(path: string, data: list): FileInfo

aip.file.save_changes(path: string, changes: string): FileInfo

aip.file.load_md_sections(path: string, headings?: string | list<string>): list<MdSection>

aip.file.load_md_split_first(path: string): {before: string, first: MdSection, after: string}

aip.file.save_html_to_md(html_path: string, dest?: string | table): FileInfo

aip.file.save_html_to_slim(html_path: string, dest?: string | table): FileInfo
aip.file.load_html_as_slim(html_path: string): string
aip.file.load_html_as_md(html_path: string, options?: table): string

aip.file.save_docx_to_md(docx_path: string, dest?: string | table): FileInfo

aip.file.load_docx_as_md(docx_path: string): string

aip.file.hash_sha256(path: string): string
aip.file.hash_sha256_b64(path: string): string
aip.file.hash_sha256_b64u(path: string): string
aip.file.hash_sha256_b58u(path: string): string

aip.file.hash_sha512(path: string): string
aip.file.hash_sha512_b64(path: string): string
aip.file.hash_sha512_b64u(path: string): string
aip.file.hash_sha512_b58u(path: string): string

aip.file.hash_blake3(path: string): string
aip.file.hash_blake3_b64(path: string): string
aip.file.hash_blake3_b64u(path: string): string
aip.file.hash_blake3_b58u(path: string): string

Note: All relative paths are relative to the workspace directory (parent of .aipack/). Unless a base_dir option is specified. Pack references (e.g., ns@pack/) can be used in paths and base_dir.

aip.file.load

Load a FileRecord object with its content.

-- API Signature
aip.file.load(rel_path: string, options?: {base_dir: string}): FileRecord

Loads the file specified by rel_path and returns a FileRecord object containing the file's metadata and its content.

Arguments

Returns

Example

local readme = aip.file.load("doc/README.md")
print(readme.path)    -- Output: "doc/README.md" (relative path used)
print(#readme.content) -- Output: <length of content>

local agent_file = aip.file.load("agent.aip", { base_dir = "ns@pack/" })
print(agent_file.path) -- Output: "agent.aip" (relative to the resolved base_dir)

Error

Returns an error (Lua table { error: string }) if the file cannot be found, read, or metadata retrieved, or if base_dir is invalid.

aip.file.save

Save string content to a file at the specified path.

-- API Signature
aip.file.save(rel_path: string, content: string)

Writes the content string to the file specified by rel_path. Overwrites existing files. Creates directories as needed. Restricts saving outside the workspace or shared base directory for security.

Arguments

Returns

Example

aip.file.save("docs/new_feature.md", "# New Feature\n\nDetails.")

Error

Returns an error (Lua table { error: string }) on write failure, permission issues, path restrictions, or if no workspace context.

aip.file.append

Append string content to a file at the specified path.

-- API Signature
aip.file.append(rel_path: string, content: string)

Appends content to the end of the file at rel_path. Creates the file and directories if they don't exist.

Arguments

Returns

Example

aip.file.append("logs/app.log", "INFO: User logged in.\n")

Error

Returns an error (Lua table { error: string }) on write failure, permission issues, or I/O errors.

aip.file.delete

Deletes a file at the specified path.

-- API Signature
aip.file.delete(path: string): boolean

Attempts to delete the file specified by path. The path is resolved relative to the workspace root.

Security:

Arguments

Returns

Example

local removed = aip.file.delete("logs/app.log")
if removed then
  print("Removed logs/app.log")
else
  print("No file to remove")
end

Error

Returns an error (Lua table { error: string }) if:

aip.file.ensure_exists

Ensure a file exists at the given path, optionally creating it or adding content if empty.

-- API Signature
aip.file.ensure_exists(path: string, content?: string, options?: {content_when_empty?: boolean}): FileInfo

Checks if the file exists. If not, creates it with content. If it exists and options.content_when_empty is true and the file is empty (or whitespace only), writes content. Intended for files, not directories.

Arguments

Returns

Example

-- Create config if needed, with default content
local default_config = "-- Default Settings --\nenabled=true"
local meta = aip.file.ensure_exists("config/settings.lua", default_config)
print("Ensured file:", meta.path)

-- Ensure log file exists, don't overwrite
aip.file.ensure_exists("logs/activity.log")

-- Add placeholder only if file is currently empty
aip.file.ensure_exists("src/module.lua", "-- TODO", {content_when_empty = true})

Error

Returns an error (Lua table { error: string }) on creation/write failure, permission issues, or metadata retrieval failure.

aip.file.exists

Checks if the specified path exists (file or directory).

-- API Signature
aip.file.exists(path: string): boolean

Checks if the file or directory specified by path exists. The path is resolved relative to the workspace root. Supports relative paths, absolute paths, and pack references (ns@pack/...).

Arguments

Returns

Example

if aip.file.exists("README.md") then
  print("README.md exists.")
end

if aip.file.exists("ns@pack/main.aip") then
  print("Pack main agent exists.")
end

Error

Returns an error (Lua table { error: string }) if the path string cannot be resolved (e.g., invalid pack reference, invalid path format).

{
  error: string // Error message
}

aip.file.list

List file metadata (FileInfo) matching glob patterns.

-- API Signature
aip.file.list(
  include_globs: string | list<string>,
  options?: {
    base_dir?: string,
    absolute?: boolean,
    with_meta?: boolean
  }
): list<FileInfo>

Finds files matching include_globs within base_dir (or workspace) and returns a list of FileInfo objects (metadata only, no content).

Arguments

Returns

Example

-- List all Markdown files in the 'docs' directory (relative paths)
local doc_files = aip.file.list("*.md", { base_dir = "docs" })
for _, file in ipairs(doc_files) do
  print(file.path) -- e.g., "guide.md", "api.md"
end

-- List all '.aip' files in a specific pack (absolute paths, no detailed meta)
local agent_files = aip.file.list("**/*.aip", {
  base_dir = "ns@pack/",
  absolute = true,
  with_meta = false
})
for _, file in ipairs(agent_files) do
  print(file.path) -- e.g., "/path/to/workspace/.aipack/ns/pack/agent1.aip"
end

-- List text and config files from the workspace root
local config_files = aip.file.list({"*.txt", "*.config"})
for _, file in ipairs(config_files) do
  print(file.path, file.size) -- e.g., "notes.txt", 1024
end

Error

Returns an error (Lua table { error: string }) on invalid arguments, resolution failure, glob matching error, or metadata retrieval error (if with_meta=true).

aip.file.list_load

List and load files (FileRecord) matching glob patterns.

-- API Signature
aip.file.list_load(
  include_globs: string | list<string>,
  options?: {
    base_dir?: string,
    absolute?: boolean
  }
): list<FileRecord>

Finds files matching include_globs patterns within the specified base_dir (or workspace root), loads the content of each matching file, and returns a list of FileRecord objects. Each FileRecord contains both metadata and the file content.

Arguments

Returns

Example

-- Load all Markdown files in the 'docs' directory
local doc_files = aip.file.list_load("*.md", { base_dir = "docs" })
for _, file in ipairs(doc_files) do
  print("--- File:", file.path, "---")
  print(file.content)
end

-- Load all '.aip' files in a specific pack
local agent_files = aip.file.list_load("**/*.aip", { base_dir = "ns@pack/" })
for _, file in ipairs(agent_files) do
  print("Agent Name:", file.stem)
end

Error

Returns an error (Lua table { error: string }) on invalid arguments, resolution failure, glob matching error, or file read/metadata error.

aip.file.first

Find the first file matching glob patterns and return its metadata (FileInfo).

-- API Signature
aip.file.first(
  include_globs: string | list<string>,
  options?: {
    base_dir?: string,
    absolute?: boolean
  }
): FileInfo | nil

Searches for files matching the include_globs patterns within the specified base_dir (or workspace root). It stops searching as soon as the first matching file is found and returns its FileInfo object (metadata only, no content). If no matching file is found, it returns nil.

Arguments

Returns

Example

-- Find the first '.aip' file in a pack
local agent_meta = aip.file.first("*.aip", { base_dir = "ns@pack/" })
if agent_meta then
  print("Found agent:", agent_meta.path)
  -- To load its content:
  -- local agent_file = aip.file.load(agent_meta.path, { base_dir = "ns@pack/" })
  -- print(agent_file.content)
else
  print("No agent file found in pack.")
end

-- Find any config file in the root
local config_meta = aip.file.first({"*.toml", "*.yaml", "*.json"}, { base_dir = "." })
if config_meta then
  print("Config file:", config_meta.name)
end

Error

Returns an error (Lua table { error: string }) on invalid arguments, resolution failure, error during search before first match, or metadata retrieval error for the first match.

aip.file.info

Retrieves file metadata (FileInfo) for the specified path.

-- API Signature
aip.file.info(path: string): FileInfo | nil

If the given path exists, this function returns a FileInfo object containing the file metadata (no content).
If the path cannot be resolved or the file does not exist, it returns nil.

Arguments

Returns

Example

local meta = aip.file.info("README.md")
if meta then
  print("Size:", meta.size)
end

Error

Returns an error only if the path cannot be resolved (invalid pack reference, invalid format, …). If the path resolves successfully but the file does not exist, the function simply returns nil.

aip.file.stats

Calculates aggregate statistics for a set of files matching glob patterns.

-- API Signature
aip.file.stats(
  include_globs: string | list<string> | nil,
  options?: {
    base_dir?: string,
    absolute?: boolean
  }
): FileStats | nil

Finds files matching the include_globs patterns within the specified base_dir (or workspace root) and returns aggregate statistics about these files in a FileStats object. If include_globs is nil or no files match the patterns, returns nil.

Arguments

Returns

If no files if ound a FileStats will all 0 will be returned.

Example

-- Get statistics for all Markdown files in the 'docs' directory
local stats = aip.file.stats("*.md", { base_dir = "docs" })
if stats then
  print("Number of files:", stats.number_of_files)
  print("Total size:", stats.total_size)
  print("First created:", stats.ctime_first)
  print("Last modified:", stats.mtime_last)
end

-- Get statistics for all '.aip' files in a specific pack
local agent_stats = aip.file.stats("**/*.aip", { base_dir = "ns@pack/" })
if agent_stats then
  print("Total agent files:", agent_stats.number_of_files)
end

-- Nil globs return nil
local nil_stats = aip.file.stats(nil)
print(nil_stats) -- Output: nil

Error

Returns an error if:

aip.file.load_json

Load a file, parse its content as JSON, and return the corresponding Lua value.

-- API Signature
aip.file.load_json(path: string): table | value

Loads the file at path (relative to workspace), parses it as JSON, and converts it to a Lua value.

Arguments

Returns

Example

-- Assuming 'config.json' contains {"port": 8080, "enabled": true}
local config = aip.file.load_json("config.json")
print(config.port) -- Output: 8080

Error

Returns an error (Lua table { error: string }) if file not found/read, content is invalid JSON, or conversion fails.

aip.file.load_ndjson

Load a file containing newline-delimited JSON (NDJSON), parse each line, and return a Lua list (table) of the results.

-- API Signature
aip.file.load_ndjson(path: string): list<table>

Loads the file at path (relative to workspace), parses each non-empty line as JSON, and returns a Lua list of the parsed values. Empty lines are skipped.

Arguments

Returns

Example

-- Assuming 'logs.ndjson' contains:
-- {"level": "info", "msg": "Started"}
-- {"level": "warn", "msg": "Low space"}
local logs = aip.file.load_ndjson("logs.ndjson")
print(#logs) -- Output: 2
print(logs[1].msg) -- Output: Started

Error

Returns an error (Lua table { error: string }) if file not found/read, any line has invalid JSON, or conversion fails.

aip.file.append_json_line

Convert a Lua value to a JSON string and append it as a new line to a file.

-- API Signature
aip.file.append_json_line(path: string, data: value)

Converts data to JSON and appends it, followed by a newline (\n), to the file at path (relative to workspace). Creates file/directories if needed.

Arguments

Returns

Example

aip.file.append_json_line("output.ndjson", {user = "test", score = 100})
-- Appends '{"score":100,"user":"test"}\n' to output.ndjson

Error

Returns an error (Lua table { error: string }) on conversion/serialization failure, directory creation failure, or file write/permission error.

aip.file.append_json_lines

Convert a Lua list (table) of values to JSON strings and append them as new lines to a file.

-- API Signature
aip.file.append_json_lines(path: string, data: list)

Iterates through the data list, converts each element to JSON, and appends it followed by a newline (\n) to the file at path (relative to workspace). Creates file/directories if needed. Uses buffering.

Arguments

Returns

Does not return anything upon success.

Example

local users = { {user = "alice"}, {user = "bob"} }
aip.file.append_json_lines("users.ndjson", users)
-- Appends '{"user":"alice"}\n{"user":"bob"}\n'

Error

Returns an error (Lua table { error: string }) if data is not a list, conversion/serialization fails for any element, directory creation fails, or file write/permission error.

aip.file.load_md_sections

Load markdown sections from a file, optionally filtering by specific heading names.

-- API Signature
aip.file.load_md_sections(
  path: string,
  headings?: string | list<string>
): list<MdSection>

Reads the markdown file at path (relative to workspace) and splits it into sections based on headings (#). Returns a list of MdSection objects. Optionally filters by exact heading name (case-sensitive, excluding #).

Arguments

Returns

Example

-- Load all sections
local all_sections = aip.file.load_md_sections("doc/readme.md")

-- Load only the "Summary" section
local summary_section = aip.file.load_md_sections("doc/readme.md", "Summary")

-- Load "Summary" and "Conclusion" sections
local sections = aip.file.load_md_sections("doc/readme.md", {"Summary", "Conclusion"})

Error

Returns an error (Lua table { error: string }) if file not found/read, headings invalid, or parsing/conversion error.

aip.file.load_md_split_first

Splits a markdown file into three parts based on the first heading encountered.

-- API Signature
aip.file.load_md_split_first(path: string): {before: string, first: MdSection, after: string}

Reads the file at path (relative to workspace) and divides it into: content before the first heading (before), the first heading section (first), and content from the second heading onwards (after).

Arguments

Returns

Example

local split = aip.file.load_md_split_first("doc/structure.md")
print("--- BEFORE ---")
print(split.before)
print("--- FIRST Heading Name ---")
print(split.first.heading.name)
print("--- AFTER ---")
print(split.after)

Error

Returns an error (Lua table { error: string }) if file not found/read, or parsing/conversion error.

aip.file.save_html_to_md

Loads an HTML file, converts its content to Markdown, and saves it.

-- API Signature
aip.file.save_html_to_md(
  html_path: string,
  dest?: string | table
): FileInfo

Loads the HTML file at html_path (relative to workspace), converts its content to Markdown, and saves the result. The destination can be specified as a string path or a table of options (DestOptions).

Arguments

Returns

Example

-- Default (replaces .html with .md):
aip.file.save_html_to_md("docs/page.html")
-- Result: docs/page.md

-- Using a custom string path:
aip.file.save_html_to_md("docs/page.html", "out/custom.md")

-- Using options table:
aip.file.save_html_to_md("docs/page.html", {
  base_dir = "output",
  suffix = "_v2",
})
-- Assuming source was 'docs/page.html', result might be 'output/page_v2.md'

Error

Returns an error (Lua table { error: string }) if file I/O, parsing, conversion, or destination resolution fails.

aip.file.save_html_to_slim

Loads an HTML file, "slims" its content (removes scripts, styles, comments, etc.), and saves the slimmed HTML.

-- API Signature
aip.file.save_html_to_slim(
  html_path: string,
  dest?: string | table
): FileInfo

Loads the HTML file at html_path (relative to workspace), removes non-content elements, and saves the cleaned HTML. The destination can be specified as a string path or a table of options (DestOptions).

Arguments

Returns

Example

-- Default (saves as original-slim.html):
aip.file.save_html_to_slim("web/page.html")
-- Result: web/page-slim.html

-- Using a custom string path:
aip.file.save_html_to_slim("web/page.html", "output/slim_page.html")

-- Using options table (base_dir, uses original name):
aip.file.save_html_to_slim("web/page.html", { base_dir = "slim_output" })
-- Assuming source was 'web/page.html', result might be 'slim_output/page.html'

-- Using options table (suffix):
aip.file.save_html_to_slim("web/page.html", { suffix = "_light" })
-- Assuming source was 'web/page.html', result might be 'web/page_light.html'

-- Using options table (no slimming):
aip.file.save_html_to_slim("web/page.html", { slim = false })
-- Result: web/page.html (original content saved)

Error

Returns an error (Lua table { error: string }) if file I/O, slimming, or destination resolution fails.

aip.file.load_html_as_slim

Loads an HTML file, "slims" its content (removes scripts, styles, comments, etc.), and returns the slimmed HTML string.

-- API Signature
aip.file.load_html_as_slim(html_path: string): string

Arguments

Returns

Example

local slim = aip.file.load_html_as_slim("web/page.html")
-- For example, ensure scripts are removed:
print(string.find(slim, "<script") == nil)

Error

Returns an error (Lua table { error: string }) if the HTML file cannot be found/read or if slimming fails.

aip.file.load_html_as_md

Loads an HTML file, optionally "trims" (slims) its content, converts it to Markdown, and returns the Markdown string.

-- API Signature
aip.file.load_html_as_md(
  html_path: string,
  options?: { trim?: boolean } -- default true. When true, slim HTML before converting to Markdown.
): string

Arguments

Returns

Example

-- Default (slims first, then converts)
local md1 = aip.file.load_html_as_md("docs/page.html")

-- No slimming before conversion
local md2 = aip.file.load_html_as_md("docs/page.html", { trim = false })

Error

Returns an error (Lua table { error: string }) if the HTML file cannot be found/read, if slimming fails (when enabled), or if the conversion to Markdown fails.

aip.file.save_docx_to_md

Loads a DOCX file, converts its content to Markdown, and saves it.

-- API Signature
aip.file.save_docx_to_md(
  docx_path: string,
  dest?: string | table
): FileInfo

Arguments

Returns

Example

-- Default (replaces .docx with .md):
aip.file.save_docx_to_md("docs/spec.docx")
-- Result: docs/spec.md

-- Using a custom string path:
aip.file.save_docx_to_md("docs/spec.docx", "out/spec.md")

-- Using options table:
aip.file.save_docx_to_md("docs/spec.docx", {
  base_dir = "output",
  suffix = "_v2",
})
-- Assuming source was 'docs/spec.docx', result might be 'output/spec_v2.md'

Error

Returns an error (Lua table { error: string }) if file I/O, parsing/conversion, or destination resolution fails.

aip.file.load_docx_as_md

Loads a DOCX file, converts its content to Markdown, and returns a Markdown string.

-- API Signature
aip.file.load_docx_as_md(docx_path: string): string

Arguments

Returns

Example

local md = aip.file.load_docx_as_md("docs/spec.docx")
print(string.sub(md, 1, 80)) -- prints the first 80 characters of the converted Markdown

Error

Returns an error (Lua table { error: string }) if the DOCX file cannot be found/read or if the conversion to Markdown fails.

aip.path

Functions for path manipulation, checking, and resolution within the AIPACK workspace.

Functions Summary

aip.path.split(path: string): (parent: string, filename: string)

aip.path.resolve(path: string): string

aip.path.exists(path: string): boolean

aip.path.is_file(path: string): boolean

aip.path.is_dir(path: string): boolean

aip.path.diff(file_path: string, base_path: string): string

aip.path.parent(path: string): string | nil

aip.path.matches_glob(path: string | nil, globs: string | list<string>): boolean | nil

aip.path.join(base: string, ...parts: string | string[]): string

aip.path.parse(path: string | nil): table | nil

Note: Paths are typically relative to the workspace directory unless otherwise specified or resolved using pack references.

aip.path.parse

Parses a path string and returns a FileInfo table representation of its components.

-- API Signature
aip.path.parse(path: string | nil): table | nil

Parses the given path string into a structured table containing components like dir, name, stem, ext, etc., without checking file existence or metadata.

Arguments

Returns

Example

local parsed = aip.path.parse("some/folder/file.txt")
-- parsed will be similar to { path = "some/folder/file.txt", dir = "some/folder", name = "file.txt", stem = "file", ext = "txt", ctime = nil, ... }
print(parsed.name) -- Output: "file.txt"

local nil_result = aip.path.parse(nil)
-- nil_result will be nil

Error

Returns an error (Lua table { error: string }) if the path string is provided but is invalid and cannot be parsed into a valid SPath object.

{
  error: string // Error message
}

aip.path.split

Split path into parent directory and filename.

-- API Signature
aip.path.split(path: string): (parent: string, filename: string)

Splits the given path into its parent directory and filename components.

Arguments

Returns

Example

local parent, filename = aip.path.split("folder/file.txt")
print(parent)   -- Output: "folder"
print(filename) -- Output: "file.txt"

local parent, filename = aip.path.split("justafile.md")
print(parent)   -- Output: ""
print(filename) -- Output: "justafile.md"

Error

Does not typically error.

aip.path.join

Joins a base path with one or more path segments.

-- API Signature
aip.path.join(base: string, ...parts: string | string[]): string

Constructs a new path by appending processed segments from ...parts to the base path. Each argument in ...parts is first converted to a string:

Arguments

Returns

Example

-- Example 1: Basic join
print(aip.path.join("dir1/", "file1.txt"))             -- Output: "dir1/file1.txt"
print(aip.path.join("dir1", "file1.txt"))              -- Output: "dir1/file1.txt"

-- Example 2: Joining with a list (table)
print(aip.path.join("dir1/", {"subdir", "file2.txt"})) -- Output: "dir1/subdir/file2.txt"

-- Example 3: Multiple string arguments
-- Segments are concatenated, then joined to base.
print(aip.path.join("dir1/", "subdir/", "file3.txt"))  -- Output: "dir1/subdir/file3.txt"
print(aip.path.join("dir1/", "subdir", "file3.txt"))   -- Output: "dir1/subdirfile3.txt"

-- Example 4: Mixed arguments (strings and lists)
-- Lists are pre-joined with '/', then all resulting strings are concatenated, then joined to base.
print(aip.path.join("root/", {"user", "docs"}, "projectA", {"report", "final.pdf"}))
-- Output: "root/user/docsprojectAreport/final.pdf"

-- Example 5: Normalization
print(aip.path.join("", {"my-dir//", "///file.txt"}))  -- Output: "my-dir/file.txt"
print(aip.path.join("a", "b", "c"))                     -- Output: "a/bc"
print(aip.path.join("a/", "b/", "c/"))                  -- Output: "a/b/c/"

Error

Returns an error (Lua table { error: string }) if any of the parts arguments cannot be converted to a string or a list of strings (e.g., passing a boolean or a function).

aip.path.resolve

Resolves and normalizes a path relative to the workspace or pack structure.

-- API Signature
aip.path.resolve(path: string): string

Resolves relative paths (., ..), absolute paths, and pack references (ns@pack/, ns@pack$base/, ns@pack$workspace/) to a normalized, typically absolute, path.

Arguments

Returns

Example

local resolved_path = aip.path.resolve("./agent-script/../agent.aip")
-- Output: /path/to/workspace/agent.aip (example)

local resolved_pack_path = aip.path.resolve("ns@pack/some/file.txt")
-- Output: /path/to/aipack-base/packs/ns/pack/some/file.txt (example)

Error

Returns an error (Lua table { error: string }) if the path cannot be resolved (e.g., invalid pack reference, invalid format).

aip.path.exists

Checks if the specified path exists (file or directory).

-- API Signature
aip.path.exists(path: string): boolean

Checks existence after resolving the path relative to the workspace or pack structure.

Arguments

Returns

Example

if aip.path.exists("README.md") then print("Exists") end
if aip.path.exists("ns@pack/main.aip") then print("Pack agent exists") end

Error

Returns an error (Lua table { error: string }) if the path cannot be resolved.

aip.path.is_file

Checks if the specified path points to an existing file.

-- API Signature
aip.path.is_file(path: string): boolean

Checks after resolving the path relative to the workspace or pack structure.

Arguments

Returns

Example

if aip.path.is_file("config.toml") then print("Is a file") end

Error

Returns an error (Lua table { error: string }) if the path cannot be resolved.

aip.path.is_dir

Checks if the specified path points to an existing directory.

-- API Signature
aip.path.is_dir(path: string): boolean

Checks after resolving the path relative to the workspace or pack structure.

Arguments

Returns

Example

if aip.path.is_dir("src/") then print("Is a directory") end

Error

Returns an error (Lua table { error: string }) if the path cannot be resolved.

aip.path.diff

Computes the relative path from base_path to file_path.

-- API Signature
aip.path.diff(file_path: string, base_path: string): string

Calculates the relative path string that navigates from base_path to file_path.

Arguments

Returns

Example

print(aip.path.diff("/a/b/c/file.txt", "/a/b/")) -- Output: "c/file.txt"
print(aip.path.diff("/a/b/", "/a/b/c/file.txt")) -- Output: "../.."
print(aip.path.diff("folder/file.txt", "folder")) -- Output: "file.txt"

Error

Returns an error (Lua table { error: string }) if paths are invalid.

aip.path.parent

Returns the parent directory path of the specified path.

-- API Signature
aip.path.parent(path: string): string | nil

Gets the parent directory component.

Arguments

Returns

Example

print(aip.path.parent("some/path/file.txt")) -- Output: "some/path"
print(aip.path.parent("."))                  -- Output: nil

Error

Does not typically error.

aip.path.matches_glob

Checks if a path matches one or more glob patterns.

-- API Signature
aip.path.matches_glob(path: string | nil, globs: string | list<string>): boolean | nil

Determines whether the provided path matches any of the glob patterns given in globs. The function returns nil when path is nil.
If globs is an empty string or an empty list, the result is false.

Arguments

Returns

Example

-- Single pattern
print(aip.path.matches_glob("src/main.rs", "**/*.rs"))            -- true

-- Multiple patterns
print(aip.path.matches_glob("README.md", {"*.md", "*.txt"}))      -- true

-- No match
print(aip.path.matches_glob("image.png", {"*.jpg", "*.gif"}))     -- false

-- Nil path
print(aip.path.matches_glob(nil, "*.rs"))                         -- nil

Error

Returns an error (Lua table { error: string }) if globs is not a string or a list of strings.

aip.text

Text manipulation functions for cleaning, splitting, modifying, and extracting text content.

Functions Summary

aip.text.escape_decode(content: string | nil): string | nil

aip.text.escape_decode_if_needed(content: string | nil): string | nil

aip.text.split_first(content: string | nil, sep: string): (string | nil, string | nil)

aip.text.split_last(content: string | nil, sep: string): (string | nil, string | nil)

aip.text.remove_first_line(content: string | nil): string | nil

aip.text.remove_first_lines(content: string | nil, n: number): string | nil

aip.text.remove_last_line(content: string | nil): string | nil

aip.text.remove_last_lines(content: string | nil, n: number): string | nil

aip.text.trim(content: string | nil): string | nil

aip.text.trim_start(content: string | nil): string | nil

aip.text.trim_end(content: string | nil): string | nil

aip.text.remove_last_lines(content: string | nil, n: number): string | nil

aip.text.truncate(content: string | nil, max_len: number, ellipsis?: string): string | nil

aip.text.replace_markers(content: string | nil, new_sections: list): string | nil

aip.text.ensure(content: string | nil, {prefix?: string, suffix?: string}): string | nil

aip.text.ensure_single_ending_newline(content: string | nil): string | nil

aip.text.format_size(bytes: integer | nil, lowest_size_unit?: "B" | "KB" | "MB" | "GB"): string | nil -- lowest_size_unit default "B"

aip.text.extract_line_blocks(content: string | nil, options: {starts_with: string, extrude?: "content", first?: number}): (list<string> | nil, string | nil)

aip.text.split_first_line(content: string | nil, sep: string): (string | nil, string | nil)

aip.text.split_last_line(content: string | nil, sep: string): (string | nil, string | nil)

aip.text.escape_decode

HTML-decodes the entire content string. If content is nil, returns nil.

-- API Signature
aip.text.escape_decode(content: string | nil): string | nil

Useful for decoding responses from LLMs that might HTML-encode output.

Arguments

Returns

Error

Returns an error (Lua table { error: string }) if decoding fails (and content was not nil).

aip.text.escape_decode_if_needed

Selectively HTML-decodes content if needed (currently only decodes &lt;). If content is nil, returns nil.

-- API Signature
aip.text.escape_decode_if_needed(content: string | nil): string | nil

A more conservative version of escape_decode for cases where only specific entities need decoding.

Arguments

Returns

Error

Returns an error (Lua table { error: string }) if decoding fails (and content was not nil).

aip.text.split_first

Splits a string into two parts based on the first occurrence of a separator. If content is nil, returns (nil, nil).

-- API Signature
aip.text.split_first(content: string | nil, sep: string): (string | nil, string | nil)

Arguments

Returns

Example

local content = "first part===second part"
local first, second = aip.text.split_first(content, "===")
-- first = "first part"
-- second = "second part"

Error

This function does not typically error.

aip.text.split_last

Splits a string into two parts based on the last occurrence of a separator. If content is nil, returns (nil, nil).

-- API Signature
aip.text.split_last(content: string | nil, sep: string): (string | nil, string | nil)

Arguments

Returns

Example

local content = "some == text == more"
local first, second = aip.text.split_last(content, "==")
-- first = "some == text "
-- second = " more"

local content = "no separator here"
local first, second = aip.text.split_last(content, "++")
-- first = "no separator here"
-- second = nil

Error

This function does not typically error.

aip.text.remove_first_line

Removes the first line from the content. If content is nil, returns nil.

-- API Signature
aip.text.remove_first_line(content: string | nil): string | nil

Arguments

Returns

Error

This function does not typically error.

aip.text.remove_first_lines

Removes the first n lines from the content. If content is nil, returns nil.

-- API Signature
aip.text.remove_first_lines(content: string | nil, n: number): string | nil

Arguments

Returns

Error

This function does not typically error.

aip.text.remove_last_line

Removes the last line from the content. If content is nil, returns nil.

-- API Signature
aip.text.remove_last_line(content: string | nil): string | nil

Arguments

Returns

Error

This function does not typically error.

aip.text.remove_last_lines

Removes the last n lines from the content. If content is nil, returns nil.

-- API Signature
aip.text.remove_last_lines(content: string | nil, n: number): string | nil

Arguments

Returns

Error

This function does not typically error.

aip.text.trim

Trims leading and trailing whitespace from a string. If content is nil, returns nil.

-- API Signature
aip.text.trim(content: string | nil): string | nil

Arguments

Returns

Error

This function does not typically error.

aip.text.trim_start

Trims leading whitespace from a string. If content is nil, returns nil.

-- API Signature
aip.text.trim_start(content: string | nil): string | nil

Arguments

Returns

Error

This function does not typically error.

aip.text.trim_end

Trims trailing whitespace from a string. If content is nil, returns nil.

-- API Signature
aip.text.trim_end(content: string | nil): string | nil

Arguments

Returns

Error

This function does not typically error.

aip.text.truncate

Truncates content to a maximum length, optionally adding an ellipsis. If content is nil, returns nil.

-- API Signature
aip.text.truncate(content: string | nil, max_len: number, ellipsis?: string): string | nil

If content length exceeds max_len, truncates and appends ellipsis (if provided).

Arguments

Returns

Error

This function does not typically error.

aip.text.replace_markers

Replaces <<START>>...<<END>> markers in content with corresponding sections. If content is nil, returns nil.

-- API Signature
aip.text.replace_markers(content: string | nil, new_sections: list): string | nil

Replaces occurrences of <<START>>...<<END>> blocks sequentially with items from new_sections. Items in new_sections can be strings or tables with a .content field.

Arguments

Returns

Error

This function does not typically error.

aip.text.ensure

Ensures the content starts with prefix and/or ends with suffix. If content is nil, returns nil.

-- API Signature
aip.text.ensure(content: string | nil, {prefix?: string, suffix?: string}): string | nil

Adds the prefix/suffix only if the content doesn't already start/end with it.

Arguments

Returns

Error

This function does not typically error.

aip.text.ensure_single_ending_newline

Ensures the content ends with exactly one newline character (\n). If content is nil, returns nil.

-- API Signature
aip.text.ensure_single_ending_newline(content: string | nil): string | nil

Removes trailing whitespace and adds a single newline if needed. Returns \n if content is empty. Useful for code normalization.

Arguments

Returns

Error

This function does not typically error.

aip.text.format_size

Formats a byte count (in bytes) into a human-readable, fixed-width string (9 characters, right-aligned).
If bytes is nil, the function returns nil.

Optional lowest unit size to be used (by default "B" for Bytes)

-- API Signature
aip.text.format_size(bytes: integer | nil, lowest_size_unit?: "B" | "KB" | "MB" | "GB"): string | nil

Examples

aip.text.format_size(777)          -- "   777 B "
aip.text.format_size(8_777)        -- "  8.78 KB"
aip.text.format_size(5_242_880)    -- "  5.24 MB"
aip.text.format_size(nil)          -- nil

aip.text.extract_line_blocks

Extracts consecutive lines starting with a specific prefix. If content is nil, returns (nil, nil).

-- API Signature
aip.text.extract_line_blocks(content: string | nil, options: {starts_with: string, extrude?: "content", first?: number}): (list<string> | nil, string | nil)

Extracts blocks of consecutive lines from content where each line begins with options.starts_with.

Arguments

Returns

Example

local text = "> Block 1 Line 1\n> Block 1 Line 2\nSome other text\n> Block 2"
local blocks, remain = aip.text.extract_line_blocks(text, {starts_with = ">", extrude = "content"})
-- blocks = { "> Block 1 Line 1\n> Block 1 Line 2", "> Block 2" }
-- remain = "Some other text\n"

Error

Returns an error (Lua table { error: string }) if arguments are invalid (and content was not nil).

aip.text.split_first_line

Splits a string into two parts based on the first line that exactly matches the separator. If content is nil, returns (nil, nil). If no line matches, returns (original_content, nil).

-- API Signature
aip.text.split_first_line(content: string | nil, sep: string): (string | nil, string | nil)

The separator line itself is not included in either part.

Arguments

Returns

Example

local text = "line one\n---\nline two\n---\nline three"
local first, second = aip.text.split_first_line(text, "---")
-- first = "line one"
-- second = "line two\n---\nline three"

local first, second = aip.text.split_first_line("START\ncontent", "START")
-- first = ""
-- second = "content"

local first, second = aip.text.split_first_line("no separator", "---")
-- first = "no separator"
-- second = nil

Error

This function does not typically error.

aip.text.split_last_line

Splits a string into two parts based on the last line that exactly matches the separator. If content is nil, returns (nil, nil). If no line matches, returns (original_content, nil).

-- API Signature
aip.text.split_last_line(content: string | nil, sep: string): (string | nil, string | nil)

The separator line itself is not included in either part.

Arguments

Returns

Example

local text = "line one\n---\nline two\n---\nline three"
local first, second = aip.text.split_last_line(text, "---")
-- first = "line one\n---\nline two"
-- second = "line three"

local first, second = aip.text.split_last_line("content\nEND", "END")
-- first = "content"
-- second = ""

local first, second = aip.text.split_last_line("no separator", "---")
-- first = "no separator"
-- second = nil

Error

This function does not typically error.

aip.md

Markdown processing functions for extracting structured information like code blocks and metadata.

Functions Summary

aip.md.extract_blocks(md_content: string): list<MdBlock>

aip.md.extract_blocks(md_content: string, lang: string): list<MdBlock>

aip.md.extract_blocks(md_content: string, {lang?: string, extrude: "content"}): (list<MdBlock>, string)

aip.md.extract_meta(md_content: string | nil): (table | nil, string | nil)

aip.md.outer_block_content_or_raw(md_content: string): string

aip.md.extract_blocks

Extracts fenced code blocks (MdBlock) from markdown content.

-- API Signatures
-- Extract all blocks:
aip.md.extract_blocks(md_content: string): list<MdBlock>
-- Extract blocks by language:
aip.md.extract_blocks(md_content: string, lang: string): list<MdBlock>
-- Extract blocks and remaining content:
aip.md.extract_blocks(md_content: string, {lang?: string, extrude: "content"}): (list<MdBlock>, string)

Parses md_content and extracts fenced code blocks ( ).

Arguments

Returns

Example

local md = "```rust\nfn main() {}\n```\nSome text.\n```lua\nprint('hi')\n```"
local rust_blocks = aip.md.extract_blocks(md, "rust")
-- rust_blocks = { { content = "fn main() {}", lang = "rust", info = "" } }

local lua_blocks, remain = aip.md.extract_blocks(md, {lang = "lua", extrude = "content"})
-- lua_blocks = { { content = "print('hi')", lang = "lua", info = "" } }
-- remain = "Some text.\n" (approx.)

Error

Returns an error (Lua table { error: string }) on invalid options or parsing errors.

aip.md.extract_meta

Extracts and merges metadata from #!meta TOML blocks.

-- API Signature
aip.md.extract_meta(md_content: string | nil): (table | nil, string | nil)

Finds all toml #!meta ... blocks, parses their TOML content, merges them into a single Lua table, and returns the table along with the original content stripped of the meta blocks.

Arguments

Returns

If md_content the return will be (nil, nil)

Example

local content = "Intro.\n```toml\n#!meta\ntitle=\"T\"\n```\nMain.\n```toml\n#!meta\nauthor=\"A\"\n```"
local meta, remain = aip.md.extract_meta(content)
-- meta = { title = "T", author = "A" }
-- remain = "Intro.\n\nMain.\n" (approx.)

Error

Returns an error (Lua table { error: string }) if any meta block contains invalid TOML.

aip.md.outer_block_content_or_raw

Extracts content from the outermost code block, or returns raw content.

-- API Signature
aip.md.outer_block_content_or_raw(md_content: string): string

If md_content starts and ends with a fenced code block (```), returns the content inside. Otherwise, returns the original md_content. Useful for processing LLM responses.

Arguments

Returns

Example

local block = "```rust\ncontent\n```"
local raw = "no block"
print(aip.md.outer_block_content_or_raw(block)) -- Output: "content\n"
print(aip.md.outer_block_content_or_raw(raw))   -- Output: "no block"

aip.json

JSON parsing and stringification functions.

Functions Summary

aip.json.parse(content: string): table | value

aip.json.parse_ndjson(content: string): list<table>

aip.json.stringify(content: table): string

aip.json.stringify_pretty(content: table): string

aip.json.stringify_to_line(content: table): string -- Deprecated alias for `stringify`

aip.json.parse

Parse a JSON string into a Lua table or value.

-- API Signature
aip.json.parse(content: string): table | value

Arguments

Returns

Example

local obj = aip.json.parse('{"name": "John", "age": 30}')
print(obj.name) -- Output: John

Error

Returns an error (Lua table { error: string }) if content is not valid JSON.

aip.json.parse_ndjson

Parse a newline-delimited JSON (NDJSON) string into a list of tables/values.

-- API Signature
aip.json.parse_ndjson(content: string): list<table>

Parses each non-empty line as a separate JSON object/value.

Arguments

Returns

Example

local ndjson = '{"id":1}\n{"id":2}'
local items = aip.json.parse_ndjson(ndjson)
print(items[1].id) -- Output: 1
print(items[2].id) -- Output: 2

Error

Returns an error (Lua table { error: string }) if any line contains invalid JSON.

aip.json.stringify

Stringify a Lua table/value into a compact, single-line JSON string.

-- API Signature
aip.json.stringify(content: table): string

Arguments

Returns

Example

local obj = {name = "John", age = 30}
local json_str = aip.json.stringify(obj)
-- json_str = '{"age":30,"name":"John"}' (order may vary)

Error

Returns an error (Lua table { error: string }) if content cannot be serialized.

aip.json.stringify_pretty

Stringify a Lua table/value into a pretty-formatted JSON string (2-space indent).

-- API Signature
aip.json.stringify_pretty(content: table): string

Arguments

Returns

Example

local obj = {name = "John", age = 30}
local json_str = aip.json.stringify_pretty(obj)
-- json_str =
-- {
--   "age": 30,
--   "name": "John"
-- } (order may vary)

Error

Returns an error (Lua table { error: string }) if content cannot be serialized.

aip.json.stringify_to_line (Deprecated)

Deprecated alias for aip.json.stringify.

-- API Signature
aip.json.stringify_to_line(content: table): string

aip.web

Functions for making HTTP GET and POST requests, and for URL manipulation.

Functions Summary

aip.web.get(url: string): WebResponse

aip.web.post(url: string, data: string | table): WebResponse

aip.web.parse_url(url: string | nil): table | nil

aip.web.resolve_href(href: string | nil, base_url: string): string | nil

aip.web.get

Makes an HTTP GET request.

-- API Signature
aip.web.get(url: string): WebResponse

Arguments

Returns

Example

local response = aip.web.get("https://httpbin.org/get")
if response.success then
  print("Status:", response.status)
  -- response.content might be a string or table (if JSON)
  print("Content Type:", type(response.content))
else
  print("Error:", response.error, "Status:", response.status)
end

Error

Returns an error (Lua table { error: string }) if the request cannot be initiated (e.g., network error, invalid URL). Check response.success for HTTP-level errors (non-2xx status).

aip.web.post

Makes an HTTP POST request.

-- API Signature
aip.web.post(url: string, data: string | table): WebResponse

Sends data in the request body. If data is a string, Content-Type is text/plain. If data is a table, it's serialized to JSON and Content-Type is application/json.

Arguments

Returns

Example

-- POST plain text
local r1 = aip.web.post("https://httpbin.org/post", "plain text data")

-- POST JSON
local r2 = aip.web.post("https://httpbin.org/post", { key = "value", num = 123 })
if r2.success and type(r2.content) == "table" then
  print("Received JSON echo:", r2.content.json.key) -- Output: value
end

Error

Returns an error (Lua table { error: string }) if the request cannot be initiated or data serialization fails. Check response.success for HTTP-level errors.

aip.web.parse_url

Parses a URL string and returns its components as a table.

-- API Signature
aip.web.parse_url(url: string | nil): table | nil

Parses the given URL string and extracts its various components.

Arguments

Returns

(table | nil)

Example

local parsed = aip.web.parse_url("https://user:pass@example.com:8080/path/to/page.html?param1=val#fragment")
if parsed then
  print(parsed.scheme)       -- "https"
  print(parsed.host)         -- "example.com"
  print(parsed.port)         -- 8080
  print(parsed.path)         -- "/path/to/page.html"
  print(parsed.query.param1) -- "val"
  print(parsed.fragment)     -- "fragment"
  print(parsed.username)     -- "user"
  print(parsed.password)     -- "pass"
  print(parsed.url)          -- "https://user:pass@example.com:8080/path/to/page.html?query=val#fragment"
  print(parsed.page_url)     -- "https://user:pass@example.com:8080/path/to/page.html"
end

local nil_result = aip.web.parse_url(nil)
-- nil_result will be nil

Error

Returns an error (Lua table { error: string }) if the url string is provided but is invalid and cannot be parsed.

aip.web.resolve_href

Resolves an href (like one from an HTML <a> tag) against a base_url.

-- API Signature
aip.web.resolve_href(href: string | nil, base_url: string): string | nil

Arguments

Returns

(string | nil)

Example

local base = "https://example.com/docs/path/"

-- Absolute href
print(aip.web.resolve_href("https://another.com/page.html", base))
-- Output: "https://another.com/page.html"

-- Relative path href
print(aip.web.resolve_href("sub/page.html", base))
-- Output: "https://example.com/docs/path/sub/page.html"

-- Absolute path href
print(aip.web.resolve_href("/other/resource.txt", base))
-- Output: "https://example.com/other/resource.txt"

-- Scheme-relative href
print(aip.web.resolve_href("//cdn.com/asset.js", base))
-- Output: "https://cdn.com/asset.js" (uses base_url's scheme)

print(aip.web.resolve_href("//cdn.com/asset.js", "http://example.com/"))
-- Output: "http://cdn.com/asset.js"

-- href is nil
print(aip.web.resolve_href(nil, base))
-- Output: nil (Lua nil)

Error

Returns an error (Lua table { error: string }) if:

aip.uuid

The aip.uuid module exposes functions for generating various UUIDs and converting timestamped UUIDs.

Functions Summary

aip.uuid.new(): string
aip.uuid.new_v4(): string
aip.uuid.new_v7(): string
aip.uuid.new_v4_b64(): string
aip.uuid.new_v4_b64u(): string
aip.uuid.new_v4_b58(): string
aip.uuid.new_v7_b64(): string
aip.uuid.new_v7_b64u(): string
aip.uuid.new_v7_b58(): string
aip.uuid.to_time_epoch_ms(value: string | nil): integer | nil

aip.uuid.new

Generates a new UUID version 4. This is an alias for aip.uuid.new_v4().

-- API Signature
aip.uuid.new(): string

Returns

string: The generated UUIDv4 as a string (e.g., "f47ac10b-58cc-4372-a567-0e02b2c3d479").

Example

local id = aip.uuid.new()
print(id)

aip.uuid.new_v4

Generates a new UUID version 4.

-- API Signature
aip.uuid.new_v4(): string

Returns

string: The generated UUIDv4 as a string (e.g., "f47ac10b-58cc-4372-a567-0e02b2c3d479").

Example

local id_v4 = aip.uuid.new_v4()
print(id_v4)

aip.uuid.new_v7

Generates a new UUID version 7 (time-ordered).

-- API Signature
aip.uuid.new_v7(): string

Returns

string: The generated UUIDv7 as a string.

Example

local id_v7 = aip.uuid.new_v7()
print(id_v7)

aip.uuid.new_v4_b64

Generates a new UUID version 4 and encodes it using standard Base64.

-- API Signature
aip.uuid.new_v4_b64(): string

Returns

string: The Base64 encoded UUIDv4 string.

Example

local id_v4_b64 = aip.uuid.new_v4_b64()
print(id_v4_b64)

aip.uuid.new_v4_b64u

Generates a new UUID version 4 and encodes it using URL-safe Base64 without padding.

-- API Signature
aip.uuid.new_v4_b64u(): string

Returns

string: The URL-safe Base64 encoded (no padding) UUIDv4 string.

Example

local id_v4_b64u = aip.uuid.new_v4_b64u()
print(id_v4_b64u)

aip.uuid.new_v4_b58

Generates a new UUID version 4 and encodes it using Base58.

-- API Signature
aip.uuid.new_v4_b58(): string

Returns

string: The Base58 encoded UUIDv4 string.

Example

local id_v4_b58 = aip.uuid.new_v4_b58()
print(id_v4_b58)

aip.uuid.new_v7_b64

Generates a new UUID version 7 and encodes it using standard Base64.

-- API Signature
aip.uuid.new_v7_b64(): string

Returns

string: The Base64 encoded UUIDv7 string.

Example

local id_v7_b64 = aip.uuid.new_v7_b64()
print(id_v7_b64)

aip.uuid.new_v7_b64u

Generates a new UUID version 7 and encodes it using URL-safe Base64 without padding.

-- API Signature
aip.uuid.new_v7_b64u(): string

Returns

string: The URL-safe Base64 encoded (no padding) UUIDv7 string.

Example

local id_v7_b64u = aip.uuid.new_v7_b64u()
print(id_v7_b64u)

aip.uuid.new_v7_b58

Generates a new UUID version 7 and encodes it using Base58.

-- API Signature
aip.uuid.new_v7_b58(): string

Returns

string: The Base58 encoded UUIDv7 string.

Example

local id_v7_b58 = aip.uuid.new_v7_b58()
print(id_v7_b58)

aip.uuid.to_time_epoch_ms

Converts a timestamped UUID string (V1, V6, V7) to milliseconds since Unix epoch. Returns nil if the input is nil, not a valid UUID string, or if the UUID type does not contain an extractable timestamp (e.g., V4).

-- API Signature
aip.uuid.to_time_epoch_ms(value: string | nil): integer | nil

Arguments

Returns

integer | nil: Milliseconds since Unix epoch, or nil.

Example

local v7_uuid_str = aip.uuid.new_v7()
local millis = aip.uuid.to_time_epoch_ms(v7_uuid_str)
if millis then
  print("Timestamp in ms: " .. millis)
else
  print("Could not extract timestamp.")
end

local v4_uuid_str = aip.uuid.new_v4()
local millis_v4 = aip.uuid.to_time_epoch_ms(v4_uuid_str)
-- millis_v4 will be nil

local invalid_millis = aip.uuid.to_time_epoch_ms("not-a-uuid")
-- invalid_millis will be nil

local nil_millis = aip.uuid.to_time_epoch_ms(nil)
-- nil_millis will be nil

aip.time

aip.time.now_iso_utc(): string            -- RFC 3339 UTC (seconds precision)

aip.time.now_iso_local(): string          -- RFC 3339 local time (seconds precision)

aip.time.now_iso_utc_micro(): string      -- RFC 3339 UTC (microseconds)

aip.time.now_iso_local_micro(): string    -- RFC 3339 local time (microseconds)

aip.time.now_utc_micro(): integer         -- epoch microseconds (UTC)

aip.time.today_utc(): string              -- "YYYY-MM-DD" (UTC)

aip.time.today_local(): string            -- "YYYY-MM-DD" (local)

aip.lua

Lua value inspection functions.

Functions Summary

aip.lua.dump(value: any): string

aip.lua.dump

Dump a Lua value into its string representation.

-- API Signature
aip.lua.dump(value: any): string

Provides a detailed string representation of any Lua value, useful for debugging.

Arguments

Returns

Example

local tbl = { key = "value", nested = { num = 42 } }
print(aip.lua.dump(tbl))
-- Output: Example: table: 0x... { key = "value", nested = table: 0x... { num = 42 } }

Error

Returns an error (Lua table { error: string }) if the value cannot be converted to string.

aip.agent

Functions for running other AIPACK agents from within a Lua script.

Functions Summary

aip.agent.run(agent_name: string, options?: table): any

aip.agent.extract_options(value: any): table | nil

aip.agent.run

Runs another agent and returns its response.

-- API Signature
aip.agent.run(agent_name: string, options?: table): any

Executes the agent specified by agent_name. The function waits for the called agent to complete and returns its result. This allows for chaining agents together.

Arguments

Input Examples:
-- Run an agent with a single string input
local response = aip.agent.run("agent-name", { inputs = "hello" })

-- Run an agent with multiple string inputs
local response = aip.agent.run("agent-name", { inputs = {"input1", "input2"} })

-- Run an agent with structured inputs (e.g., file records)
local response = aip.agent.run("agent-name", {
  inputs = {
    { path = "file1.txt", content = "..." },
    { path = "file2.txt", content = "..." }
  }
})

Returns

The result of the agent execution. The type of the returned value depends on the agent's output:

// Example structure of a returned AiResponse object (if no output script)
{
  action: string, // e.g., "PrintToConsole", "WriteFiles"
  outputs: any,   // Depends on the action/output
  options: table  // Options used during the run
  // ... other properties from AiResponse
}

Error

Returns an error if:

{
  error: string // Error message
}

aip.agent.extract_options

Extracts relevant agent options from a given Lua value.

-- API Signature
aip.agent.extract_options(value: any): table | nil

If the input value is a Lua table, this function creates a new table and copies the following properties if they exist in the input table:

Other properties are ignored. If the input value is nil or not a table, the function returns nil.

Arguments

Returns

A new Lua table containing the extracted options, or nil if the input was nil or not a table.

aip.task

Functions for recording pins at the task level (attached to the current task of the current run).

Functions Summary

aip.task.pin(iden: string, content: any)
aip.task.pin(iden: string, priority: number, content: any)

aip.task.pin

Creates a pin attached to the current task. Requires that both CTX.RUN_UID and CTX.TASK_UID are available (i.e., must be called during a task cycle, not in before_all or after_all).

-- API Signatures
aip.task.pin(iden: string, content: any)
aip.task.pin(iden: string, priority: number, content: any)

Records a pin for the current task. When the optional priority is provided, it will be stored along with the pin.

Arguments

Returns

Example

-- Simple pin (no priority)
aip.task.pin("review", "Needs follow-up")

-- Pin with priority
aip.task.pin("checkpoint", 0.7, { step = 3, note = "after validation" })

Error

Returns an error (Lua table { error: string }) if called outside a task context (no CTX.TASK_UID), if there is no run context, or if arguments are invalid.

aip.run

Functions for recording pins at the run level (attached to the overall run).

Functions Summary

aip.run.pin(iden: string, content: any)
aip.run.pin(iden: string, priority: number, content: any)

aip.run.pin

Creates a pin attached to the current run. Requires that CTX.RUN_UID is available.

-- API Signatures
aip.run.pin(iden: string, content: any)
aip.run.pin(iden: string, priority: number, content: any)

Records a pin for the current run. When the optional priority is provided, it will be stored along with the pin.

Arguments

Returns

Example

-- Simple pin (no priority)
aip.run.pin("summary", "Run started successfully")

-- Pin with priority
aip.run.pin("quality-score", 0.85, { score = 0.85, rationale = "good coverage" })

Error

Returns an error (Lua table { error: string }) if there is no run context (no CTX.RUN_UID) or if arguments are invalid.

aip.flow

Functions for controlling the AIPACK agent execution flow from within script blocks (before_all, data).

Functions Summary

aip.flow.before_all_response(data: BeforeAllData) -> table

aip.flow.data_response(data: DataData) -> table

aip.flow.skip(reason?: string): table

These functions return special tables that instruct the agent executor how to proceed. They should be the return value of the script block.

aip.flow.before_all_response

Customizes execution flow at the 'Before All' stage (in before_all script block).

-- API Signature
aip.flow.before_all_response(data: BeforeAllData) -> table

This function is typically called within the before_all block of an agent script to override the default behavior of passing all initial inputs to the agent.

Arguments

Example

local result = aip.flow.before_all_response({
  inputs = {"processed_input_1", "processed_input_2"},
  options = {
    model = "gemini-2.5-flash",
    input_concurrency = 3
  },
  before_all = {some_data = "hello world" } -- Arbitrary data is allowed
})
-- The agent executor will process this result table.

Error

This function does not directly return any errors. Errors might occur during the creation of lua table.

aip.flow.data_response

Customizes execution flow at the 'Data' stage for a single input (in data script block).

-- API Signature
aip.flow.data_response(data: DataData) -> table

This function is typically called within the data block of an agent script. It allows overriding the input and/or options for the current input cycle, or returning additional arbitrary data.

Arguments

Example

-- Use a transformed input and override the model for this cycle
return aip.flow.data_response({
  data  = data,              -- The data that would have been returned
  input = transformed_input,
  options = { model = "gpt-4o" },
})
-- The agent executor will process this result table.

Error

This function does not directly return any errors. Errors might occur during the creation of lua table.

aip.flow.skip

Skips processing the current input cycle (in data script block).

-- API Signature
aip.flow.skip(reason?: string): table

This function is typically called within the data block of an agent script to instruct AIPACK to skip processing the current input value and move to the next one.

Arguments

Example

-- Skip processing if the input is nil or empty
if input == nil or input == "" then
  return aip.flow.skip("Input is empty")
end
-- Continue processing the input if not skipped
-- ... rest of data block ...

Error

This function does not directly return any errors. Errors might occur during the creation of lua table.

aip.cmd

Functions for executing system commands.

Functions Summary

aip.cmd.exec(cmd_name: string, args?: string | list<string>): CmdResponse | {error: string, stdout?: string, stderr?: string, exit?: number}

aip.cmd.exec

Execute a system command with optional arguments.

-- API Signature
aip.cmd.exec(cmd_name: string, args?: string | list<string>): CmdResponse | {error: string, stdout?: string, stderr?: string, exit?: number}

Executes the command using the system shell. On Windows, wraps with cmd /C.

Arguments

Returns

Example

-- Single string argument
local r1 = aip.cmd.exec("echo", "hello world")
print("stdout:", r1.stdout) -- Output: hello world\n (or similar)
print("exit:", r1.exit)   -- Output: 0

-- Table of arguments
local r2 = aip.cmd.exec("ls", {"-l", "-a", "nonexistent"})
print("stderr:", r2.stderr) -- Output: ls: nonexistent: No such file... (or similar)
print("exit:", r2.exit)   -- Output: non-zero exit code

-- Example of potential error return (e.g., command not found)
local r3 = aip.cmd.exec("nonexistent_command")
if type(r3) == "table" and r3.error then
  print("Execution Error:", r3.error)
end

Error

Returns an error (Lua table { error: string, stdout?: string, stderr?: string, exit?: number }) only if the process fails to start (e.g., command not found, permission issue). Non-zero exit codes from the command itself are captured in the CmdResponse and do not cause a Lua error by default.

aip.semver

Functions for semantic versioning (SemVer 2.0.0) operations.

Functions Summary

aip.semver.compare(version1: string, operator: string, version2: string): boolean | {error: string}

aip.semver.parse(version: string): {major: number, minor: number, patch: number, prerelease: string | nil, build: string | nil} | {error: string}

aip.semver.is_prerelease(version: string): boolean | {error: string}

aip.semver.valid(version: string): boolean

aip.semver.compare

Compares two version strings using an operator.

-- API Signature
aip.semver.compare(version1: string, operator: string, version2: string): boolean | {error: string}

Compares versions according to SemVer rules (prerelease < release, build metadata ignored).

Arguments

Returns

Example

print(aip.semver.compare("1.2.3", ">", "1.2.0"))     -- Output: true
print(aip.semver.compare("1.0.0-alpha", "<", "1.0.0")) -- Output: true
print(aip.semver.compare("1.0.0+build", "==", "1.0.0")) -- Output: true

local r = aip.semver.compare("abc", ">", "1.0.0")
if type(r) == "table" and r.error then
  print("Error:", r.error)
end

Error

Returns an error (Lua table { error: string }) if operator is invalid or versions are not valid SemVer strings.

aip.semver.parse

Parses a version string into its components.

-- API Signature
aip.semver.parse(version: string): {major: number, minor: number, patch: number, prerelease: string | nil, build: string | nil} | {error: string}

Arguments

Returns

Example

local v = aip.semver.parse("1.2.3-beta.1+build.123")
print(v.major, v.minor, v.patch) -- Output: 1 2 3
print(v.prerelease)             -- Output: beta.1
print(v.build)                  -- Output: build.123

local r = aip.semver.parse("invalid")
if type(r) == "table" and r.error then
  print("Error:", r.error)
end

Error

Returns an error (Lua table { error: string }) if version is not a valid SemVer string.

aip.semver.is_prerelease

Checks if a version string has a prerelease component.

-- API Signature
aip.semver.is_prerelease(version: string): boolean | {error: string}

Arguments

Returns

Example

print(aip.semver.is_prerelease("1.2.3-beta"))      -- Output: true
print(aip.semver.is_prerelease("1.2.3"))         -- Output: false
print(aip.semver.is_prerelease("1.0.0+build")) -- Output: false

local r = aip.semver.is_prerelease("invalid")
if type(r) == "table" and r.error then
  print("Error:", r.error)
end

Error

Returns an error (Lua table { error: string }) if version is not a valid SemVer string.

aip.semver.valid

Checks if a string is a valid SemVer 2.0.0 version.

-- API Signature
aip.semver.valid(version: string): boolean

Arguments

Returns

Example

print(aip.semver.valid("1.2.3"))          -- Output: true
print(aip.semver.valid("1.2.3-alpha.1"))   -- Output: true
print(aip.semver.valid("1.0"))           -- Output: false
print(aip.semver.valid("invalid"))       -- Output: false

Error

This function does not typically error, returning false for invalid formats.

aip.rust

Functions for processing Rust code.

Functions Summary

aip.rust.prune_to_declarations(code: string): string | {error: string}

aip.rust.prune_to_declarations

Prunes Rust code, replacing function bodies with { ... }.

-- API Signature
aip.rust.prune_to_declarations(code: string): string | {error: string}

Replaces function bodies with { ... }, preserving comments, whitespace, and non-function code structures.

Arguments

Returns

Example

local rust_code = "fn greet(name: &str) {\n  println!(\"Hello, {}!\", name);\n}\n\nstruct Data;"
local pruned = aip.rust.prune_to_declarations(rust_code)
-- pruned might be: "fn greet(name: &str) { ... }\n\nstruct Data;" (exact spacing may vary)

Error

Returns an error (Lua table { error: string }) if pruning fails.

aip.html

Functions for processing HTML content.

Functions Summary

aip.html.slim(html_content: string): string | {error: string}

aip.html.to_md(html_content: string): string | {error: string}

aip.html.slim

Strips non-content elements and most attributes from HTML.

-- API Signature
aip.html.slim(html_content: string): string | {error: string}

Removes <script>, <link>, <style>, <svg>, comments, empty lines, and most attributes (keeps class, aria-label, href).

Arguments

Returns

Example

local html = "<script>alert('hi')</script><p class='c' style='color:red'>Hello</p>"
local cleaned = aip.html.slim(html)
-- cleaned might be: "<p class=\"c\">Hello</p>" (exact output may vary)

Error

Returns an error (Lua table { error: string }) if pruning fails.

aip.html.to_md

Converts HTML content to Markdown format.

-- API Signature
aip.html.to_md(html_content: string): string | {error: string}

Arguments

Returns

Example

local markdown_content = aip.html.to_md("<h1>Hello</h1><p>World</p>")
-- markdown_content will be "# Hello\n\nWorld\n"

Error

Returns an error (Lua table { error: string }) if the HTML content fails to be converted to Markdown.

aip.git

Functions for performing basic Git operations in the workspace.

Functions Summary

aip.git.restore(path: string): string | {error: string, stdout?: string, stderr?: string, exit?: number}

aip.git.restore

Executes git restore <path> in the workspace directory.

-- API Signature
aip.git.restore(path: string): string | {error: string, stdout?: string, stderr?: string, exit?: number}

Restores the specified file or directory path to its state from the Git index.

Arguments

Returns

Example

-- Restore a modified file
local result = aip.git.restore("src/main.rs")
-- Check if result is an error table or the stdout string
if type(result) == "table" and result.error then
  print("Error restoring:", result.error)
  print("Stderr:", result.stderr) -- May contain git error message
else
  print("Restore stdout:", result)
end

Error

Returns an error (Lua table { error: string, stdout?: string, stderr?: string, exit?: number }) if the git restore command encounters an issue, such as the path not being known to Git, insufficient permissions, or the command returning a non-zero exit code with stderr output.

aip.hash

The aip.hash module exposes functions for various hashing algorithms and encodings.

Functions Summary

aip.hash.sha256(input: string): string
aip.hash.sha256_b58(input: string): string
aip.hash.sha256_b64(input: string): string
aip.hash.sha256_b64u(input: string): string
aip.hash.sha512(input: string): string
aip.hash.sha512_b58(input: string): string
aip.hash.sha512_b64(input: string): string
aip.hash.sha512_b64u(input: string): string
aip.hash.blake3(input: string): string
aip.hash.blake3_b58(input: string): string
aip.hash.blake3_b64(input: string): string
aip.hash.blake3_b64u(input: string): string

aip.hash.sha256

Computes the SHA256 hash of the input string and returns it as a lowercase hex-encoded string.

-- API Signature
aip.hash.sha256(input: string): string

Arguments

Returns

string: The SHA256 hash, hex-encoded.

Example

local hex_hash = aip.hash.sha256("hello world")
-- hex_hash will be "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
print(hex_hash)

Error

This function does not typically error if the input is a string.

aip.hash.sha256_b58

Computes the SHA256 hash of the input string and returns it as a Base58-encoded string.

-- API Signature
aip.hash.sha256_b58(input: string): string

Arguments

Returns

string: The SHA256 hash, Base58-encoded.

Example

local b58_hash = aip.hash.sha256_b58("hello world")
-- b58_hash will be "CnKqR4x6r4nAv2iGk8DrZSSWp7n3W9xKRj69eZysS272"
print(b58_hash)

Error

This function does not typically error if the input is a string.

aip.hash.sha256_b64

Computes the SHA256 hash of the input string and returns it as a standard Base64-encoded string (RFC 4648).

-- API Signature
aip.hash.sha256_b64(input: string): string

Arguments

Returns

string: The SHA256 hash, standard Base64-encoded.

Example

local b64_hash = aip.hash.sha256_b64("hello world")
-- b64_hash will be "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="
print(b64_hash)

Error

This function does not typically error if the input is a string.

aip.hash.sha256_b64u

Computes the SHA256 hash of the input string and returns it as a URL-safe Base64-encoded string (RFC 4648, section 5), without padding.

-- API Signature
aip.hash.sha256_b64u(input: string): string

Arguments

Returns

string: The SHA256 hash, URL-safe Base64-encoded without padding.

Example

local b64u_hash = aip.hash.sha256_b64u("hello world")
-- b64u_hash will be "uU0nuZNNPgilLlLX2n2r-sSE7-N6U4DukIj3rOLvzek"
print(b64u_hash)

Error

This function does not typically error if the input is a string.

aip.hash.sha512

Computes the SHA512 hash of the input string and returns it as a lowercase hex-encoded string.

-- API Signature
aip.hash.sha512(input: string): string

Arguments

Returns

string: The SHA512 hash, hex-encoded.

Example

local hex_hash = aip.hash.sha512("hello world")
-- hex_hash will be "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
print(hex_hash)

Error

This function does not typically error if the input is a string.

aip.hash.sha512_b58

Computes the SHA512 hash of the input string and returns it as a Base58-encoded string.

-- API Signature
aip.hash.sha512_b58(input: string): string

Arguments

Returns

string: The SHA512 hash, Base58-encoded.

Example

local b58_hash = aip.hash.sha512_b58("hello world")
-- b58_hash will be "yP4cqy7jmaRDzC2bmcGNZkuQb3VdftMk6YH7ynQ2Qw4zktKsyA9fk52xghNQNAdkpF9iFmFkKh2bNVG4kDWhsok"
print(b58_hash)

Error

This function does not typically error if the input is a string.

aip.hash.sha512_b64

Computes the SHA512 hash of the input string and returns it as a standard Base64-encoded string (RFC 4648).

-- API Signature
aip.hash.sha512_b64(input: string): string

Arguments

Returns

string: The SHA512 hash, standard Base64-encoded.

Example

local b64_hash = aip.hash.sha512_b64("hello world")
-- b64_hash will be "MJ7MSJwS1utMxA9QyQLytNDtd+5RGnx6m808qG1M2G+YndNbxf9JlnDaNCVbRbDP2DDoH2Bdz33FVC6TrpzXbw=="
print(b64_hash)

Error

This function does not typically error if the input is a string.

aip.hash.sha512_b64u

Computes the SHA512 hash of the input string and returns it as a URL-safe Base64-encoded string (RFC 4648, section 5), without padding.

-- API Signature
aip.hash.sha512_b64u(input: string): string

Arguments

Returns

string: The SHA512 hash, URL-safe Base64-encoded without padding.

Example

local b64u_hash = aip.hash.sha512_b64u("hello world")
-- b64u_hash will be "MJ7MSJwS1utMxA9QyQLytNDtd-5RGnx6m808qG1M2G-YndNbxf9JlnDaNCVbRbDP2DDoH2Bdz33FVC6TrpzXbw"
print(b64u_hash)

Error

This function does not typically error if the input is a string.

aip.hash.blake3

Computes the Blake3 hash of the input string and returns it as a lowercase hex-encoded string.

-- API Signature
aip.hash.blake3(input: string): string

Arguments

Returns

string: The Blake3 hash, hex-encoded.

Example

local hex_hash = aip.hash.blake3("hello world")
-- hex_hash will be "d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24"
print(hex_hash)

Error

This function does not typically error if the input is a string.

aip.hash.blake3_b58

Computes the Blake3 hash of the input string and returns it as a Base58-encoded string.

-- API Signature
aip.hash.blake3_b58(input: string): string

Arguments

Returns

string: The Blake3 hash, Base58-encoded.

Example

local b58_hash = aip.hash.blake3_b58("hello world")
-- b58_hash will be "FVPfbg9bK7mj7jnaSRXhuVcVakkXcjMPgSwxmauUofYf"
print(b58_hash)

Error

This function does not typically error if the input is a string.

aip.hash.blake3_b64

Computes the Blake3 hash of the input string and returns it as a standard Base64-encoded string (RFC 4648).

-- API Signature
aip.hash.blake3_b64(input: string): string

Arguments

Returns

string: The Blake3 hash, standard Base64-encoded.

Example

local b64_hash = aip.hash.blake3_b64("hello world")
-- b64_hash will be "10mB76cKDIgLjYwZhdB128v2ebmaX5kU5ar5a4ManiQ="
print(b64_hash)

Error

This function does not typically error if the input is a string.

aip.hash.blake3_b64u

Computes the Blake3 hash of the input string and returns it as a URL-safe Base64-encoded string (RFC 4648, section 5), without padding.

-- API Signature
aip.hash.blake3_b64u(input: string): string

Arguments

Returns

string: The Blake3 hash, URL-safe Base64-encoded without padding.

Example

local b64u_hash = aip.hash.blake3_b64u("hello world")
-- b64u_hash will be "10mB76cKDIgLjYwZhdB128v2ebmaX5kU5ar5a4ManiQ"
print(b64u_hash)

Error

This function does not typically error if the input is a string.

aip.hbs

Functions for rendering Handlebars templates.

Functions Summary

aip.hbs.render(content: string, data: any): string | {error: string}

aip.hbs.render

Renders a Handlebars template string with Lua data.

-- API Signature
aip.hbs.render(content: string, data: any): string | {error: string}

Converts Lua data to JSON internally and renders the Handlebars content template.

Arguments

Returns

Example

local template = "Hello, !"
local data = {name = "World"}
local rendered_content = aip.hbs.render(template, data)
print(rendered_content) -- Output: Hello, World!

local data_list = {
    name  = "Jen Donavan",
    todos = {"Bug Triage AIPACK", "Fix Windows Support"}
}
local template_list = [[
Hello ,

Your tasks today:


Have a good day (after you completed this tasks)
]]
local content_list = aip.hbs.render(template_list, data_list)
print(content_list)

Error

Returns an error (Lua table { error: string }) if Lua data cannot be converted to JSON or if Handlebars rendering fails.

aip.code

Utility functions for code formatting and manipulation.

Functions Summary

aip.code.comment_line(lang_ext: string, comment_content: string): string | {error: string}

aip.code.comment_line

Creates a single comment line appropriate for a given language extension.

-- API Signature
aip.code.comment_line(lang_ext: string, comment_content: string): string | {error: string}

Formats comment_content as a single-line comment based on lang_ext.

Arguments

Returns

Example

print(aip.code.comment_line("rs", "TODO: Refactor"))  -- Output: // TODO: Refactor
print(aip.code.comment_line("py", "Add validation"))  -- Output: # Add validation
print(aip.code.comment_line("lua", "Fix this later")) -- Output: -- Fix this later
print(aip.code.comment_line("html", "Main content"))  -- Output: <!-- Main content -->

Error

Returns an error (Lua table { error: string }) on conversion or formatting issues.

Common Types

Common data structures returned by or used in API functions.

FileRecord

Represents a file with its metadata and content. Returned by aip.file.load and aip.file.list_load.

{
  path : string,    // Relative or absolute path used to load/find the file
  dir: string,      // Parent directory of the path (empty if no parent)
  name : string,    // File name with extension (e.g., "main.rs")
  stem : string,    // File name without extension (e.g., "main")
  ext  : string,    // File extension (e.g., "rs")

  ctime?: number,   // Creation timestamp (microseconds since epoch), optional
  ctime?: number,   // Modification timestamp (microseconds), optional
  size?: number,    // File size in bytes, optional

  content: string   // The text content of the file
}

FileInfo

Represents file metadata without content. Returned by aip.file.list, aip.file.first, aip.file.ensure_exists, aip.file.save_html_to_md, and aip.file.save_html_to_slim.

{
  path : string,     // Relative or absolute path
  dir: string,       // Parent directory of the path
  name : string,     // File name with extension
  stem : string,     // File name without extension
  ext  : string,     // File extension

  ctime?: number,    // Creation timestamp (microseconds), optional (if with_meta=true for list)
  mtime?: number,    // Modification timestamp (microseconds), optional (if with_meta=true for list)
  size?: number      // File size in bytes, optional (if with_meta=true for list)
}

FileStats

Aggregated statistics for a collection of files. Returned by aip.file.stats.

{
  total_size: number,      // Total size of all matched files in bytes
  number_of_files: number, // Number of files matched
  ctime_first: number,     // Creation timestamp of the oldest file (microseconds since epoch)
  ctime_last: number,      // Creation timestamp of the newest file (microseconds since epoch)
  mtime_first: number,     // Modification timestamp of the oldest file (microseconds since epoch)
  mtime_last: number       // Modification timestamp of the newest file (microseconds since epoch)
}

DestOptions

Options table used for specifying the destination path in functions like aip.file.save_html_to_md and aip.file.save_html_to_slim.

{
  base_dir?: string,  // Base directory for resolving the destination
  file_name?: string, // Custom file name for the output
  suffix?: string     // Suffix appended to the source file stem
}

MdSection

Represents a section of a Markdown document, potentially associated with a heading. Returned by aip.file.load_md_sections and aip.file.load_md_split_first.

{
  content: string,    // Full content of the section (including heading line and sub-sections)
  heading?: {         // Present if the section starts with a heading
    content: string,  // The raw heading line (e.g., "## Section Title")
    level: number,    // Heading level (1-6)
    name: string      // Extracted heading name (e.g., "Section Title")
  }
}

MdBlock

Represents a fenced block (usually code) in Markdown. Returned by aip.md.extract_blocks.

{
  content: string,     // Content inside the block (excluding fence lines)
  lang?: string,        // Language identifier (e.g., "rust", "lua"), optional
  info: string         // Full info string from the opening fence (e.g., "rust file:main.rs"), optional
}

WebResponse

Represents the result of an HTTP request made by aip.web.get or aip.web.post.

{
  success: boolean,   // true if HTTP status code is 2xx, false otherwise
  status: number,     // HTTP status code (e.g., 200, 404, 500)
  url: string,        // The final URL requested (after redirects)
  content: string | table, // Response body. Decoded to a Lua table if Content-Type is application/json, otherwise a string.
  error?: string      // Error message if success is false or if request initiation failed
}

CmdResponse

Represents the result of executing a system command via aip.cmd.exec.

{
  stdout: string,  // Standard output captured from the command
  stderr: string,  // Standard error captured from the command
  exit:   number   // Exit code returned by the command (0 usually indicates success)
}

AgentOptions

Configuration options for an agent. Used in aip.flow.before_all_response and aip.flow.data_response to override settings for a run or a specific cycle.

{
  model?: string,
  temperature?: number,
  top_p?: number,
  input_concurrency?: number,
  model_aliases?: { [key: string]: string }
}

CTX

All Lua scripts get the CTX table in scope, providing context about the current execution environment.

Key Example Value Description
CTX.WORKSPACE_DIR /Users/dev/my-project Absolute path to the workspace directory (containing .aipack/).
CTX.WORKSPACE_AIPACK_DIR /Users/dev/my-project/.aipack Absolute path to the .aipack/ directory in the workspace.
CTX.BASE_AIPACK_DIR /Users/dev/.aipack-base Absolute path to the user's base AIPACK directory.
CTX.AGENT_NAME my_pack/my-agent or path/to/my-agent.aip The name or path used to invoke the agent.
CTX.AGENT_FILE_PATH /Users/home/john/.aipack-base/pack/installed/acme/my_pack/my-agent.aip Absolute path to the resolved agent .aip file.
CTX.AGENT_FILE_DIR /Users/home/john/.aipack-base/pack/installed/acme/my_pack Absolute path to the directory containing the agent file.
CTX.AGENT_FILE_NAME my-agent.aip The base name of the my-agent file.
CTX.AGENT_FILE_STEM my-agent The base name of the agent file without extension.
CTX.TMP_DIR .aipack/.session/0196adbf-b792-7070-a5be-eec26698c065/tmp The tmp dir for this session (all redos in same session)
CTX.SESSION_UID 0196adbf-b792-7070-a5be-eec26698c065 The Session Unique ID for this CLI Session
CTX.RUN_UID 0196adbf-b792-7070-a5be-ddc33698c065 The Run Unique ID
CTX.TASK_UID 0196adbf-b792-7070-a5be-aac55698c065 The Task Unique ID (when in a task stage)

When running a pack. (when no packs, those will be all nil)

For aip run acme@my_pack/my-agent

Key Example Value Description
CTX.PACK_IDENTITY acme@my_pack Pack identity (namespace@name) (nil if not run via pack ref).
CTX.PACK_NAMESPACE acme Namespace of the pack (nil if not run via pack reference).
CTX.PACK_NAME my_pack Name of the pack (nil if not run via pack reference).
CTX.PACK_REF acme@my_pack/my-agent (Nil if not a pack) Full pack reference used (nil if not run via pack reference).
CTX.PACK_WORKSPACE_SUPPORT_DIR /Users/dev/my-project/.aipack/support/pack/acme/my_pack Workspace-specific support directory for this agent (if applicable).
CTX.PACK_BASE_SUPPORT_DIR /Users/home/john/.aipack-base/support/pack/acme/my_pack Base support directory for this agent (if applicable).