Tool Specification
A Tool is the fundamental building block of Unspec'd applications. Each tool defines a complete interface with its content, functions, and input configuration.
Tool Interface
interface Tool {
id: string; // Unique tool identifier
title: string; // Display title
content: ComponentContent; // Component configuration
functions?: Record<string, Function>; // Tool functions
inputs?: Record<string, InputConfig>; // Input definitions
description?: string; // Tool description
icon?: string; // Tool icon
category?: string; // Tool category
tags?: string[]; // Search tags
permissions?: string[]; // Required permissions
}
Required Properties
id: string
Unique identifier for the tool. Used for routing and function calls.
const tool = {
id: 'user-management', // Must be unique across all tools
// ...
};
Requirements:
- Must be unique within the application
- Should use kebab-case (lowercase with hyphens)
- Cannot contain spaces or special characters
- Should be descriptive and meaningful
title: string
Human-readable title displayed in the UI.
const tool = {
id: 'user-management',
title: 'User Management', // Displayed in navigation and headers
// ...
};
content: ComponentContent
Defines the component type and its configuration.
const tool = {
id: 'users',
title: 'Users',
content: {
type: 'editableTable', // Component type
columns: { // Component-specific configuration
name: { type: 'text', label: 'Name' },
email: { type: 'email', label: 'Email' }
}
}
};
Available Component Types:
displayRecord
- Display structured dataeditableTable
- CRUD data tableseditForm
- Form interfacesstreamingTable
- Real-time data streamsactionButton
- Interactive buttons
Optional Properties
functions?: Record<string, Function>
Functions that can be called by the component or externally.
const tool = {
id: 'users',
title: 'Users',
content: { /* ... */ },
functions: {
loadData: async ({ inputs }) => {
// Function implementation
return data;
},
updateUser: async ({ data, inputs }) => {
// Function implementation
return result;
}
}
};
Function Signature:
type ToolFunction = (params: {
inputs?: Record<string, any>;
data?: any;
[key: string]: any;
}) => Promise<any> | any;
inputs?: Record<string, InputConfig>
Input field definitions for the tool.
const tool = {
id: 'user-search',
title: 'User Search',
inputs: {
searchTerm: {
type: 'text',
label: 'Search Term',
placeholder: 'Enter name or email...',
required: true
},
role: {
type: 'select',
label: 'Role Filter',
options: [
{ value: 'all', label: 'All Roles' },
{ value: 'admin', label: 'Admin' },
{ value: 'user', label: 'User' }
]
}
},
content: { /* ... */ },
functions: { /* ... */ }
};
description?: string
Optional description for documentation and tooltips.
const tool = {
id: 'analytics',
title: 'Analytics Dashboard',
description: 'View comprehensive analytics and metrics for your application',
content: { /* ... */ }
};
icon?: string
Icon identifier for the tool (used in navigation).
const tool = {
id: 'users',
title: 'Users',
icon: 'users', // Icon name or SVG
content: { /* ... */ }
};
category?: string
Category for organizing tools in navigation.
const tool = {
id: 'user-management',
title: 'User Management',
category: 'Administration', // Groups tools together
content: { /* ... */ }
};
tags?: string[]
Tags for search and filtering.
const tool = {
id: 'user-analytics',
title: 'User Analytics',
tags: ['analytics', 'users', 'reports', 'dashboard'],
content: { /* ... */ }
};
permissions?: string[]
Required permissions to access the tool.
const tool = {
id: 'admin-settings',
title: 'Admin Settings',
permissions: ['admin', 'settings.write'],
content: { /* ... */ }
};
Input Configuration
InputConfig Interface
interface InputConfig {
type: InputType;
label: string;
required?: boolean;
defaultValue?: any;
placeholder?: string;
description?: string;
validation?: ValidationRule[];
visible?: (inputs: Record<string, any>) => boolean;
disabled?: (inputs: Record<string, any>) => boolean;
// Type-specific properties...
}
Input Types
text
- Text Input
{
type: 'text',
label: 'Full Name',
required: true,
placeholder: 'Enter full name',
maxLength: 100,
minLength: 2,
pattern: '^[a-zA-Z\\s]+$'
}
number
- Numeric Input
{
type: 'number',
label: 'Age',
min: 0,
max: 120,
step: 1,
defaultValue: 25
}
select
- Dropdown Selection
{
type: 'select',
label: 'Country',
options: [
{ value: 'us', label: 'United States' },
{ value: 'ca', label: 'Canada' },
{ value: 'uk', label: 'United Kingdom' }
],
required: true
}
boolean
- Checkbox
{
type: 'boolean',
label: 'Active User',
defaultValue: true
}
date
- Date Picker
{
type: 'date',
label: 'Birth Date',
min: '1900-01-01',
max: '2010-12-31'
}
file
- File Upload
{
type: 'file',
label: 'Profile Picture',
accept: '.jpg,.jpeg,.png',
maxSize: 5242880 // 5MB in bytes
}
array
- Multiple Values
{
type: 'array',
label: 'Skills',
itemType: 'text',
minItems: 1,
maxItems: 10
}
Complete Tool Examples
User Management Tool
const userManagementTool = {
id: 'user-management',
title: 'User Management',
description: 'Manage user accounts, roles, and permissions',
icon: 'users',
category: 'Administration',
tags: ['users', 'admin', 'management'],
permissions: ['admin', 'users.read'],
inputs: {
searchTerm: {
type: 'text',
label: 'Search Users',
placeholder: 'Search by name or email...'
},
roleFilter: {
type: 'select',
label: 'Role Filter',
options: [
{ value: 'all', label: 'All Roles' },
{ value: 'admin', label: 'Administrators' },
{ value: 'manager', label: 'Managers' },
{ value: 'user', label: 'Users' }
],
defaultValue: 'all'
},
activeOnly: {
type: 'boolean',
label: 'Active Users Only',
defaultValue: true
}
},
content: {
type: 'editableTable',
columns: {
name: {
type: 'text',
label: 'Full Name',
required: true,
maxLength: 100
},
email: {
type: 'email',
label: 'Email Address',
required: true
},
role: {
type: 'select',
label: 'Role',
options: [
{ value: 'admin', label: 'Administrator' },
{ value: 'manager', label: 'Manager' },
{ value: 'user', label: 'User' }
],
required: true
},
active: {
type: 'boolean',
label: 'Active'
},
lastLogin: {
type: 'datetime',
label: 'Last Login'
},
createdAt: {
type: 'datetime',
label: 'Created'
}
},
tableConfig: {
pageSize: 20,
sortable: true,
searchable: true,
exportable: true
}
},
functions: {
loadData: async ({ inputs }) => {
const params = new URLSearchParams();
if (inputs.searchTerm) params.append('search', inputs.searchTerm);
if (inputs.roleFilter !== 'all') params.append('role', inputs.roleFilter);
if (inputs.activeOnly) params.append('active', 'true');
const response = await fetch(`/api/users?${params}`);
if (!response.ok) {
throw new Error('Failed to load users');
}
return response.json();
},
createRow: async ({ data }) => {
// Validation
if (!data.name?.trim()) {
throw new Error('Name is required');
}
if (!data.email?.includes('@')) {
throw new Error('Valid email is required');
}
// Check for duplicate email
const existingUser = await checkUserExists(data.email);
if (existingUser) {
throw new Error('User with this email already exists');
}
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...data,
createdAt: new Date().toISOString()
})
});
if (!response.ok) {
throw new Error('Failed to create user');
}
return response.json();
},
updateRow: async ({ data }) => {
const response = await fetch(`/api/users/${data.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...data,
updatedAt: new Date().toISOString()
})
});
if (!response.ok) {
throw new Error('Failed to update user');
}
return response.json();
},
deleteRow: async ({ id }) => {
const response = await fetch(`/api/users/${id}`, {
method: 'DELETE'
});
if (!response.ok) {
throw new Error('Failed to delete user');
}
return { success: true };
}
}
};
Analytics Dashboard Tool
const analyticsDashboardTool = {
id: 'analytics-dashboard',
title: 'Analytics Dashboard',
description: 'View comprehensive analytics and key performance indicators',
icon: 'chart-bar',
category: 'Analytics',
tags: ['analytics', 'dashboard', 'metrics', 'kpi'],
inputs: {
dateRange: {
type: 'dateRange',
label: 'Date Range',
defaultValue: {
start: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
end: new Date().toISOString().split('T')[0]
}
},
metric: {
type: 'select',
label: 'Primary Metric',
options: [
{ value: 'users', label: 'User Growth' },
{ value: 'revenue', label: 'Revenue' },
{ value: 'engagement', label: 'User Engagement' },
{ value: 'conversion', label: 'Conversion Rate' }
],
defaultValue: 'users'
},
refreshInterval: {
type: 'select',
label: 'Auto Refresh',
options: [
{ value: 'off', label: 'Off' },
{ value: '30', label: 'Every 30 seconds' },
{ value: '60', label: 'Every minute' },
{ value: '300', label: 'Every 5 minutes' }
],
defaultValue: 'off'
}
},
content: {
type: 'displayRecord',
fields: {
totalUsers: {
type: 'number',
label: 'Total Users',
format: 'compact'
},
activeUsers: {
type: 'number',
label: 'Active Users (30d)',
format: 'compact'
},
newUsers: {
type: 'number',
label: 'New Users',
format: 'compact'
},
userGrowth: {
type: 'percentage',
label: 'User Growth',
colorize: true
},
totalRevenue: {
type: 'currency',
label: 'Total Revenue',
currency: 'USD'
},
monthlyRevenue: {
type: 'currency',
label: 'Monthly Revenue',
currency: 'USD'
},
revenueGrowth: {
type: 'percentage',
label: 'Revenue Growth',
colorize: true
},
conversionRate: {
type: 'percentage',
label: 'Conversion Rate'
},
avgSessionDuration: {
type: 'duration',
label: 'Avg Session Duration'
},
lastUpdated: {
type: 'datetime',
label: 'Last Updated',
format: 'relative'
}
},
layout: 'grid',
columns: 3
},
functions: {
loadData: async ({ inputs }) => {
const params = new URLSearchParams({
startDate: inputs.dateRange?.start || '',
endDate: inputs.dateRange?.end || '',
metric: inputs.metric || 'users'
});
const response = await fetch(`/api/analytics/dashboard?${params}`);
if (!response.ok) {
throw new Error('Failed to load analytics data');
}
const data = await response.json();
// Add computed fields
return {
...data,
lastUpdated: new Date().toISOString()
};
}
}
};
Settings Configuration Tool
const settingsConfigTool = {
id: 'settings-config',
title: 'Application Settings',
description: 'Configure application settings and preferences',
icon: 'cog',
category: 'Configuration',
tags: ['settings', 'config', 'preferences'],
permissions: ['admin', 'settings.write'],
content: {
type: 'editForm',
formConfig: {
fields: [
{
type: 'group',
label: 'General Settings',
fields: [
{
name: 'appName',
type: 'text',
label: 'Application Name',
required: true,
maxLength: 100
},
{
name: 'appDescription',
type: 'textarea',
label: 'Description',
rows: 3,
maxLength: 500
},
{
name: 'timezone',
type: 'select',
label: 'Default Timezone',
options: [
{ value: 'UTC', label: 'UTC' },
{ value: 'America/New_York', label: 'Eastern Time' },
{ value: 'America/Chicago', label: 'Central Time' },
{ value: 'America/Denver', label: 'Mountain Time' },
{ value: 'America/Los_Angeles', label: 'Pacific Time' }
],
defaultValue: 'UTC'
}
]
},
{
type: 'group',
label: 'User Settings',
fields: [
{
name: 'allowRegistration',
type: 'boolean',
label: 'Allow User Registration',
defaultValue: true
},
{
name: 'requireEmailVerification',
type: 'boolean',
label: 'Require Email Verification',
defaultValue: true
},
{
name: 'maxUsers',
type: 'number',
label: 'Maximum Users',
min: 1,
max: 10000,
visible: (data) => data.allowRegistration
}
]
},
{
type: 'group',
label: 'Security Settings',
fields: [
{
name: 'sessionTimeout',
type: 'number',
label: 'Session Timeout (minutes)',
min: 5,
max: 1440,
defaultValue: 60
},
{
name: 'passwordMinLength',
type: 'number',
label: 'Minimum Password Length',
min: 6,
max: 50,
defaultValue: 8
},
{
name: 'enableTwoFactor',
type: 'boolean',
label: 'Enable Two-Factor Authentication',
defaultValue: false
}
]
}
],
submitLabel: 'Save Settings',
layout: 'vertical'
},
onSubmit: {
functionName: 'saveSettings'
}
},
functions: {
loadData: async () => {
const response = await fetch('/api/settings');
if (!response.ok) {
throw new Error('Failed to load settings');
}
return response.json();
},
saveSettings: async ({ data }) => {
// Validation
if (!data.appName?.trim()) {
throw new Error('Application name is required');
}
if (data.maxUsers && data.maxUsers < 1) {
throw new Error('Maximum users must be at least 1');
}
if (data.passwordMinLength < 6) {
throw new Error('Password minimum length must be at least 6');
}
const response = await fetch('/api/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...data,
updatedAt: new Date().toISOString()
})
});
if (!response.ok) {
throw new Error('Failed to save settings');
}
return response.json();
}
}
};
Validation and Best Practices
Tool ID Validation
// ✅ Good - Valid tool IDs
'user-management'
'analytics-dashboard'
'order-processing'
'file-upload'
// ❌ Bad - Invalid tool IDs
'User Management' // Contains spaces
'analytics_dashboard' // Use hyphens, not underscores
'order.processing' // Contains dots
'fileUpload' // Use kebab-case, not camelCase
Function Naming
// ✅ Good - Clear function names
functions: {
loadData: async () => { /* ... */ },
createUser: async () => { /* ... */ },
updateUser: async () => { /* ... */ },
deleteUser: async () => { /* ... */ },
exportData: async () => { /* ... */ }
}
// ❌ Bad - Unclear function names
functions: {
getData: async () => { /* ... */ },
doAction: async () => { /* ... */ },
process: async () => { /* ... */ },
handle: async () => { /* ... */ }
}
Error Handling
// ✅ Good - Proper error handling
functions: {
loadData: async ({ inputs }) => {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
} catch (error) {
console.error('Failed to load data:', error);
throw new Error('Unable to load data. Please try again.');
}
}
}
Input Validation
// ✅ Good - Comprehensive input validation
inputs: {
email: {
type: 'email',
label: 'Email Address',
required: true,
validation: [
{
rule: 'email',
message: 'Please enter a valid email address'
}
]
},
age: {
type: 'number',
label: 'Age',
min: 0,
max: 120,
validation: [
{
rule: 'range',
min: 0,
max: 120,
message: 'Age must be between 0 and 120'
}
]
}
}
Related APIs
- UnspecdUI Class - Main application class
- Component Types - Available component types
- Type Definitions - Complete TypeScript types
Tool Specification is the foundation of every Unspec'd application! Define your tools clearly and consistently for the best user experience. 🛠️