KosmoKrator

productivity

Gmail Lua API for KosmoKrator Agents

Agent-facing Lua documentation and function reference for the Gmail KosmoKrator integration.

Lua Namespace

Agents call this integration through app.integrations.gmail.*. Use lua_read_doc("integrations.gmail") inside KosmoKrator to discover the same reference at runtime.

Call Lua from the Headless CLI

Use kosmo integrations:lua when a shell script, CI job, cron job, or another coding CLI should run a deterministic Gmail workflow without starting an interactive agent session.

Inline Lua call
kosmo integrations:lua --eval 'dump(app.integrations.gmail.add_labels({message_id = "example_message_id", message_ids = "example_message_ids", label_ids = "example_label_ids"}))' --json
Read Lua docs headlessly
kosmo integrations:lua --eval 'print(docs.read("gmail"))' --json
kosmo integrations:lua --eval 'print(docs.read("gmail.add_labels"))' --json

Workflow file

Put repeatable logic in a Lua file, then execute it with JSON output for the calling process.

workflow.lua
local gmail = app.integrations.gmail
local result = gmail.add_labels({message_id = "example_message_id", message_ids = "example_message_ids", label_ids = "example_label_ids"})

dump(result)
Run the workflow
kosmo integrations:lua workflow.lua --json
kosmo integrations:lua workflow.lua --force --json
Namespace note. integrations:lua exposes app.integrations.gmail, app.mcp.*, docs.*, json.*, and regex.*. Use app.integrations.gmail.default.* or app.integrations.gmail.work.* when you configured named credential accounts.

MCP-only Lua

If the script only needs configured MCP servers and does not need Gmail, use the narrower mcp:lua command.

MCP Lua command
# Use mcp:lua for MCP-only scripts; use integrations:lua for this integration namespace.
kosmo mcp:lua --eval 'dump(mcp.servers())' --json

Agent-Facing Lua Docs

This is the rendered version of the full Lua documentation exposed to agents when they inspect the integration namespace.

Google Integration — Lua API Supplement

Google services are registered as separate namespaces: integrations.gmail, integrations["google-sheets"], integrations["google-calendar"], integrations["google-drive"], etc. All share the same OAuth credentials.

Gmail

Send email with CC/BCC:

app.integrations.gmail.gmail_send_email({
    to = "alice@example.com",
    subject = "Q1 Report",
    body = "Please find the report attached.",
    cc = "bob@example.com, carol@example.com",
    bcc = "manager@example.com",
})

Search, read, then reply workflow:

-- Step 1: Search for messages
local results = app.integrations.gmail.gmail_search_emails({
    query = "from:alice subject:meeting is:unread",
    max_results = 5,
})

-- Step 2: Read the full message
local msg = app.integrations.gmail.gmail_read({ message_id = results.messages[1].id })

-- Step 3: Reply in the same thread
app.integrations.gmail.gmail_reply({
    message_id = msg.id,
    thread_id = msg.threadId,
    body = "Thanks, I'll be there.",
    cc = "team@example.com",
})

Draft vs direct send — use create_draft to stage an email without sending, then send_draft to send it later:

-- Create a draft (not sent)
local draft = app.integrations.gmail.gmail_create_draft({
    to = "client@example.com",
    subject = "Proposal",
    body = "Draft content here...",
})

-- Send it later using the draft ID
app.integrations.gmail.gmail_send_draft({ draft_id = draft.draftId })

Google Sheets

Values use 2D Lua tables — each inner table is one row:

local values = {
    {"Name", "Age", "City"},
    {"Alice", 30, "NYC"},
    {"Bob", 25, "LA"},
}

A1 notation examples:

  • "Sheet1!A1:D10" — specific range
  • "Sheet1!A:A" — entire column
  • "Sheet1" — entire sheet
  • "'My Sheet'!A1:B2" — sheet names with spaces need quotes

Input modes: "user_entered" (default) parses formulas and dates, "raw" stores literal strings.

Create a spreadsheet, add a sheet, write data:

-- Create a new spreadsheet
local ss = app.integrations["google-sheets"].google_sheets_create({ title = "Q1 Sales" })
local id = ss.spreadsheetId

-- Add a second sheet/tab
app.integrations["google-sheets"].google_sheets_add_sheet({
    spreadsheet_id = id,
    title = "By Region",
})

-- Write data with headers
app.integrations["google-sheets"].google_sheets_write_range({
    spreadsheet_id = id,
    range = "Sheet1!A1:C3",
    values = {
        {"Region", "Revenue", "Growth"},
        {"North", 50000, "=B2/50000-1"},
        {"South", 42000, "=B3/42000-1"},
    },
    input = "user_entered",  -- parses the formulas
})

Read data back:

local data = app.integrations["google-sheets"].google_sheets_read_range({
    spreadsheet_id = id,
    range = "Sheet1!A1:C3",
    render = "formatted",  -- "formatted" (default), "unformatted", or "formula"
})
-- data.values is a 2D table: {{"Region","Revenue","Growth"}, {"North","50000","0%"}, ...}

Append vs write — append_rows auto-detects the last row and adds below it:

app.integrations["google-sheets"].google_sheets_append({
    spreadsheet_id = id,
    range = "Sheet1",
    values = {
        {"East", 38000, "=B4/38000-1"},
    },
    input = "user_entered",
})

Google Calendar

Create a timed event with attendees:

app.integrations["google-calendar"].google_calendar_create_event({
    summary = "Sprint Planning",
    description = "Bi-weekly sprint planning session",
    location = "Conference Room B",
    start_date_time = "2026-04-01T10:00:00-05:00",
    end_date_time = "2026-04-01T11:00:00-05:00",
    time_zone = "America/New_York",
    attendees = "alice@example.com, bob@example.com",
    recurrence = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=10",
})

Create an all-day event:

app.integrations["google-calendar"].google_calendar_create_event({
    summary = "Company Holiday",
    start_date = "2026-07-04",
    end_date = "2026-07-05",
})

Date/time format: ISO 8601 with timezone offset for timed events (2026-04-01T10:00:00-05:00), plain YYYY-MM-DD for all-day events. Use time_zone for IANA names like "America/New_York".

Google Drive

Search for files, then get details:

-- Search by name and type
local results = app.integrations["google-drive"].google_drive_search_files({
    query = "name contains 'report' and mimeType = 'application/vnd.google-apps.spreadsheet'",
    max_results = 10,
    order_by = "modifiedTime desc",
})

-- Get full file info (and optionally export content)
local file = app.integrations["google-drive"].google_drive_get_file({
    file_id = results.files[1].id,
    export_as = "csv",  -- "text", "csv", or "markdown" (Google Workspace files only)
})

Common Drive query patterns:

  • "name contains 'budget'" — by name
  • "mimeType = 'application/vnd.google-apps.spreadsheet'" — Sheets
  • "mimeType = 'application/vnd.google-apps.document'" — Docs
  • "mimeType = 'application/vnd.google-apps.folder'" — folders
  • "modifiedTime > '2026-01-01'" — recently modified
  • "sharedWithMe = true" — shared files
  • "'FOLDER_ID' in parents" — files in a folder

Share a file:

-- Share with a specific user
app.integrations["google-drive"].google_drive_share_file({
    file_id = "abc123",
    role = "writer",       -- "reader", "writer", or "commenter"
    email = "alice@example.com",
    notify = "true",
})

-- Share with anyone via link
app.integrations["google-drive"].google_drive_share_file({
    file_id = "abc123",
    role = "reader",
    type = "anyone",
})

Google Analytics

The GA4 namespace is app.integrations["google-analytics"]. Start with property discovery, then run metadata or report tools against the numeric property ID.

local properties = app.integrations["google-analytics"].google_analytics_list_properties({})

Run a standard report:

local report = app.integrations["google-analytics"].google_analytics_report({
    property_id = "123456789",
    metrics = {"sessions", "totalUsers"},
    dimensions = {"sessionDefaultChannelGroup"},
    start_date = "28daysAgo",
    end_date = "yesterday",
    order_by = "sessions",
    order_direction = "desc",
    limit = 20,
})

Check compatibility before combining unfamiliar dimensions and metrics:

local compatibility = app.integrations["google-analytics"].google_analytics_check_compatibility({
    property_id = "123456789",
    metrics = {"sessions"},
    dimensions = {"country", "deviceCategory"},
})

Run pivot and batch reports when you need the exact Google Analytics Data API response shape:

local pivot = app.integrations["google-analytics"].google_analytics_pivot_report({
    property_id = "123456789",
    metrics = {"sessions"},
    dimensions = {"country", "deviceCategory"},
    pivots = {
        { fieldNames = {"country"}, limit = 10 },
        { fieldNames = {"deviceCategory"}, limit = 5 },
    },
})

local batch = app.integrations["google-analytics"].google_analytics_batch_run_reports({
    property_id = "123456789",
    requests = {
        {
            metrics = {{ name = "sessions" }},
            dimensions = {{ name = "country" }},
            dateRanges = {{ startDate = "7daysAgo", endDate = "yesterday" }},
        },
    },
})

Tips

  • All Google APIs share the same OAuth token — if Gmail is connected, the same credentials work for Sheets, Drive, Calendar, etc.
  • Use input = "user_entered" when writing Sheets data that contains formulas (e.g., "=SUM(A1:A10)") or dates. Use "raw" for literal strings.
  • Sheet names with spaces must be quoted in A1 notation: "'My Sheet'!A1:B2".
  • append_rows is better than write_range when adding rows to an existing table — it auto-detects where the data ends.
  • Calendar event times use ISO 8601 with timezone offset. Always include the offset or set time_zone explicitly.
  • Drive search excludes trashed files by default.

Multi-Account Usage

If you have multiple Google service accounts configured, use account-specific namespaces:

-- Default account (always works)
app.integrations["google-sheets"].function_name({...})

-- Explicit default (portable across setups)
app.integrations["google-sheets"].default.function_name({...})

-- Named accounts
app.integrations["google-sheets"].work.function_name({...})
app.integrations["google-sheets"].personal.function_name({...})

All functions are identical across accounts — only the credentials differ.

Raw agent markdown
# Google Integration — Lua API Supplement

Google services are registered as separate namespaces: `integrations.gmail`, `integrations["google-sheets"]`, `integrations["google-calendar"]`, `integrations["google-drive"]`, etc. All share the same OAuth credentials.

## Gmail

Send email with CC/BCC:

```lua
app.integrations.gmail.gmail_send_email({
    to = "alice@example.com",
    subject = "Q1 Report",
    body = "Please find the report attached.",
    cc = "bob@example.com, carol@example.com",
    bcc = "manager@example.com",
})
```

Search, read, then reply workflow:

```lua
-- Step 1: Search for messages
local results = app.integrations.gmail.gmail_search_emails({
    query = "from:alice subject:meeting is:unread",
    max_results = 5,
})

-- Step 2: Read the full message
local msg = app.integrations.gmail.gmail_read({ message_id = results.messages[1].id })

-- Step 3: Reply in the same thread
app.integrations.gmail.gmail_reply({
    message_id = msg.id,
    thread_id = msg.threadId,
    body = "Thanks, I'll be there.",
    cc = "team@example.com",
})
```

Draft vs direct send -- use `create_draft` to stage an email without sending, then `send_draft` to send it later:

```lua
-- Create a draft (not sent)
local draft = app.integrations.gmail.gmail_create_draft({
    to = "client@example.com",
    subject = "Proposal",
    body = "Draft content here...",
})

-- Send it later using the draft ID
app.integrations.gmail.gmail_send_draft({ draft_id = draft.draftId })
```

## Google Sheets

Values use 2D Lua tables -- each inner table is one row:

```lua
local values = {
    {"Name", "Age", "City"},
    {"Alice", 30, "NYC"},
    {"Bob", 25, "LA"},
}
```

A1 notation examples:

- `"Sheet1!A1:D10"` -- specific range
- `"Sheet1!A:A"` -- entire column
- `"Sheet1"` -- entire sheet
- `"'My Sheet'!A1:B2"` -- sheet names with spaces need quotes

Input modes: `"user_entered"` (default) parses formulas and dates, `"raw"` stores literal strings.

Create a spreadsheet, add a sheet, write data:

```lua
-- Create a new spreadsheet
local ss = app.integrations["google-sheets"].google_sheets_create({ title = "Q1 Sales" })
local id = ss.spreadsheetId

-- Add a second sheet/tab
app.integrations["google-sheets"].google_sheets_add_sheet({
    spreadsheet_id = id,
    title = "By Region",
})

-- Write data with headers
app.integrations["google-sheets"].google_sheets_write_range({
    spreadsheet_id = id,
    range = "Sheet1!A1:C3",
    values = {
        {"Region", "Revenue", "Growth"},
        {"North", 50000, "=B2/50000-1"},
        {"South", 42000, "=B3/42000-1"},
    },
    input = "user_entered",  -- parses the formulas
})
```

Read data back:

```lua
local data = app.integrations["google-sheets"].google_sheets_read_range({
    spreadsheet_id = id,
    range = "Sheet1!A1:C3",
    render = "formatted",  -- "formatted" (default), "unformatted", or "formula"
})
-- data.values is a 2D table: {{"Region","Revenue","Growth"}, {"North","50000","0%"}, ...}
```

Append vs write -- `append_rows` auto-detects the last row and adds below it:

```lua
app.integrations["google-sheets"].google_sheets_append({
    spreadsheet_id = id,
    range = "Sheet1",
    values = {
        {"East", 38000, "=B4/38000-1"},
    },
    input = "user_entered",
})
```

## Google Calendar

Create a timed event with attendees:

```lua
app.integrations["google-calendar"].google_calendar_create_event({
    summary = "Sprint Planning",
    description = "Bi-weekly sprint planning session",
    location = "Conference Room B",
    start_date_time = "2026-04-01T10:00:00-05:00",
    end_date_time = "2026-04-01T11:00:00-05:00",
    time_zone = "America/New_York",
    attendees = "alice@example.com, bob@example.com",
    recurrence = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=10",
})
```

Create an all-day event:

```lua
app.integrations["google-calendar"].google_calendar_create_event({
    summary = "Company Holiday",
    start_date = "2026-07-04",
    end_date = "2026-07-05",
})
```

Date/time format: ISO 8601 with timezone offset for timed events (`2026-04-01T10:00:00-05:00`), plain `YYYY-MM-DD` for all-day events. Use `time_zone` for IANA names like `"America/New_York"`.

## Google Drive

Search for files, then get details:

```lua
-- Search by name and type
local results = app.integrations["google-drive"].google_drive_search_files({
    query = "name contains 'report' and mimeType = 'application/vnd.google-apps.spreadsheet'",
    max_results = 10,
    order_by = "modifiedTime desc",
})

-- Get full file info (and optionally export content)
local file = app.integrations["google-drive"].google_drive_get_file({
    file_id = results.files[1].id,
    export_as = "csv",  -- "text", "csv", or "markdown" (Google Workspace files only)
})
```

Common Drive query patterns:

- `"name contains 'budget'"` -- by name
- `"mimeType = 'application/vnd.google-apps.spreadsheet'"` -- Sheets
- `"mimeType = 'application/vnd.google-apps.document'"` -- Docs
- `"mimeType = 'application/vnd.google-apps.folder'"` -- folders
- `"modifiedTime > '2026-01-01'"` -- recently modified
- `"sharedWithMe = true"` -- shared files
- `"'FOLDER_ID' in parents"` -- files in a folder

Share a file:

```lua
-- Share with a specific user
app.integrations["google-drive"].google_drive_share_file({
    file_id = "abc123",
    role = "writer",       -- "reader", "writer", or "commenter"
    email = "alice@example.com",
    notify = "true",
})

-- Share with anyone via link
app.integrations["google-drive"].google_drive_share_file({
    file_id = "abc123",
    role = "reader",
    type = "anyone",
})
```

## Google Analytics

The GA4 namespace is `app.integrations["google-analytics"]`. Start with property discovery, then run metadata or report tools against the numeric property ID.

```lua
local properties = app.integrations["google-analytics"].google_analytics_list_properties({})
```

Run a standard report:

```lua
local report = app.integrations["google-analytics"].google_analytics_report({
    property_id = "123456789",
    metrics = {"sessions", "totalUsers"},
    dimensions = {"sessionDefaultChannelGroup"},
    start_date = "28daysAgo",
    end_date = "yesterday",
    order_by = "sessions",
    order_direction = "desc",
    limit = 20,
})
```

Check compatibility before combining unfamiliar dimensions and metrics:

```lua
local compatibility = app.integrations["google-analytics"].google_analytics_check_compatibility({
    property_id = "123456789",
    metrics = {"sessions"},
    dimensions = {"country", "deviceCategory"},
})
```

Run pivot and batch reports when you need the exact Google Analytics Data API response shape:

```lua
local pivot = app.integrations["google-analytics"].google_analytics_pivot_report({
    property_id = "123456789",
    metrics = {"sessions"},
    dimensions = {"country", "deviceCategory"},
    pivots = {
        { fieldNames = {"country"}, limit = 10 },
        { fieldNames = {"deviceCategory"}, limit = 5 },
    },
})

local batch = app.integrations["google-analytics"].google_analytics_batch_run_reports({
    property_id = "123456789",
    requests = {
        {
            metrics = {{ name = "sessions" }},
            dimensions = {{ name = "country" }},
            dateRanges = {{ startDate = "7daysAgo", endDate = "yesterday" }},
        },
    },
})
```

## Tips

- All Google APIs share the same OAuth token -- if Gmail is connected, the same credentials work for Sheets, Drive, Calendar, etc.
- Use `input = "user_entered"` when writing Sheets data that contains formulas (e.g., `"=SUM(A1:A10)"`) or dates. Use `"raw"` for literal strings.
- Sheet names with spaces must be quoted in A1 notation: `"'My Sheet'!A1:B2"`.
- `append_rows` is better than `write_range` when adding rows to an existing table -- it auto-detects where the data ends.
- Calendar event times use ISO 8601 with timezone offset. Always include the offset or set `time_zone` explicitly.
- Drive search excludes trashed files by default.

---

## Multi-Account Usage

If you have multiple Google service accounts configured, use account-specific namespaces:

```lua
-- Default account (always works)
app.integrations["google-sheets"].function_name({...})

-- Explicit default (portable across setups)
app.integrations["google-sheets"].default.function_name({...})

-- Named accounts
app.integrations["google-sheets"].work.function_name({...})
app.integrations["google-sheets"].personal.function_name({...})
```

All functions are identical across accounts — only the credentials differ.
Metadata-derived Lua example
local result = app.integrations.gmail.add_labels({message_id = "example_message_id", message_ids = "example_message_ids", label_ids = "example_label_ids"})
print(result)

Functions

add_labels Write

Add labels to one or more Gmail messages. Provide messageIds (comma-separated) for batch operations.

Lua path
app.integrations.gmail.add_labels
Full name
gmail.gmail_add_labels
ParameterTypeRequiredDescription
message_id string no Single message ID to add labels to.
message_ids string no Comma-separated message IDs for batch operations.
label_ids string yes Comma-separated label IDs to add.
archive Read

Archive one or more Gmail messages (remove from inbox). Provide messageIds (comma-separated) for batch operations.

Lua path
app.integrations.gmail.archive
Full name
gmail.gmail_archive
ParameterTypeRequiredDescription
message_id string no Single message ID to archive.
message_ids string no Comma-separated message IDs for batch operations.
create_draft Write

Create a draft email in Gmail (not sent).

Lua path
app.integrations.gmail.create_draft
Full name
gmail.gmail_create_draft
ParameterTypeRequiredDescription
to string yes Recipient email address.
subject string yes Email subject.
body string no Email body text.
cc string no CC recipients (comma-separated emails).
bcc string no BCC recipients (comma-separated emails).
mark_read Write

Mark one or more Gmail messages as read. Provide messageIds (comma-separated) for batch operations.

Lua path
app.integrations.gmail.mark_read
Full name
gmail.gmail_mark_read
ParameterTypeRequiredDescription
message_id string no Single message ID to mark as read.
message_ids string no Comma-separated message IDs for batch operations.
mark_unread Write

Mark one or more Gmail messages as unread. Provide messageIds (comma-separated) for batch operations.

Lua path
app.integrations.gmail.mark_unread
Full name
gmail.gmail_mark_unread
ParameterTypeRequiredDescription
message_id string no Single message ID to mark as unread.
message_ids string no Comma-separated message IDs for batch operations.
read Read

Read the full content of a Gmail message by its ID. Returns headers (From, To, Subject, Date), the decoded text body, and a list of attachments. Use gmail_search first to find message IDs, then use this tool to read the full content.

Lua path
app.integrations.gmail.read
Full name
gmail.gmail_read
ParameterTypeRequiredDescription
message_id string yes Gmail message ID to read.
format string no Response format: "full" (default, includes body), "metadata" (headers only), "minimal" (IDs only).
remove_labels Write

Remove labels from one or more Gmail messages. Provide messageIds (comma-separated) for batch operations.

Lua path
app.integrations.gmail.remove_labels
Full name
gmail.gmail_remove_labels
ParameterTypeRequiredDescription
message_id string no Single message ID to remove labels from.
message_ids string no Comma-separated message IDs for batch operations.
label_ids string yes Comma-separated label IDs to remove.
reply Read

Reply to an existing Gmail message (maintains the thread).

Lua path
app.integrations.gmail.reply
Full name
gmail.gmail_reply
ParameterTypeRequiredDescription
message_id string yes Original message ID to reply to.
thread_id string yes Thread ID to reply in.
body string yes Reply body text.
to string no Recipient email address (defaults to original sender).
cc string no CC recipients (comma-separated emails).
bcc string no BCC recipients (comma-separated emails).
count_by_sender Read

Count all matching Gmail messages grouped by sender. Automatically paginates through ALL results (handles thousands of messages). Returns top senders sorted by count. Use for questions like "who sends me the most email?" or "count unread by sender".

Lua path
app.integrations.gmail.count_by_sender
Full name
gmail.gmail_count_by_sender
ParameterTypeRequiredDescription
query string no Gmail search query to filter messages (e.g., "is:unread", "after:2026-01-01").
label_ids string no Comma-separated label IDs to filter by.
list_labels Read

List all labels in the Gmail mailbox (INBOX, SENT, custom labels, etc.).

Lua path
app.integrations.gmail.list_labels
Full name
gmail.gmail_list_labels
ParameterTypeRequiredDescription
No parameters.
save_attachment Read

Download an email attachment and save it to workspace files. Requires a messageId and attachmentId (both returned by gmail_read). The file is saved under the agent's folder and can be browsed in the Files page.

Lua path
app.integrations.gmail.save_attachment
Full name
gmail.gmail_save_attachment
ParameterTypeRequiredDescription
message_id string yes Gmail message ID containing the attachment.
attachment_id string yes Attachment ID from the gmail_read response.
filename string yes Filename to save as (e.g. "invoice.pdf"). Use the filename from gmail_read.
mime_type string no MIME type of the attachment (e.g. "application/pdf"). Use the mimeType from gmail_read.
search_emails Read

Search Gmail messages using Gmail query syntax (e.g., "from:alice subject:meeting is:unread has:attachment after:2026-02-01"). Returns message summaries with headers. Max 100 per page.

Lua path
app.integrations.gmail.search_emails
Full name
gmail.gmail_search_emails
ParameterTypeRequiredDescription
query string no Gmail search query (e.g., "from:alice subject:meeting is:unread").
max_results integer no Max results to return (default: 10, max: 100).
page_token string no Pagination token from previous response.
label_ids string no Comma-separated label IDs to filter by.
send_draft Write

Send a previously created Gmail draft by its ID.

Lua path
app.integrations.gmail.send_draft
Full name
gmail.gmail_send_draft
ParameterTypeRequiredDescription
draft_id string yes Draft ID to send.
send_email Write

Send an email directly via Gmail.

Lua path
app.integrations.gmail.send_email
Full name
gmail.gmail_send_email
ParameterTypeRequiredDescription
to string yes Recipient email address.
subject string yes Email subject.
body string yes Email body text.
cc string no CC recipients (comma-separated emails).
bcc string no BCC recipients (comma-separated emails).
trash Read

Move one or more Gmail messages to trash. Provide messageIds (comma-separated) for batch operations.

Lua path
app.integrations.gmail.trash
Full name
gmail.gmail_trash
ParameterTypeRequiredDescription
message_id string no Single message ID to trash.
message_ids string no Comma-separated message IDs for batch operations.
untrash Read

Remove one or more Gmail messages from trash. Provide messageIds (comma-separated) for batch operations.

Lua path
app.integrations.gmail.untrash
Full name
gmail.gmail_untrash
ParameterTypeRequiredDescription
message_id string no Single message ID to restore from trash.
message_ids string no Comma-separated message IDs for batch operations.