AI Enabler Built on Enterprise Data Models
DSiloed is the platform behind Portablemind: an AI enablement engine built on comprehensive enterprise data models, exposed through a REST API, WebSockets, and MCP tools.
This guide covers the developer surface of the platform — API integration and authentication, the MCP tools your agents can call, sandboxed Dynamic Functions, and building your own applications on the data foundation. For using the Portablemind app itself (chat, agents, files, sharing, orchestration), see the user guide.
DSiloed is built on a flexible, enterprise-grade data model designed for extensibility and integration. Here are the key components:
DSiloed is designed with an AI-first, API-driven approach. Every AI capability—from chat conversations to memory graphs to autonomous agents—is accessible through our comprehensive REST API and WebSocket connections. Build any AI-powered interface on top of our enterprise data foundation.
All sample applications in this demo are built using static JavaScript frameworks that interact with the API, demonstrating how you can create sophisticated AI-enabled applications with standard web technologies.
Ready to build? Head to API Documentation for authentication and endpoints, the MCP Tools Reference for agent tooling, or Building Your Own App to scaffold an application. Check out Sample Apps to see real-world AI applications in action.
Model Context Protocol (MCP) tools provide a standardized interface for AI models to interact with your DSiloed platform. These tools enable LLMs to perform operations, access data, manage agents, handle communications, and more.
All MCP tools are available through the MCP server and can be used by external applications, AI agents, and LLM conversations. This reference lists all 35+ available MCP tools with their descriptions and use cases.
Tools are organized into categories for easier filtering and discovery. Use these category names
with the categories query parameter to load specific tool groups.
| Category | Description | Tools |
|---|---|---|
| Create, configure, execute, and monitor AI agents | list_available_agents, execute_agent, check_agent_status, complete_agent_run, create_agent, get_tool_configuration, list_available_agent_tools, list_available_agent_resources, list_available_llm_models, list_available_prompts, set_agent_state, update_agent, delete_agent | |
| Email, conversation/guest invitations, voice calls | send_email, send_conversation_invitation, send_guest_invitation, outbound_call | |
| CRUD, schema discovery, file management, status, Tier-3 document generation | general_crud, model_schema, create_llm_file, update_llm_file, read_llm_file, list_llm_files, move_llm_file, llm_cost_stats, apply_status, run_python_skill, convert_to_pdf | |
| Persistent memory: store, load, and curate AI context | store_memory, load_memories, update_memory, forget_memory, link_memories | |
| Chat messaging and direct messages | conversation_chat, start_dm_with_user | |
| Web search and page fetch | web_research | |
| Serverless JavaScript function management | list_dynamic_functions, get_dynamic_function, execute_dynamic_function, dynamic_function_executions, manage_dynamic_function | |
| Custom LLM tool creation and management | list_llm_tools, get_llm_tool, manage_llm_tool, test_llm_tool | |
| Platform + app-development documentation assistants | dmapi_assistant, app_docs_assistant | |
| Administrative tools (logs, cost statistics) | tail_rails_log, llm_cost_stats | |
| General utilities | current_date_time | |
| Master Data Management for external system mappings | external_mappings_by_system | |
| Workflow artifacts | create_workflow_artifact | |
| Agent coordination / resource leases | coordination_tool |
?categories=data,memory to your MCP endpoint URL
to load only specific categories, or ?tools= to name individual tools.
Tools for sending emails and managing conversation invitations.
Send emails with customizable subject, body, recipients, and sender information.
Use Cases:
Key Parameters:
subject - Email subject lineemail_body - HTML email contentto_email - Recipient(s), semicolon-separatedfrom_email - Optional sender addressSend single-use invitation links for one-time feedback in LLM conversations.
Use Cases:
Send guest trial invitations allowing multiple messages before signup.
Use Cases:
Make outbound AI voice calls.
Tools for CRUD operations, schema discovery, and file management.
Comprehensive CRUD operations for all data models with advanced filtering, relationships, and aggregations.
Capabilities:
Supported Models:
Party, Individual, Organization, Contact, BizTxnEvent, Project, Task, LlmConversation, and 30+ more
Discover schema information, available columns, required fields, and data types for any model.
Use Cases:
Create text-based documents (Markdown, TXT, CSV, PDF, DOCX) programmatically.
Use Cases:
Update existing documents with new content, titles, or move to different directories.
Read file contents including text files, documents (PDF/DOCX), images, and media files.
Retrieve comprehensive LLM usage statistics, costs, and token consumption by model, user, and conversation.
Apply tracked statuses to entities (Tasks, Projects, BizTxnEvents, etc.) with proper history tracking.
Run an admin-reviewed, registered Python script (Tier-3, sandboxed subprocess) by id — e.g. generate a .pptx deck or a print-quality PDF — and persist the output as an attached file. Generates .pptx decks and print-quality PDFs from registered scripts.
Convert an existing Office document (.pptx/.docx/.xlsx) already stored as a file into a PDF, attached back to the conversation.
List files and directories in the LLM file system.
Move files or directories to a new location in the LLM file system.
Tools for creating, managing, and executing autonomous AI agents.
Create complete LLM agents with custom tools, resources, prompts, and role assignments.
Modify existing agent configurations, prompts, tools, and settings.
Permanently remove agents from the system.
List all available agents with their capabilities and descriptions.
Execute an agent with specific prompts and monitor execution status.
Check the execution status and output of running agents.
Mark agent runs as complete with success/failure status.
List all tools that can be assigned to agents during creation.
List all resources available for agent configuration.
List configured LLM models available for agent creation.
List available system and user prompts for agents.
Get configuration requirements for specific tools before assigning to agents.
Tools for persistent memory management across AI sessions.
Store facts, insights, decisions, preferences, and context as persistent memories.
Memory Types:
Retrieve relevant memories to provide context for AI conversations.
Retrieval Modes:
Correct or refine a memory you own (title, content, importance, tags) in place.
Retire (soft-archive) a memory you own so it stops surfacing in recall.
Create a typed relationship between two memories (builds the memory graph).
Tools for managing LLM conversations and messaging.
Send messages to LLM conversations and trigger AI responses.
Use Cases:
Tools for accessing platform documentation.
Ask questions about the Data Model API platform implementation and features.
Topics Covered:
Access app development documentation for building applications on the platform.
Topics Covered:
Utility and administrative tools for system operations.
Get current date and time with timezone support and multiple formats.
Root tenant only: Tail Rails application logs for debugging and monitoring.
Get external system mappings for MDM integration and data synchronization.
Tools for creating, managing, and executing serverless JavaScript functions.
List available dynamic functions with their status, schedule, and recent execution info.
Filtering Options:
active_only - Only show active functionsscheduled_only - Only show scheduled functionscallbacks_only - Only show callback functionscallback_model - Filter by callback model namename - Filter by function name (partial match)Get full details of a specific function by ID or name, including JavaScript code and execution history.
Key Parameters:
id or name - Function identifierinclude_executions - Include recent execution historyexecution_limit - Number of executions to include (max 20)Execute a dynamic function by ID or name and return results.
Key Parameters:
function_id or function_name - Function to executeparams - Parameters passed to the functionasync - Execute asynchronously (queued)Returns:
success - Execution statusresult - Function return valueexecution_id - For tracking historyexecution_time_ms - DurationCreate, update, or delete dynamic functions with full configuration support.
Actions:
create - Create new function with name, code, schedule, callbacksupdate - Modify existing function (can rename with new_name)delete - Remove functionConfiguration Options:
schedule - Cron expression for scheduled executioncallback_model - Model to trigger callback oncallback_event - Event type (create, update, destroy, all)timeout_seconds - Max execution time (1-300)configuration - Custom config including OAuthView execution history and logs for debugging and monitoring.
Filtering Options:
function_id or function_name - Filter by functionexecution_id - Get specific execution detailstrigger_type - Filter by trigger (manual, api, schedule, mcp_tool, webhook, nested_call, callback)success_only / failed_only - Filter by statuslimit - Number of records (max 100)executeAction(), make HTTP requests with fetch(),
call other functions with executeFunction(), and integrate with external systems via OAuth.
See the Dynamic Functions section for full documentation.
web_research_tool — Search and fetch the public web (DuckDuckGo / Tavily / Brave / Wikipedia).
list_llm_tools_tool — List available custom LLM Tools with their status and configuration.
get_llm_tool_tool — Get details of a specific custom LLM Tool by ID or name.
manage_llm_tool_tool — Create, update, and delete custom LLM Tools.
test_llm_tool_tool — Test-execute a custom LLM Tool with provided parameters.
external_mappings_by_system_tool — Get external-system ID mappings for integrated systems (Master Data Management).
tail_rails_log_tool — Tail Rails logs for debugging (tenant-scoped access).
llm_cost_stats_tool — Get LLM cost and token-usage statistics.
create_workflow_artifact_tool — File an organized, work-item-linked structured-work artifact (any domain).
coordination_tool — Claim / release / inspect advisory leases on shared resources (e.g. the shared DEV/PROD environment).
MCP tools can be accessed in multiple ways:
Agents can be granted these tools and use them autonomously during execution.
LLMs in conversations can invoke tools as needed to answer questions, retrieve data, or perform actions.
Connect external applications via MCP protocol to access all tools programmatically.
Create custom JavaScript tools for tenant-specific functionality via the Dynamic Functions system.
Pro Tip: Combine multiple tools in agent workflows for complex automation. For example,
use general_crud_tool to fetch data, create_llm_file_tool to generate a report,
and send_email_tool to distribute it.
DSiloed provides a comprehensive RESTful API for building applications. All endpoints follow consistent RESTful conventions with JSON responses.
Authentication uses JWT (JSON Web Tokens) passed in the Authorization header.
curl -X GET "https://example-model-api.com/api/v1/parties" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
All API requests should use JSON for request bodies and accept JSON responses.
-H "Content-Type: application/json" \
-H "Accept: application/json"
Responses follow a consistent format with data returned in an object named after the resource.
// Single resource example (e.g., GET /api/v1/users/123)
{
"success": true,
"user": {
"id": 123,
"description": "John Doe",
"created_at": "2025-05-01T12:34:56Z",
"updated_at": "2025-05-02T10:11:12Z"
}
}
// Multiple resources example (e.g., GET /api/v1/users)
{
"success": true,
"total_count": 42,
"users": [
{
"id": 123,
"description": "John Doe",
"created_at": "2025-05-01T12:34:56Z"
},
{
"id": 124,
"description": "Jane Smith",
"created_at": "2025-05-02T08:15:30Z"
}
// ... more users
]
}
Errors return a simple format with success set to false and an error message.
{
"success": false,
"message": "Invalid Access"
}
Parties represent individuals and organizations. The Party model is the foundation of your application's data model.
List all parties
curl -X GET "https://example-model-api.com/api/v1/parties" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
Get a specific party
curl -X GET "https://example-model-api.com/api/v1/parties/123" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
Create an individual
curl -X POST "https://example-model-api.com/api/v1/individuals" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"first_name": "John",
"last_name": "Doe",
"dob": "1990-01-01"
}'
Create an organization
curl -X POST "https://example-model-api.com/api/v1/organizations" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"description": "Acme Corporation"
}'
Contacts represent various contact methods like email addresses, phone numbers, and postal addresses.
List all contacts
curl -X GET "https://example-model-api.com/api/v1/contacts" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
Create an email address
curl -X POST "https://example-model-api.com/api/v1/email_addresses" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"party_id": 123,
"description": "Work Email",
"email_address": "john.doe@example.com"
}'
Create a phone number
curl -X POST "https://example-model-api.com/api/v1/phone_numbers" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"party_id": 123,
"description": "Mobile",
"phone_number": "+15551234567"
}'
Business events track activities and transactions within your application.
List all business events
curl -X GET "https://example-model-api.com/api/v1/biz_txn_events" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
Create a business event
curl -X POST "https://example-model-api.com/api/v1/biz_txn_events" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"biz_txn_event_type_id": 1,
"description": "Order Placed",
"event_date": "2025-05-11T14:30:00Z",
"amount": 99.99,
"payload": {
"order_number": "ORD-12345",
"items": 3
}
}'
Manage security, roles, and capabilities within your application.
List all security roles
curl -X GET "https://example-model-api.com/api/v1/security_roles" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
List all capabilities
curl -X GET "https://example-model-api.com/api/v1/capabilities" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
APIs for managing LLM models, tools, and conversations.
List all LLM models
curl -X GET "https://example-model-api.com/api/v1/llm_models" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
List all LLM tools
curl -X GET "https://example-model-api.com/api/v1/llm_tools" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
For complete API documentation, refer to the Swagger UI which provides interactive documentation for all available endpoints.
Dynamic Functions provide a serverless JavaScript execution environment within the DSiloed platform. They allow you to create, manage, and execute custom JavaScript functions that can integrate with external APIs, process data, and automate workflows—all without managing any infrastructure.
executeAction.
Query, create, update, and delete records from your functions.
Create a dynamic function using the REST API. Functions receive a context object with parameters, configuration, OAuth tokens, and tenant information.
// Create a function via REST API
POST /api/v1/dynamic_functions
Content-Type: application/json
{
"dynamic_function": {
"name": "hello_world",
"description": "A simple greeting function",
"javascript_code": "return { message: 'Hello, ' + (params.name || 'World') + '!' };",
"active": true,
"timeout_seconds": 30
}
}
Execute the function by ID or name:
// Execute by name
POST /api/v1/dynamic_functions/hello_world/execute
Content-Type: application/json
{
"params": {
"name": "DSiloed"
}
}
// Response:
{
"success": true,
"result": { "message": "Hello, DSiloed!" },
"execution_id": 456,
"execution_time_ms": 12
}
Functions receive a rich context with access to parameters, configuration, and built-in functions for data access and HTTP requests.
// Available context properties
params // Parameters passed when executing
config // Function configuration (excluding secrets)
functionId // Database ID of this function
functionName // Function name
tenantId // Current tenant ID
// OAuth tokens (if connected)
oauth.accessToken // OAuth access token
oauth.tokenType // Token type (usually "Bearer")
// Callback context (only in callback executions)
event // 'create', 'update', or 'destroy'
model_name // Model class name (e.g., 'Task')
record_id // ID of the affected record
record // Full record data
changes // Changed attributes (update only)
// Make HTTP requests to external APIs
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Authorization': `Bearer ${oauth.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: 'value' })
});
const data = await response.json();
return { fetched: data };
// Query tenant data
var customers = executeAction('Individual', 'list', {
filters: { role_type_id: 'customer' },
limit: 100
});
// Create records
var newContact = executeAction('PhoneNumber', 'create', {
attributes: {
party_id: 123,
phone_number: '555-1234'
}
});
// Update records
executeAction('Individual', 'update', {
id: 456,
attributes: { custom_fields: { synced: true } }
});
// Convenience wrappers also available:
listRecords(modelName, options)
getRecord(modelName, id)
createRecord(modelName, attributes)
updateRecord(modelName, id, attributes)
deleteRecord(modelName, id)
findOrCreateRecord(modelName, findAttrs, createAttrs)
// Execute another DynamicFunction by name (synchronous by default)
const result = executeFunction('helper_function', { key: 'value' });
if (result.success) {
console.log('Helper returned:', result.result);
} else {
console.error('Helper failed:', result.error);
}
// Execute asynchronously (queued for background execution)
const asyncResult = executeFunction('long_running_task', { data: params.input }, true);
// Returns immediately: { success: true, message: '...', execution_id: ... }
// Chain multiple functions together
const validation = executeFunction('validate_data', { data: params.input });
if (!validation.success || !validation.result.valid) {
return { success: false, error: 'Validation failed' };
}
const processed = executeFunction('process_data', {
data: params.input,
validationResult: validation.result
});
return processed.result;
// executeFunction(functionNameOrId, params, async)
// - functionNameOrId: Name or ID of the function
// - params: Parameters object (optional)
// - async: If true, queues for background execution (optional, default: false)
// Look up external ID for a local record
var result = getExternalId('Party', partyId, 'xero', 'xero_user_id');
if (result.found) {
console.log('Xero user ID:', result.external_id);
}
// Find local record by external ID
var projectMapping = findByExternalId('Project', 'xero', xeroProjectId);
if (projectMapping.found) {
var localProject = projectMapping.record;
}
// Store a new mapping
storeExternalMapping('Project', localProjectId, 'xero', xeroProjectId, {
column_name: 'xero_project_id',
table_name: 'xero_projects',
is_primary_key: true
});
Functions can be scheduled to run automatically using cron expressions. The scheduler checks every 30 seconds for functions due to execute.
| Schedule | Cron Expression |
|---|---|
| Every minute | * * * * * |
| Every hour | 0 * * * * |
| Daily at 9am | 0 9 * * * |
| Every Monday at 8am | 0 8 * * 1 |
| First of month at midnight | 0 0 1 * * |
| Every 15 minutes | */15 * * * * |
run_as_user_id to define
which user's permissions are used during background execution. The user must belong to the same tenant.
// Create a scheduled function
POST /api/v1/dynamic_functions
{
"dynamic_function": {
"name": "daily_sync",
"description": "Sync contacts with CRM every morning",
"javascript_code": "/* sync logic */",
"schedule": "0 9 * * *",
"timeout_seconds": 120,
"run_as_user_id": 123,
"active": true
}
}
Functions can be triggered automatically when records are created, updated, or destroyed. This enables event-driven automation without polling.
run_as_user_id to define
which user's permissions are used during callback execution. The user must belong to the same tenant.
// Create a callback function for task creation
POST /api/v1/dynamic_functions
{
"dynamic_function": {
"name": "on_task_created",
"description": "Notify team when tasks are created",
"callback_model": "Task",
"callback_event": "create",
"run_as_user_id": 123,
"javascript_code": `
// Context includes: event, model_name, record_id, record
console.log('Task created:', record.name);
// Send notification to external system
await fetch('https://slack.com/api/chat.postMessage', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + oauth.accessToken,
'Content-Type': 'application/json'
},
body: JSON.stringify({
channel: '#tasks',
text: 'New task created: ' + record.name
})
});
return { notified: true };
`
}
}
Dynamic Functions support OAuth 2.0 for integrating with external services. OAuth is configuration-based, meaning any OAuth 2.0 provider can be used without code changes.
{
"oauth": {
"provider": "xero",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"authorize_url": "https://login.xero.com/identity/connect/authorize",
"token_url": "https://identity.xero.com/connect/token",
"scopes": ["openid", "profile", "accounting.transactions.read"]
}
}
/oauth/authorize to get authorization URL
oauth.accessToken
| Endpoint | Description |
|---|---|
GET /api/v1/dynamic_functions |
List all functions |
POST /api/v1/dynamic_functions |
Create a new function |
GET /api/v1/dynamic_functions/:id |
Get function details |
PUT /api/v1/dynamic_functions/:id |
Update a function |
DELETE /api/v1/dynamic_functions/:id |
Delete a function |
POST /api/v1/dynamic_functions/:id/execute |
Execute a function (sync or async) |
GET /api/v1/dynamic_functions/:id/export |
Export function configuration |
POST /api/v1/dynamic_functions/import |
Import a function |
POST /api/v1/dynamic_functions/:id/oauth/authorize |
Start OAuth authorization |
GET /api/v1/dynamic_functions/:id/oauth/status |
Check OAuth connection status |
POST /api/v1/dynamic_functions/:id/oauth/disconnect |
Disconnect OAuth |
/api/v1/dynamic_functions/my_function/execute
AI agents can manage and execute Dynamic Functions via five dedicated MCP tools. This enables intelligent automation where AI can create, modify, and run custom code.
run_as_user_id: "current_user" for scheduled/callback functions.
Here's a complete example of a function that syncs time entries to Xero, demonstrating OAuth, data access, and MDM mapping helpers.
// Function: sync_time_entries_to_xero
// Schedule: 0 * * * * (every hour)
// Get unsynced time entries
var entries = listRecords('TimeEntry', {
filters: { status: 'approved' },
limit: 50
});
var synced = 0;
var skipped = 0;
for (var entry of entries.data) {
// Skip if already synced
var existingMapping = getExternalId('TimeEntry', entry.id, 'xero', 'xero_timeentry_id');
if (existingMapping.found) {
skipped++;
continue;
}
// Look up Xero user ID for this party
var userMapping = getExternalId('Party', entry.party_id, 'xero', 'xero_user_id');
if (!userMapping.found) {
console.log('No Xero user mapping for party:', entry.party_id);
continue;
}
// Create time entry in Xero
var xeroResponse = await fetch('https://api.xero.com/projects/timeEntries', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + oauth.accessToken,
'Content-Type': 'application/json',
'Xero-Tenant-Id': config.xero_tenant_id
},
body: JSON.stringify({
userId: userMapping.external_id,
projectId: entry.custom_fields.xero_project_id,
duration: entry.hours * 60,
description: entry.description
})
});
var xeroEntry = await xeroResponse.json();
// Store mapping for future reference
storeExternalMapping('TimeEntry', entry.id, 'xero', xeroEntry.timeEntryId, {
column_name: 'xero_timeentry_id'
});
synced++;
}
return {
success: true,
synced: synced,
skipped: skipped,
message: `Synced ${synced} entries, skipped ${skipped} already synced`
};
DSiloed comes with several sample applications that demonstrate different capabilities of the platform. Each app is built as a static JavaScript application that interacts with the API.
{{ app.description }}
Each sample application follows a similar architecture pattern:
Building your own application on top of DSiloed is straightforward. You can use any modern JavaScript framework that can make HTTP requests to the API.
Create a new project directory with the following structure. You can place this directory anywhere on your system or web server:
# Create the main app directory
mkdir -p myapp
# Create subdirectories for CSS, JavaScript, and documentation
mkdir -p myapp/css
mkdir -p myapp/js
mkdir -p myapp/js/components
mkdir -p myapp/docs
# Create basic files
touch myapp/index.html
touch myapp/css/styles.css
touch myapp/js/app.js
/apps/myapp/.
Next, download these essential components and place them in your application directory structure:
myapp/js/auth.js
myapp/js/components/LoginDialog.js
myapp/docs/
myapp/js/components/ChatAssistant.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App - DSiloed</title>
<!-- Vue and Vuetify -->
<link href="https://cdn.jsdelivr.net/npm/vuetify@3.5.11/dist/vuetify.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<!-- Custom styles -->
<link rel="stylesheet" href="css/styles.css?v=1771863622">
<!-- Auth helper -->
<script src="js/auth.js?v=1771863622"></script>
<script src="js/components/LoginDialog.js?v=1771863622"></script>
<!-- App scripts -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.21/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3.5.11/dist/vuetify.min.js"></script>
<script src="js/app.js?v=1771863622" defer></script>
</head>
<body>
<div id="app" v-cloak>
<v-app>
<v-app-bar color="primary" app>
<v-app-bar-title>My App</v-app-bar-title>
</v-app-bar>
<v-main>
<v-container>
<h1>My Custom App</h1>
<p>Welcome to my custom DSiloed application!</p>
</v-container>
</v-main>
</v-app>
</div>
</body>
</html>
// Initialize Vue app
document.addEventListener('DOMContentLoaded', function() {
const { createApp } = Vue;
const { createVuetify } = Vuetify;
// Initialize authentication
const authManager = new AuthManager('myapp');
// Create Vuetify instance
const vuetify = createVuetify();
const app = createApp({
data() {
return {
authManager: authManager,
isAuthenticated: false,
user: null,
}
},
methods: {
async initialize() {
// Initialize authentication
const authResult = await this.authManager.initialize();
this.isAuthenticated = authResult.authenticated;
this.user = authResult.user;
// Show login if not authenticated
if (!this.isAuthenticated) {
this.showLogin();
}
},
showLogin() {
const loginDialog = new LoginDialog('myapp');
loginDialog.onLogin = (result) => {
if (result.success) {
this.isAuthenticated = true;
this.user = result.user;
console.log('Logged in as:', this.user.email);
}
};
loginDialog.show();
},
logout() {
this.authManager.logout();
this.isAuthenticated = false;
this.user = null;
}
},
mounted() {
this.initialize();
}
});
app.use(vuetify);
app.mount('#app');
});
Start by creating a new React application using Create React App or your preferred tool:
# Create a new React app
npx create-react-app my-model-api-app
# Navigate to the app directory
cd my-model-api-app
# Install Material UI and other dependencies
npm install @mui/material @mui/icons-material @emotion/react @emotion/styled
Create authentication utilities to work with DSiloed:
// src/utils/auth.js
export class AuthManager {
constructor(appName) {
this.appName = appName;
this.authToken = localStorage.getItem('auth_token');
this.tenantId = localStorage.getItem('tenant_id');
this.user = null;
}
isAuthenticated() {
return !!this.authToken;
}
getToken() {
return this.authToken;
}
getTenantId() {
return this.tenantId;
}
async loadUserInfo() {
if (!this.isAuthenticated()) {
return null;
}
try {
const response = await fetch('https://modelapi.russonrails.com/api/v1/users/current', {
headers: {
'Authorization': 'Bearer ' + this.authToken,
'Tenant-Id': this.tenantId || 'root-tenant'
}
});
const data = await response.json();
if (data.success) {
this.user = data.user;
return this.user;
} else {
this.logout();
return null;
}
} catch (error) {
console.error('Error loading user info:', error);
return null;
}
}
async login(email, password, tenantId) {
try {
const response = await fetch('https://modelapi.russonrails.com/api/v1/users/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Tenant-Id': tenantId
},
body: JSON.stringify({
email: email,
password: password
})
});
const data = await response.json();
if (data.success) {
this.authToken = data.token;
this.tenantId = tenantId;
localStorage.setItem('auth_token', this.authToken);
localStorage.setItem('tenant_id', this.tenantId);
await this.loadUserInfo();
return { success: true, user: this.user };
} else {
return { success: false, message: data.message || 'Invalid email or password' };
}
} catch (error) {
console.error('Login error:', error);
return { success: false, message: 'An error occurred during login. Please try again.' };
}
}
logout() {
this.authToken = null;
this.user = null;
localStorage.removeItem('auth_token');
localStorage.removeItem('tenant_id');
window.location.href = window.location.pathname;
}
async initialize() {
if (this.isAuthenticated()) {
const user = await this.loadUserInfo();
return { authenticated: true, user: user };
}
return { authenticated: false };
}
}
// src/components/LoginDialog.jsx
import React, { useState } from 'react';
import {
Dialog, DialogTitle, DialogContent, DialogActions,
TextField, Button, CircularProgress, Alert
} from '@mui/material';
function LoginDialog({ open, onClose, onLogin, authManager }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [tenantId, setTenantId] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
setLoading(true);
try {
if (!tenantId) {
setError('Tenant ID is required');
setLoading(false);
return;
}
const result = await authManager.login(email, password, tenantId);
if (result.success) {
onLogin(result);
onClose();
} else {
setError(result.message || 'Login failed');
}
} catch (err) {
setError('An unexpected error occurred. Please try again.');
} finally {
setLoading(false);
}
};
return (
);
}
export default LoginDialog;
// src/App.jsx
import React, { useState, useEffect, useRef } from 'react';
import {
Container, AppBar, Toolbar, Typography, Button,
ThemeProvider, createTheme, CssBaseline, Box
} from '@mui/material';
import { AuthManager } from './utils/auth';
import LoginDialog from './components/LoginDialog';
const theme = createTheme({
palette: {
primary: {
main: '#3161FF',
},
secondary: {
main: '#6C63FF',
},
},
});
function App() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [user, setUser] = useState(null);
const [loginOpen, setLoginOpen] = useState(false);
const authManager = useRef(new AuthManager('myapp')).current;
useEffect(() => {
const initializeAuth = async () => {
try {
const authResult = await authManager.initialize();
setIsAuthenticated(authResult.authenticated);
setUser(authResult.user);
} catch (error) {
console.error('Auth initialization error:', error);
}
};
initializeAuth();
}, []);
const handleLogin = (result) => {
if (result.success) {
setIsAuthenticated(true);
setUser(result.user);
}
};
const handleLogout = () => {
authManager.logout();
setIsAuthenticated(false);
setUser(null);
};
return (
My App
{isAuthenticated ? (
<>
{user?.email}
>
) : (
)}
{isAuthenticated ? (
My Custom App
Welcome to my custom DSiloed application!
) : (
Welcome to My App
Please log in to access the application.
)}
setLoginOpen(false)}
onLogin={handleLogin}
authManager={authManager}
/>
);
}
export default App;
// Example API hook (src/hooks/useApi.js)
import { useState, useCallback } from 'react';
export function useApi(authManager) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const headers = useCallback(() => ({
'Authorization': 'Bearer ' + authManager.getToken(),
'Tenant-Id': authManager.getTenantId(),
'Content-Type': 'application/json'
}), [authManager]);
const fetchData = useCallback(async (endpoint, options = {}) => {
if (!authManager.isAuthenticated()) {
setError('Authentication required');
return null;
}
setLoading(true);
setError(null);
try {
const response = await fetch(`https://modelapi.russonrails.com/api/v1/${endpoint}`, {
...options,
headers: {
...headers(),
...(options.headers || {})
}
});
const data = await response.json();
if (!data.success) {
throw new Error(data.error?.message || 'API request failed');
}
return data;
} catch (err) {
setError(err.message);
return null;
} finally {
setLoading(false);
}
}, [authManager, headers]);
return { loading, error, fetchData };
}
// Using the hook in a component:
function PartyList() {
const [parties, setParties] = useState([]);
const authManager = useRef(new AuthManager('myapp')).current;
const { loading, error, fetchData } = useApi(authManager);
const loadParties = useCallback(async () => {
const data = await fetchData('parties');
if (data) {
setParties(data.parties);
}
}, [fetchData]);
useEffect(() => {
if (authManager.isAuthenticated()) {
loadParties();
}
}, [authManager, loadParties]);
if (loading) return ;
if (error) return {error} ;
return (
{parties.map(party => (
))}
);
}
Here's how to make API requests to the DSiloed backend with Vue.js:
// Example method to fetch parties
async fetchParties() {
try {
const response = await fetch('https://modelapi.russonrails.com/api/v1/parties', {
headers: {
'Authorization': 'Bearer ' + this.authManager.getToken(),
'Tenant-Id': this.authManager.getTenantId()
}
});
const data = await response.json();
if (data.success) {
this.parties = data.parties;
} else {
console.error('Error fetching parties:', data.error);
}
} catch (error) {
console.error('API request failed:', error);
}
}
Here's how to make API requests to the DSiloed backend with React:
// Using React hooks and fetch API
import { useState, useEffect, useCallback } from 'react';
function PartyList({ authManager }) {
const [parties, setParties] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchParties = useCallback(async () => {
if (!authManager.isAuthenticated()) return;
setLoading(true);
try {
const response = await fetch('https://modelapi.russonrails.com/api/v1/parties', {
headers: {
'Authorization': 'Bearer ' + authManager.getToken(),
'Tenant-Id': authManager.getTenantId()
}
});
const data = await response.json();
if (data.success) {
setParties(data.parties);
} else {
setError(data.error?.message || 'Failed to load parties');
}
} catch (error) {
setError('API request failed: ' + error.message);
} finally {
setLoading(false);
}
}, [authManager]);
useEffect(() => {
fetchParties();
}, [fetchParties]);
// UI components to display the data...
}
The ChatAssistant component provides a reusable, framework-independent chat interface that you can easily add to any application. It works with Vue.js, React, vanilla JavaScript, or any other framework.
// Include the ChatAssistant component
<script src="js/components/ChatAssistant.js?v=1771863622"></script>
// Initialize in your application
const chatAssistant = new ChatAssistant('MyApp', {
apiClient: apiClient, // Your API client instance
title: 'AI Assistant',
placeholder: 'Ask me anything...',
contextMessage: 'Assistant has access to your application data'
});
// Show/hide the chat
chatAssistant.toggle();
// In your Vue app
methods: {
initChatAssistant() {
this.chatAssistant = new ChatAssistant('MyApp', {
apiClient: apiClient,
title: 'MyApp Assistant',
placeholder: 'Ask about your data...',
contextMessage: 'Assistant can help with your application',
onError: (error) => {
this.showSnackbar('Chat error: ' + error.message, 'error');
}
});
},
toggleChat() {
if (this.chatAssistant) {
this.chatAssistant.toggle();
}
}
},
mounted() {
this.initChatAssistant();
}
import { useEffect, useRef } from 'react';
function MyApp() {
const chatAssistantRef = useRef(null);
useEffect(() => {
// Initialize ChatAssistant
chatAssistantRef.current = new ChatAssistant('MyApp', {
apiClient: apiClient,
title: 'MyApp Assistant',
onError: (error) => {
showErrorToast(error.message);
}
});
// Cleanup on unmount
return () => {
if (chatAssistantRef.current) {
chatAssistantRef.current.destroy();
}
};
}, []);
const toggleChat = () => {
if (chatAssistantRef.current) {
chatAssistantRef.current.toggle();
}
};
return (
<div>
<button onClick={toggleChat}>
Toggle Chat Assistant
</button>
{/* Your app content */}
</div>
);
}
const chatAssistant = new ChatAssistant('AppName', {
// Required
apiClient: apiClientInstance,
// UI Configuration
title: 'AI Assistant',
placeholder: 'Ask me anything...',
contextMessage: 'Assistant has access to your data',
position: 'right', // 'left' or 'right'
width: '400px',
height: '600px',
zIndex: 1000,
// Event Callbacks
onToggle: (isVisible) => {
console.log('Chat toggled:', isVisible);
},
onMessage: (message) => {
console.log('New message:', message);
},
onError: (error) => {
console.error('Chat error:', error);
}
});
The ChatAssistant automatically handles authentication using your existing apiClient instance. It will create conversations, manage message history, and provide a seamless chat experience without additional configuration.
You can use Large Language Models (LLMs) like Claude to help you build applications on top of DSiloed. Here's a prompt template to help you get started:
Use this prompt template with Claude or other AI assistants to help build your application.
For best results, download and extract the docs.zip file to your myapp/docs/ directory
and provide the documentation files to the AI for comprehensive guidance.
Simply modify the prompt template above to specify your application's requirements, then paste it to an LLM like Claude or GPT to get help building your application.
When using LLMs for app development, provide as much context as possible about your specific requirements and the data models you plan to use. This will help the LLM generate more relevant and usable code.
Now that you've explored the DSiloed platform, here are some next steps to continue your journey:
Need help with the DSiloed platform? Here are some resources to assist you:
Access comprehensive documentation for the DSiloed platform.