Built-in Capabilities
When you build a plugin, you get a set of capabilities for free. These are built into CableKnit and available to any automation, without the company needing to connect any external services.
Additional capabilities become available when a company connects optional services like Slack or Microsoft Teams. Those are documented separately in Connectors.
AI tools in chat
The AI has access to built-in tools during chat conversations. Tools are context-sensitive — they appear based on what’s active (attachments, connectors, installed plugins, existing artifacts).
lookup_employees
Search the company’s employee directory.
| Parameter | Type | Description |
|---|---|---|
search |
string | Name, role, or keyword |
department |
string | Filter by department |
include_schedules |
boolean | Include availability and schedule data |
Returns employee records with id, name, role, email, phone, skills, and availability.
create_automation
Create recurring automations directly from chat.
| Parameter | Type | Description |
|---|---|---|
name |
string | Automation name |
description |
string | What the automation does |
schedule_cron |
string | Cron expression (UTC) |
automation_kind |
string | One of the available automation kinds |
Available kinds: employee_stats_summary, weekly_employee_report, new_employee_digest, incomplete_profiles_audit.
fetch_briefing
Query live data from connected services. Only available when the company has active connectors.
| Parameter | Type | Description |
|---|---|---|
connection_name |
string | Name of the connected service |
period |
string | Time range: 1d, 7d, 30d, 90d, 1y, or all |
resources |
string | Comma-separated resource types |
latest |
integer | Number of most recent records to return |
transform_file
Manipulate uploaded file data. Only available when the user has file attachments in the chat.
Operations: remove_column, add_column, rename_column, reorder_columns, filter_rows, sort_rows, deduplicate
Formulas (for add_column): concat, uppercase, lowercase, trim, static_value
Filter operators (for filter_rows): equals, not_equals, contains, not_contains, greater_than, less_than, starts_with, ends_with
update_cells
Edit an active spreadsheet artifact. Only available when a spreadsheet artifact exists in the conversation.
| Parameter | Type | Description |
|---|---|---|
updates |
array | [{ row, column, value }] cell updates |
new_columns |
array | Columns to add |
delete_columns |
array | Columns to remove |
delete_rows |
array | Row indices to remove |
rename_columns |
object | { old_name: new_name } mappings |
execute_code
Run sandboxed Ruby code to query and analyze data from plugin data sources. Only available when the installed plugin has at least one active data source (i.e. files in the tools/ folder).
The tool name is dynamic: execute_{plugin_slug}_code (hyphens in the slug become underscores). Each active data source becomes a callable method inside the sandbox, also with hyphens converted to underscores.
| Parameter | Type | Description |
|---|---|---|
code |
string | Ruby code to execute in the sandbox |
Generated read methods per data source:
| Method | Description |
|---|---|
{source}(...) |
Query via the data source’s parameters (get/list) |
Write methods (opt-in only):
| Method | Description |
|---|---|
{source}_set(key, value) |
Store a value at a key |
{source}_delete(key) |
Remove a key and its value |
{source}_increment(key, amount) |
Atomically increment a numeric value |
Write methods are not available by default. To enable them, use the object format in platform_tools with "writable": true. See Data Tools — Sandboxed code execution for details.
Sandbox limits: 5-second timeout, 10 MB memory cap. Code runs in an isolated MRuby Enclave — no network access, no filesystem access.
To opt in, declare execute-code in the platform_tools array of your plugin.json. The tool auto-registers only when the plugin has active data sources.
send_webhook
Send an HTTP request to any external URL. Supports GET, POST, PUT, PATCH, and DELETE. SSRF-protected — requests to private/internal IPs are blocked.
| Parameter | Type | Description |
|---|---|---|
url |
string | Target URL |
method |
string | HTTP method (default: POST) |
headers |
string | JSON string of request headers |
body |
string | JSON string request body |
Returns the response status code and body (capped at 64 KB). Timeout: 30 seconds.
store_data
Read and write key-value data scoped to the current plugin installation. Wraps the Plugin Data Store with get, set, delete, list, and increment operations.
| Parameter | Type | Description |
|---|---|---|
action |
string | One of: get, set, delete, list, increment |
key |
string | Data key |
value |
string | Value to store (JSON or plain text) |
expires_in |
integer | Seconds until expiry (set only) |
prefix |
string | Key prefix filter (list only) |
Limits: 500 keys, 1 MB total per plugin installation.
generate_pdf
Generate a PDF document from text content. Creates an Artifact (type: document) with the PDF attached.
| Parameter | Type | Description |
|---|---|---|
title |
string | Document title |
content |
string | Text content for the body |
filename |
string | Output filename (defaults to parameterized title) |
delay
Pause the current automation for a specified duration. Automation-only — not available in interactive chat.
| Parameter | Type | Description |
|---|---|---|
duration |
string | Duration: 30s, 5m, 1h. Max 24h. |
The run transitions to paused_for_input and automatically resumes when the delay expires.
Plugin data tools
Plugins can define custom tools the AI calls in chat. These are configured as JSON files in the tools/ folder of the plugin bundle. See Data Tools for details.
Outbound email
Send emails from your workflow using the notify action with "email" as the channel, or use send_and_wait to pause the run until the recipient replies.
CableKnit sends email on behalf of the company. Messages come from a CableKnit-managed sending address unless the company has configured a custom domain.
Fire-and-forget notification
Use notify when you want to send an email and continue immediately without waiting for a response.
{
"type": "notify",
"channels": ["email"],
"to_addresses": [""],
"subject": "Application received: ",
"body": "We've received your application and will be in touch within 2 business days."
}
To send to all users with a given workflow role instead of a specific address:
{
"type": "notify",
"channels": ["email"],
"to_role": "manager",
"subject": "Review required",
"body": "A new application is awaiting your review."
}
Request a reply
Use send_and_wait when you need a response from the recipient before the workflow can continue. The run pauses in paused_for_input status until the reply arrives.
{
"type": "send_and_wait",
"channel": "email",
"to_addresses": [""],
"template": "request-additional-documents",
"wait_for": "email_reply",
"timeout": "72h",
"output_key": "vendor_reply"
}
The reply is stored in case_context under output_key. You can then pass it to an ai_assess step to extract or classify the response.
Email templates
The email_template_slug parameter lets you reference a custom email template the company has configured in CableKnit. Templates support variable interpolation from case_context.
{
"type": "notify",
"channels": ["email"],
"to_role": "manager",
"email_template_slug": "weekly-compliance-summary"
}
Human-in-the-loop decisions
The request_decision action is the primary way to get a human involved in a workflow. It pauses the run and creates a Decision in the CableKnit Decision Queue — visible in the Mac app, iOS app, and via email notification. The run resumes automatically once a team member resolves it.
This is the only mechanism third-party plugins have for reaching users directly. It is intentionally structured: decisions are tied to a run, they have explicit options, they create an audit trail, and they require deliberate action to resolve.
{
"type": "request_decision",
"title": "Approve subcontractor: ",
"description": "Review the application and select an outcome. Supporting documents are attached.",
"decision_options": [
{ "key": "approve", "label": "Approve" },
{ "key": "reject", "label": "Reject" },
{
"key": "request_more_info",
"label": "Request more information",
"requires_input": true
}
],
"assigned_role": "manager",
"context_keys": ["assessment", "vendor_reply"],
"priority": "high",
"expires_in": 48
}
The reviewer sees the Decision with all attached context. After they act, case_context.decision_outcome is set to the chosen option’s key, and the run resumes.
Use decision_outcome conditions on outgoing transitions to route based on what was decided:
{
"condition": {
"type": "decision_outcome",
"outcome": "approve"
},
"next_state": "send_approval_email"
}
See Entry Actions for the full parameter reference, and Conditions for routing patterns.
Connector-gated capabilities
The following capabilities require the company to have connected an external service. Your plugin can use these actions — they will simply be skipped silently if the connector isn’t present. Document any connector requirements clearly in your plugin’s description so companies know what they need to set up.
| Action | Requires |
|---|---|
notify_slack |
Slack connector |
notify_teams |
Microsoft 365 connector |
hubspot_create_contact |
HubSpot connector |
hubspot_create_deal |
HubSpot connector |
quickbooks_create_invoice |
QuickBooks connector |
quickbooks_send_invoice |
QuickBooks connector |
xero_create_invoice |
Xero connector |
xero_send_invoice |
Xero connector |
procore_create_rfi |
Procore connector |
See Connectors for details on how companies connect these services and how to handle graceful degradation in your workflow when a connector is absent.