Skip to content

Script

This document specifies the Script extension, a flexible data-layer solution that enables extensible functionality through multiple execution contexts. The Script extension provides a unified interface for custom logic execution within data processing workflows.

Supported script types include:

  • LLM Tools: Callable tools for AI agents
  • Table Actions: Custom actions triggered on table records
  • Document Actions: Intelligent processing triggered on documents
  • File Actions: One-click operations for background file processing
  • User-Defined Functions (UDFs): Database functions callable in SQL queries

The Script extension addresses the need for extensible data processing capabilities by providing a standardized framework for executing custom logic across multiple contexts. This specification defines the meta configuration structure and execution patterns for each supported script type.

When the type property is set to "tool", scripts function as callable tools within Large Language Model (LLM) workflows, enabling AI agents to execute custom functions with structured input/output schemas.

interface ToolMeta {
type: "tool"
funcName: string
tool: {
name: string
description: string
inputJSONSchema: JSONSchema
outputJSONSchema: JSONSchema
}
}
export const meta = {
type: "tool",
funcName: "hello",
tool: {
name: "hello",
description: "This is a hello world block",
inputJSONSchema: {
type: "object",
properties: {
name: {
type: "string",
},
},
},
outputJSONSchema: {
type: "string",
},
},
}
export function hello({ name }: { name: string }) {
return `Hello, ${name}!`
}

When the type property is set to "action", scripts serve as table-level operations that can be triggered on selected records. These actions extend the table interface with custom functionality accessible through context menus.

interface ActionMeta {
type: "tableAction"
funcName: string
tableAction: {
name: string
description: string
}
}

Table action functions receive two parameters:

  • input: The selected record data as Record<string, any>
  • ctx: Context object containing tableId, viewId, and rowId
export const meta = {
type: "tableAction",
funcName: "toggleChecked",
tableAction: {
name: "Toggle Checked Status",
description: "Toggles the checked status of the selected record",
},
}
export async function toggleChecked(
input: Record<string, any>,
ctx: {
tableId: string
viewId: string
rowId: string
}
) {
const { tableId, viewId, rowId } = ctx
await eidos.currentSpace.table(tableId).rows.update(rowId, {
checked: !input.checked,
})
return {
success: true,
}
}

When the type property is set to "docAction", scripts function as document-level operations that can be triggered on specific documents. These actions are accessible through the document actions menu, making your documents more intelligent and automated.

interface DocActionMeta {
type: "docAction"
funcName: string
docAction: {
name: string
description: string
}
}

Document action functions receive two parameters:

  • input: Input parameters as Record<string, any>
  • ctx: Context object containing docId
export const meta = {
type: "docAction",
funcName: "calculateCompletion",
docAction: {
name: "Calculate Completion",
description: "Calculates the completion percentage of the document",
},
}
export async function calculateCompletion(
input: Record<string, any>,
ctx: {
docId: string
}
) {
const { docId } = ctx
const doc = await eidos.currentSpace.doc.getMarkdown(docId)
// Extract completion ratio from markdown checkboxes
const uncheckedCount = doc
.split("\n")
.filter((line) => line.startsWith("- [ ]")).length
const checkedCount = doc
.split("\n")
.filter((line) => line.startsWith("- [x]")).length
const totalCount = uncheckedCount + checkedCount
const completion = totalCount > 0 ? (checkedCount / totalCount) * 100 : 0
await eidos.currentSpace.doc.setProperties(docId, {
completion,
})
return {
completion,
}
}

When the type property is set to "fileAction", scripts function as file-level actions that can be triggered on specific files. These actions are accessible through the file context menu, enabling background file processing without requiring a UI interface.

interface FileActionMeta {
type: "fileAction"
funcName: string
fileAction: {
name: string
description: string
extensions: string[] // Supported file extensions, e.g., [".jpg", ".png"]
icon?: string // Optional icon
}
}

File action functions receive two parameters:

  • filePath: File path string (same format as File Handler, supports ~/ and @/ prefixes)
  • ctx: Context object (currently empty, reserved for future extensions)
export const meta = {
type: "fileAction",
funcName: "compressImage",
fileAction: {
name: "Compress Image",
description: "Compress image to 50% of original size",
extensions: [".jpg", ".jpeg", ".png"],
icon: "🗜️"
}
}
export async function compressImage(
filePath: string,
ctx: Record<string, any>
) {
try {
// Read original file
const data = await eidos.currentSpace.fs.readFile(filePath)
// Compress image (using third-party library like browser-image-compression)
const compressed = await compressImageData(data, {
maxSizeMB: 1,
maxWidthOrHeight: 1920
})
// Generate new file path
const newPath = filePath.replace(/(\.\w+)$/, '_compressed$1')
await eidos.currentSpace.fs.writeFile(newPath, compressed)
// Show success notification
eidos.currentSpace.notify({
title: "Success",
description: `Compressed and saved to ${newPath}`
})
return {
success: true,
outputPath: newPath,
originalSize: data.byteLength,
compressedSize: compressed.byteLength
}
} catch (error) {
eidos.currentSpace.notify({
title: "Error",
description: `Compression failed: ${error.message}`
})
return {
success: false,
error: error.message
}
}
}
  1. User right-clicks a file in the file tree
  2. Sees “File Actions” submenu listing all fileAction scripts supporting that extension
  3. Clicks an action (e.g., “Compress Image”)
  4. Script executes in the background
  5. Notification displays upon completion

Same as File Handler, use eidos.currentSpace.fs API to access files:

// Read text file
const text = await eidos.currentSpace.fs.readFile(filePath, "utf8")
// Read binary file
const data = await eidos.currentSpace.fs.readFile(filePath)
// Write file
await eidos.currentSpace.fs.writeFile(filePath, content, "utf8")
// Get file info
const stats = await eidos.currentSpace.fs.stat(filePath)

For more file system API details, see Space API Reference - File System API.

When the type property is set to "udf", scripts create database functions that can be invoked within SQL queries, extending the database’s computational capabilities.

interface UDFMeta {
type: "udf"
funcName: string
udf: {
name: string
deterministic?: boolean
}
}

Scalar UDFs operate on individual values and return a single result per invocation.

export const meta = {
type: "udf",
funcName: "add",
udf: {
// add is a reserved word in SQL, so we use a different name
name: "myAdd",
deterministic: true,
},
}
function add(a: number, b: number) {
return a + b
}

Script execution should be sandboxed appropriately to prevent unauthorized system access. Implementations must validate input parameters and enforce proper access controls based on the execution context.

  • All scripts MUST export a meta object conforming to the specified interface
  • Function names in the meta.funcName property MUST match the actual exported function
  • Input validation SHOULD be implemented for all script types
  • Error handling MUST be consistent across all execution contexts

This specification may be extended to support additional script types such as:

  • Event handlers
  • Data validators
  • Custom field types
  • Workflow triggers