User Guide mdi-view-dashboard Guide Contents

Welcome to DSiloed

mdi-link

AI Enabler Built on Enterprise Data Models

DSiloed is a powerful AI enablement platform built on comprehensive enterprise data models. It provides everything you need to build intelligent, AI-powered applications with rich memory support, advanced chat features, and deep integration with leading AI providers.

Whether you're building customer service bots, intelligent automation systems, or knowledge management platforms, DSiloed gives you enterprise-grade data infrastructure combined with cutting-edge AI capabilities including persistent memory graphs, real-time chat, document processing, and autonomous agents.

This interactive guide will walk you through getting started with DSiloed, setting up AI models, leveraging memory systems, and building powerful AI-enabled enterprise applications.

Core Architecture

DSiloed is built on a flexible, enterprise-grade data model designed for extensibility and integration. Here are the key components:

Party Model

  • People and Organizations - Represented as Parties
  • Flexible Relationships - Connect parties with typed relationships
  • Role-based - Assign roles for different contexts

Business Transaction Events

  • Event-based Transactions - Track business events
  • Typed Event Relations - Connect related events
  • Party Roles in Events - Associates parties with roles in events

Security System

  • Capabilities - Fine-grained permissions
  • Security Roles - Group capabilities for assignment
  • Tenant Isolation - Multi-tenant architecture

AI & Memory System

  • Rich Memory Graphs - Persistent knowledge with pattern recognition
  • Real-time Chat - WebSocket-based conversations with AI models
  • Document Processing - PDF, DOCX, Markdown, and image support
  • Autonomous Agents - Self-improving AI with tool execution
AI-First, API-Driven Platform

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.

Quick Start

Ready to build with AI? Head to the Getting Started section to create your first tenant, or jump to Setting up AI to connect your first AI model. Check out Sample Apps to see real-world AI applications in action.

Getting Started

mdi-link
Create Your Tenant

To get started with DSiloed, you need to create a tenant. A tenant is an isolated environment for your application data. Follow these steps to create your first tenant:

Visit the tenant signup page.

Fill in the following information:

  • Tenant Name: A unique name for your tenant
  • Admin Email: Your email address for admin access
  • Password: Set a secure password

Click "Create Tenant" to complete your registration.

Your tenant will be created, and you'll be redirected to the dashboard where you can access all the available applications.

Note: Each tenant is isolated by row based security, so each tenant's data is isolated

Exploring the Dashboard

After creating your tenant, you'll be directed to the dashboard where you can access all available applications. Here's what you'll find:

{{ app.name }}

{{ app.description }}

{{ feature }}
Open App

Setting up AI with LLM Manager

mdi-link
Configure LLM Models for AI Features mdi-link

DSiloed includes powerful AI capabilities through integration with Large Language Models (LLMs). To enable AI features in your applications, you need to configure LLM models using the LLM Manager application.

This guide will walk you through setting up LLM models from various providers including Anthropic (Claude), OpenAI (GPT), Google (Gemini), xAI (Grok), and local Ollama installations.

Step 1: Choose Your LLM Provider and Get API Key mdi-link

DSiloed supports multiple LLM providers. Choose one of the following options based on your needs:

Option 1: Anthropic (Claude)

First, you'll need to obtain an API key from Anthropic to access Claude models:

Go to console.anthropic.com and sign up for an account if you don't have one.

Navigate to the API Keys section and create a new key:

  • Click "Create Key"
  • Give it a descriptive name (e.g., "DSiloed Integration")
  • Copy the generated API key (it starts with "sk-ant-")
Important: Keep your API key secure and never share it publicly. You'll only see the full key once when it's created.

Add credits to your Anthropic account to enable API usage. Even a small amount ($5-10) will provide substantial usage for development and testing.

Option 2: OpenAI (GPT)

To use OpenAI's GPT models (GPT-3.5, GPT-4), you'll need an OpenAI API key:

Go to platform.openai.com and sign up or log in to your account.

Navigate to API Keys section in your account settings:

  • Click "Create new secret key"
  • Name your key (e.g., "DSiloed Integration")
  • Copy the API key (it starts with "sk-")
Important: Save your API key securely. You won't be able to see it again.

Add credits to your OpenAI account. OpenAI uses a pay-as-you-go pricing model with different rates for each model.

Option 3: Google (Gemini)

To use Google's Gemini models, obtain an API key from Google AI Studio:

Go to makersuite.google.com and sign in with your Google account.

Create a new API key:

  • Click "Create API Key"
  • Select your project or create a new one
  • Copy the generated API key
Note: Google Gemini API has a free tier with generous limits for development.

Make sure the Generative Language API is enabled in your Google Cloud Console for your project.

Option 4: xAI (Grok)

To use xAI's Grok models, you'll need an API key from xAI:

Go to console.x.ai and sign up or log in to your account.

Navigate to the API Keys section and create a new key:

  • Click on "API Keys" in the navigation
  • Click "Create API key"
  • Name your key (e.g., "DSiloed Integration")
  • Copy the generated API key (it starts with "xai-")
Important: Store your API key securely. You won't be able to view the full key again after creation.

xAI provides $25 in free credits every month. You can add additional credits through the billing section if needed. The free tier is generous for development and testing.

Note: Grok models are designed for real-time information access and have strong reasoning capabilities.
Option 5: Local Ollama

Ollama allows you to run LLMs locally on your own hardware, providing privacy and offline capability:

Download and install Ollama from ollama.ai for your operating system.

# macOS/Linux
curl -fsSL https://ollama.ai/install.sh | sh

# Windows - Download installer from ollama.ai

Pull the models you want to use:

# Popular models
ollama pull llama2
ollama pull mistral
ollama pull codellama
ollama pull mixtral
Tip: Start with smaller models like Mistral (4GB) if you have limited RAM.

Ollama runs as a local API server on port 11434. It starts automatically after installation. No API key is needed for local usage.

# Check if Ollama is running
ollama list
Step 2: Configure LLM Model in LLM Manager mdi-link

Once you have your API key (or Ollama installed), use the LLM Manager application to create an LLM Model by selecting from pre-configured model types:

From your dashboard, click on mdi-smart-toyLLM Manager to open the LLM management application.

In the LLM Manager, click "Create LLM Model" to open the model creation dialog. You'll see provider cards for each available LLM provider. Select a provider to view their available models:

Select a provider to view available models with their specifications:

Anthropic OpenAI Google xAI Ollama

Available Anthropic Models:

Model Description Context Window Pricing claude-opus-4-20250514 Claude Opus 4.1 - Most powerful model 200K tokens $15/$75 per M tokens claude-opus-4-20241129 Claude Opus 4 - Previous generation flagship 200K tokens $15/$75 per M tokens claude-sonnet-4-20250514 Claude Sonnet 4 - Balanced performance 200K tokens $3/$15 per M tokens claude-3-7-sonnet-20250219 Claude 3.7 Sonnet - Enhanced reasoning 200K tokens $3/$15 per M tokens claude-3-5-haiku-20241022 Claude 3.5 Haiku - Fast and efficient 200K tokens $0.80/$4 per M tokens claude-3-haiku-20240307 Claude 3 Haiku - Budget-friendly 200K tokens $0.25/$1.25 per M tokens Setup: Select a model card, enter your Anthropic API key (sk-ant-...), and optionally customize the internal identifier

Available OpenAI Models:

Model Description Context Window Pricing gpt-4o GPT-4 Optimized - Best general-purpose 128K tokens $2.50/$10 per M tokens gpt-4o-mini GPT-4 Optimized Mini - Compact and efficient 128K tokens $0.15/$0.60 per M tokens o1 O1 - Advanced reasoning 200K tokens $15/$60 per M tokens o1-mini O1 Mini - Reasoning optimized 128K tokens $3/$12 per M tokens o1-preview O1 Preview - Beta reasoning model 128K tokens $15/$60 per M tokens gpt-4-turbo GPT-4 Turbo - Previous generation flagship 128K tokens $10/$30 per M tokens gpt-3.5-turbo GPT-3.5 Turbo - Legacy fast model 16K tokens $0.50/$1.50 per M tokens Setup: Select a model card, enter your OpenAI API key (sk-...), and optionally customize the internal identifier

Available Google Models:

Model Description Context Window Pricing gemini-2.5-flash-lite-latest Gemini 2.5 Flash Lite - Ultra-fast 1M tokens $0.075/$0.30 per M tokens gemini-2.5-flash-latest Gemini 2.5 Flash - Speed optimized 1M tokens $0.15/$0.60 per M tokens gemini-2.5-pro-latest Gemini 2.5 Pro - Most capable 2M tokens $1.25/$5 per M tokens Setup: Select a model card, enter your Google API key, and optionally customize the internal identifier

Available xAI Models:

Model Description Context Window Pricing grok-4-latest Grok 4 - Latest flagship model 128K tokens $5/$15 per M tokens grok-3-latest Grok 3 - Previous generation 128K tokens $3/$10 per M tokens grok-3-mini-latest Grok 3 Mini - Compact and fast 128K tokens $1/$3 per M tokens Setup: Select a model card, enter your xAI API key (xai-...), and optionally customize the internal identifier

Available Ollama Models (Local/Self-Hosted):

Model Description Context Window Size llama3.2:1b Llama 3.2 1B - Ultra-lightweight 128K tokens 1.3 GB llama3.2:3b Llama 3.2 3B - Balanced local model 128K tokens 2 GB qwen2.5:7b Qwen 2.5 7B - Multilingual 32K tokens 4.7 GB deepseek-coder-v2:16b DeepSeek Coder v2 - Code specialist 16K tokens 8.9 GB mistral:7b Mistral 7B - General-purpose 32K tokens 4.1 GB mixtral:8x7b Mixtral 8x7B - Mixture of experts 32K tokens 26 GB Setup: Select a model card, set API URL to http://localhost:11434 (or your Ollama server), leave API key empty for local setup Note: Ollama models run locally and require Ollama to be installed and running on your machine or server

After selecting your model:

  1. Enter your API key (or configure API URL for Ollama)
  2. Set the internal_identifier - this is what you'll use in configuration references like embedding_model_name
  3. Click "Create LLM Model" to save
The model will be available immediately throughout the DSiloed platform with consistent pricing, context windows, and capabilities from the selected LlmModelProductType.
Connecting Claude Code to DSiloed MCP Server mdi-link

Connect Claude Code to your DSiloed tenant using the Model Context Protocol (MCP) to access all your data, conversations, memories, and platform capabilities directly from your development environment.

What is Claude Code?

Claude Code is Anthropic's official CLI for Claude that integrates AI assistance directly into your terminal and development workflow. By connecting it to DSiloed's MCP server, Claude gains access to your tenant's data and can help you manage projects, conversations, documents, and more.

Navigate to your DSiloed dashboard to copy your authentication token:

  1. Open dashboard.html in your browser
  2. Log in with your credentials if you haven't already
  3. Look for the JWT token display section
  4. Click the copy button to copy your JWT token to clipboard
Security Note: Your JWT token provides full access to your tenant data. Keep it secure and never share it publicly or commit it to version control.

Add the DSiloed MCP server configuration to your Claude Code settings:

Important: Configuration Location

The MCP server configuration is placed in the projects section of your ~/.claude.json file, where each project is keyed by its full directory path. Each project can have its own mcpServers configuration.

  1. Open or create your Claude Code configuration file at ~/.claude.json
  2. Locate or create the projects section
  3. Add an entry for your project using the full directory path as the key
  4. Inside that project, add the mcpServers object with your DSiloed configuration

Complete ~/.claude.json file structure:

{
  "projects": {
    "/home/username/my-project": {
      "mcpServers": {
        "harmoniq": {
          "command": "npx",
          "args": [
            "mcp-remote",
            "https://dev.dsiloed.com/api/v1/mcp",
            "--header",
            "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
          ]
        }
      }
    }
  }
}
Configuration Notes:
  • Replace /home/username/my-project with the full path to your project directory
  • Replace YOUR_JWT_TOKEN_HERE with the JWT token you copied from the dashboard
  • For production: Use https://www.dsiloed.com/api/v1/mcp
  • For development: Use https://dev.dsiloed.com/api/v1/mcp
  • You can customize the server name (currently "harmoniq") to anything you prefer
  • On Windows, use forward slashes: C:/Users/username/my-project

Production example with actual token (truncated):

{
  "projects": {
    "/Users/john/projects/my-app": {
      "mcpServers": {
        "harmoniq": {
          "command": "npx",
          "args": [
            "mcp-remote",
            "https://www.dsiloed.com/api/v1/mcp",
            "--header",
            "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ..."
          ]
        }
      }
    }
  }
}

Multiple projects with different configurations:

{
  "projects": {
    "/home/username/project-one": {
      "mcpServers": {
        "harmoniq": {
          "command": "npx",
          "args": [
            "mcp-remote",
            "https://dev.dsiloed.com/api/v1/mcp",
            "--header",
            "Authorization: Bearer DEV_TOKEN_HERE"
          ]
        }
      }
    },
    "/home/username/project-two": {
      "mcpServers": {
        "harmoniq": {
          "command": "npx",
          "args": [
            "mcp-remote",
            "https://www.dsiloed.com/api/v1/mcp",
            "--header",
            "Authorization: Bearer PROD_TOKEN_HERE"
          ]
        },
        "other-server": {
          "command": "some-command",
          "args": ["arg1"]
        }
      }
    }
  }
}
Pro Tip: Each project directory can have different MCP server configurations, allowing you to connect to different DSiloed tenants or environments based on the project you're working on.

Test your MCP connection:

  1. Start a new Claude Code session in your terminal
  2. The MCP server should connect automatically when Claude Code starts
  3. Ask Claude to list your conversations or check your memories to verify access

Example queries to test:

  • "Can you show me my recent conversations?"
  • "What memories do we have stored?"
  • "List my current tasks"
  • "Show me the parties in the system"
You're Connected!

Claude Code now has full access to your DSiloed tenant through 30+ MCP tools including data management, conversations, memories, agents, file operations, and more.

With Claude Code connected to DSiloed MCP, you can:

Data Management
  • Query and manage parties, contacts, tasks
  • Create and update business transactions
  • Access full CRUD operations
Conversations & Memory
  • Access conversation history
  • Load and store persistent memories
  • Maintain context across sessions
Agent Management
  • Create and configure AI agents
  • Execute agent runs
  • Monitor agent status
File Operations
  • Create and update documents
  • Read file contents
  • Manage conversation attachments
Step 3: Test Your AI Setup mdi-link

After configuring your LLM model, you can test it in several ways:

Chat Assistant

Look for the chat icon in any application's interface to start a conversation with your AI model.

LLM Manager

Use the conversation features in LLM Manager to test model responses directly.

Congratulations! Your AI is now set up and ready to use. The AI can help you with data analysis, content creation, and building applications throughout the DSiloed platform.
Available AI Features

With your LLM model configured, you can now use AI features throughout the platform:

Conversational AI

Chat with AI assistants that understand your business context and data.

App Generation

Get help building custom applications with AI-generated code and guidance.

Document Analysis

Upload and interact with documents using the Document Manager application.

Setting up an AI Agent

AI Agents are sophisticated autonomous systems that can perform complex tasks using AI models, tools, and scheduling. The Visual Agent Builder provides an intuitive interface for creating and configuring these powerful AI agents.

Understanding Agent Components

An AI Agent consists of eight key components, each serving a specific purpose in the agent's operation:

LLM Model

Purpose: The AI brain of your agent

Connects to your configured AI model (like Claude) to process information and make decisions. This determines the intelligence and capabilities of your agent.

Prompts (System + User)

Purpose: Dual-layer instructions for enhanced AI control

System Prompt: Defines personality, behavior patterns, and operational constraints

User Prompt: Contains specific task instructions and execution objectives

Roles

Purpose: Context-based behavioral guidelines

Assigns specific roles (like Software Engineer, Designer) that provide context and persona for execution. Agents can use multiple roles or specific role combinations during execution.

Resources

Purpose: Data sources and information access

Provides the agent with access to databases, APIs, documents, and other information sources it needs to complete its tasks effectively.

Schedule

Purpose: Automated execution timing

Controls when and how often the agent runs. Can be set for one-time execution, recurring schedules, or event-triggered activation.

Tools

Purpose: Actions the agent can perform

Equips the agent with specific capabilities like sending emails, creating reports, updating databases, or integrating with external systems.

Conversations

Purpose: Communication history and context

Maintains conversation history and context, allowing the agent to remember previous interactions and maintain continuity across sessions.

Security Roles

Purpose: Permission-based access control

Controls what capabilities and resources the agent can access. Separate from behavioral roles, these determine API permissions and security constraints.

Setting Up Your First Agent

Follow these steps to create your own AI Agent using the Visual Agent Builder:

Navigate to the LLM Manager application and look for the "Agent Builder" or "Visual Agent Builder" option. This opens the drag-and-drop interface shown in the screenshot above.

Set up the essential components in this order:

  • Agent Name: Give your agent a descriptive name (e.g., "Content Creation Agent")
  • LLM Model: Select your configured AI model (e.g., Claude 3.5 Sonnet)
  • System Prompt: Define the agent's personality, behavior patterns, and operational guidelines
  • User Prompt: Write specific task instructions for what the agent should accomplish
  • Roles (Pink Card): Assign behavioral roles like "Software Engineer" or "Designer" to provide execution context
  • Security Roles (Purple Card): Assign permission roles like "Content Manager" to control API and resource access

Equip your agent with the capabilities it needs:

  • Tools: Select from system tools (email, database) or create custom tools
  • Resources: Grant access to specific data sources or APIs
  • Connect Components: Use the visual interface to link components together

Configure when your agent should run:

  • Manual: Run on-demand when triggered
  • Scheduled: Set recurring intervals (every 5 minutes, daily, weekly)
  • Event-triggered: Activate based on specific system events

Before activating your agent:

  • Manual Execution: Use the Execute button to run the agent manually with optional role selection
  • Role Testing: Try different role combinations to test behavior variations
  • Additional Instructions: Test with custom execution instructions to ensure flexibility
  • Review Connections: Ensure all components are properly linked in the Visual Builder
  • Activate: Turn on the agent to begin automated scheduled operation

Manual Agent Execution with Role Selection

Beyond scheduled automation, agents can be executed manually with fine-grained control over their behavior through role selection and additional instructions.

Manual Execution

Click the Execute button on any agent to:

  • Run the agent immediately without waiting for schedule
  • Add specific instructions for this execution
  • Select which roles the agent should use
  • Test agent behavior before scheduling
Role Selection

During manual execution:

  • All agent roles are pre-selected by default
  • Deselect specific roles to modify behavior
  • Each role includes ID and persona details
  • Agents adapt behavior based on selected roles
Advanced Tip: Use manual execution with different role combinations to test how your agent behaves in various contexts. For example, a content agent with only "Technical Writer" role selected might focus more on documentation, while adding "Marketing Specialist" could make it more promotional. Enhanced Example: A "Content Creation Agent" with roles like "Software Engineer" and "Technical Writer" could automatically generate documentation. During manual execution, you could select only the "Technical Writer" role for user-focused docs, or both roles for technical implementation guides, while adding specific instructions like "focus on API endpoints."

Agent Architecture: Party and User Integration

Each LLM Agent is automatically configured with both Party and User entities, providing comprehensive identity and security management:

Party Entity (Identity)
  • Provides agent identity in the party management system
  • Enables role-based behavior through PartyRoles
  • Links agent to broader organizational structure
  • Supports behavioral context for execution
User Account (Security)
  • Username matches the agent's name
  • Provides security context through SecurityRoles
  • Enables capability-based access control
  • No email required (agent users are email-less)

Dual Role System in Visual Agent Builder

The Visual Agent Builder includes two distinct role management systems, each serving different purposes:

Roles Card (Behavioral)

Purpose: Define agent personality and expertise

  • Pink-themed visual card positioned above agent
  • Shows current PartyRole count
  • Click to manage behavioral roles
  • Controls execution context and decision making
  • Examples: "Software Engineer", "Technical Writer"
Security Roles Card (Permissions)

Purpose: Control API and resource access

  • Purple-themed visual card positioned below agent
  • Shows current SecurityRole count
  • Click to manage permission roles
  • Defines what capabilities the agent can access
  • Examples: "Content Manager", "Data Analyst"

Security Role Management

Security roles are assigned to the agent's User account for fine-grained permission control. Here's how to manage them programmatically:

API Example: Assign Security Role
// Assign a security role to an agent's user account
await apiClient.createSecurityRoleAssignment({
  accessor_record_type: 'User',
  accessor_record_id: agent.user.id,
  security_role_id: securityRoleId
});

// Example: Assign content manager role
const contentManagerRole = await apiClient.getSecurityRoles({ 
  internal_identifier: 'content_manager' 
});

await apiClient.createSecurityRoleAssignment({
  accessor_record_type: 'User',
  accessor_record_id: agent.user.id,
  security_role_id: contentManagerRole.security_roles[0].id
});
API Response Structure: LLM Agent responses include comprehensive data about both Party and User relationships. The user object contains security_roles array, while party_roles contains behavioral roles with full role_type details. Security Best Practices:
  • Use Principle of Least Privilege - only assign security roles agents actually need
  • Separate behavioral roles (PartyRoles) from permission roles (SecurityRoles)
  • Regularly audit agent security role assignments
  • Always review and test agents thoroughly before activation

LLM Memory System

mdi-link
What is LLM Memory?

The LLM Memory System provides persistent memory capabilities for AI agents and conversations, enabling long-term learning, pattern recognition, and contextual awareness across sessions. Unlike simple chat history, the memory system uses advanced vector embeddings and graph-based relationships to store and retrieve information semantically.

Why is Memory Important? With LLM Memory, your AI can remember user preferences, previous conversations, learned patterns, and contextual information across sessions. This dramatically improves the quality and relevance of AI responses, making interactions feel more natural and personalized.
Key Features Vector Embeddings

85-100% Accuracy: Advanced semantic similarity matching using OpenAI embeddings

Find memories based on meaning, not just keywords. "What does Ben like?" matches "Ben Koloski loves spaghetti"

Graph-Based Storage

Relationship Tracking: Memories are connected through typed relationships

Build knowledge graphs showing how facts, preferences, and insights relate to each other

Automatic Pattern Recognition

Background Processing: Daily consolidation jobs identify patterns

Automatically extract insights from related memories and create derived knowledge

Multi-Tenant Isolation

Secure by Design: Complete data isolation between tenants

Each tenant's memories are stored separately with capability-based access control

Memory Types

Fact: Specific facts, data points, or verified information Preference: User preferences, settings, or choices Decision: Important decisions made during conversations Insight: Analysis, conclusions, or discovered patterns Context: Background information or situational context Solution: Technical solutions, fixes, or configurations
Configuring LLM Memory

LLM Memory is configured through the memory_management Configuration. The system requires OpenAI's Text Embedding 3 Small model for vector embeddings, which provides high-quality semantic similarity matching.

⚠️ OpenAI Text Embedding 3 Small REQUIRED:
  1. Only OpenAI Supported: The database uses 1536-dimensional vectors matching OpenAI Text Embedding 3 Small. Other providers are incompatible.
  2. Create LlmModel First: In LLM Manager, create an LlmModel using "Text Embedding 3 Small (1536-dim)" with your OpenAI API key.
  3. Use internal_identifier: Reference your embedding model by its internal_identifier in the configuration.

Configuration Parameters

Parameter Description Example Value enable_embeddings Enable vector embedding generation for semantic search true embedding_model_name internal_identifier of your OpenAI embedding LlmModel 'openai-embeddings' embedding_dimensions FIXED: Must be 1536 (OpenAI Text Embedding 3 Small) 1536 embedding_similarity_threshold Minimum similarity score (0.0-1.0) for memory retrieval 0.7 max_embedding_length Maximum characters to process for embeddings 8000 classification_model_name internal_identifier of LlmModel for semantic relationship classification (optional) 'classifier' or null classification_method Classification approach: 'heuristic', 'llm', or 'hybrid' (recommended) 'hybrid' classification_llm_threshold_score Minimum similarity score (0.0-1.0) to trigger LLM classification 0.9 classification_llm_threshold_importance Minimum importance score (0.0-1.0) for LLM classification 0.8 classification_max_llm_calls_per_consolidation Maximum LLM API calls per consolidation run (cost control) 50 Semantic Relationship Classification: The classification parameters control how the system determines the type of relationship between memories (e.g., "caused_by", "leads_to", "supersedes"). Setting classification_model_name enables LLM-based classification for highly accurate semantic relationships. If null, the system uses fast rule-based heuristics only.

Configuration Example

Using the API
// Step 1: Create OpenAI embedding model in LLM Manager first
// Step 2: Optionally create a classifier model (e.g., GPT-3.5-turbo or GPT-4)
// Step 3: Use internal_identifiers in this configuration

const response = await fetch('/api/v1/configurations', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + token,
    'Tenant-Id': tenantId,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    configuration: {
      internal_identifier: 'memory_management',
      configuration_type_id: 'memory_management',
      configuration_values: {
        // Vector Embeddings (Required for semantic search)
        enable_embeddings: true,
        embedding_model_name: 'openai-embeddings',  // Your embedding LlmModel
        embedding_dimensions: 1536,                  // Fixed - do not change
        embedding_similarity_threshold: 0.7,
        max_embedding_length: 8000,

        // Relationship Classification (Optional but recommended)
        classification_model_name: 'classifier',     // Your classifier LlmModel (null = heuristics only)
        classification_method: 'hybrid',             // 'heuristic', 'llm', or 'hybrid'
        classification_llm_threshold_score: 0.9,     // Similarity threshold for LLM usage
        classification_llm_threshold_importance: 0.8, // Importance threshold for LLM usage
        classification_max_llm_calls_per_consolidation: 50  // Cost control limit
      }
    }
  })
});
Using Rails Console
# Step 1: Create OpenAI embedding model in LLM Manager first
# Step 2: Optionally create a classifier model (e.g., GPT-3.5-turbo or GPT-4)
# Step 3: Use internal_identifiers in this configuration

# Find your tenant
tenant = Tenant.find_by(enterprise_identifier: 'your-tenant')

# Create or update memory_management configuration
config = Configuration.find_or_initialize_by(
  tenant: tenant,
  internal_identifier: 'memory_management'
)

config.update!(
  configuration_values: {
    # Vector Embeddings (Required for semantic search)
    'enable_embeddings' => true,
    'embedding_model_name' => 'openai-embeddings',  # Your embedding LlmModel
    'embedding_dimensions' => 1536,                  # Fixed - do not change
    'embedding_similarity_threshold' => 0.7,
    'max_embedding_length' => 8000,

    # Relationship Classification (Optional but recommended)
    'classification_model_name' => 'classifier',     # Your classifier LlmModel (nil = heuristics only)
    'classification_method' => 'hybrid',             # 'heuristic', 'llm', or 'hybrid'
    'classification_llm_threshold_score' => 0.9,     # Similarity threshold for LLM usage
    'classification_llm_threshold_importance' => 0.8, # Importance threshold for LLM usage
    'classification_max_llm_calls_per_consolidation' => 50  # Cost control limit
  }
)

Semantic Relationship Classification

When memories are connected, the system automatically classifies the type of relationship between them using intelligent semantic analysis. This creates meaningful knowledge graphs instead of generic "related to" connections.

Rule-Based Classification

Fast, zero-cost pattern matching

Uses keyword detection to identify relationships like "caused_by", "leads_to", "supersedes"

Example: "Fixed bug caused by null pointer" → detects "caused_by" relationship

LLM-Based Classification

High-accuracy semantic analysis

Uses configured LLM model for precise relationship classification on important memories

Triggered selectively based on similarity and importance thresholds to manage costs

Hybrid Approach (Recommended): Combines fast rule-based heuristics with selective LLM classification for important cases. This provides excellent accuracy while keeping costs low (typically <5% of relationships use LLM, ~$0.01/day for active tenants).

Available Relationship Types

caused_by: Causal relationships (bug caused by configuration) leads_to: Consequence relationships (decision leads to implementation) contradicts: Conflicting information references: Cross-references (implementation references design) spawns: Parent-child generation (feature spawns subtasks) supersedes: Replacement (new approach supersedes old solution) validates: Test or verification exemplifies: Pattern demonstration

Automatic Background Processing

Once configured, the memory system runs automatic background jobs to maintain and enhance memory quality:

Memory Consolidation (Daily 3am): Identifies patterns, creates relationships, extracts derived insights Memory Pruning (Weekly Sunday 4am): Cleans up low-importance memories and consolidates duplicates Agent Learning (Daily 6am): Analyzes execution patterns and improves agent performance
Using Memory in Your Applications

The memory system integrates seamlessly with AI conversations and agents. Memories are automatically loaded and used to provide context for AI responses.

Common Use Cases

Personalized AI Assistants

Remember user preferences, work patterns, and communication styles across sessions for natural, personalized interactions

Development Agents

Store solutions, code patterns, and architectural decisions to improve code quality and consistency over time

Healthcare Applications

Remember patient history, treatment preferences, and clinical insights while maintaining HIPAA compliance through multi-tenant isolation

Business Intelligence

Track customer insights, market trends, and strategic decisions to build organizational knowledge over time

Recommended: Configure LLM Memory to unlock the full potential of your AI applications. The semantic search capabilities and automatic pattern recognition significantly improve AI response quality and user satisfaction.

Chat Features and LLM Integration

mdi-link
ChatAssistant Component

DSiloed includes a powerful, reusable ChatAssistant component that provides AI-powered chat capabilities to any application. The component is framework-independent and features a modern, Discord-like interface with conversation management.

Key Features

Responsive design with quarter-screen flyout that expands to fullscreen Real-time chat with AI assistants using @ai mentions Multi-member conversations with role-based access File attachment support (PDFs, images, documents) Dark mode support with automatic theme detection Webhook integration for external message ingestion
@AI Mentions and LLM Integration

The ChatAssistant component supports intelligent @ai mentions that allow users to interact with specific LLM models within conversations.

@AI Mention Syntax

@ai - Uses the default AI model @ai:model_name - Uses a specific AI model @ai:model_name/compact - Uses a specific model with compaction @ai/compact - Uses default model with conversation compaction

Examples

@ai Can you help me analyze this data? Uses the default AI model @ai:claude-3-5-sonnet Please review this code Uses Claude 3.5 Sonnet specifically @ai:gpt-4/compact Summarize our conversation Uses GPT-4 with conversation compaction Note: Messages without @ai mentions are saved as user messages without triggering AI responses, allowing for mixed human-AI conversations.
Implementation Guide

Basic Setup

// Include the ChatAssistant component
<script src="js/components/ChatAssistant.js?v=1764792677"></script>

// Initialize with your API client
const chatAssistant = new ChatAssistant('YourAppName', {
    apiClient: apiClient,
    title: 'AI Assistant',
    placeholder: 'Ask me anything...',
    contextMessage: 'Assistant has access to your data'
});

// Toggle chat visibility
chatAssistant.toggle();

Vue.js Integration

// In your Vue component
methods: {
    initChatAssistant() {
        this.chatAssistant = new ChatAssistant('MyApp', {
            apiClient: this.apiClient,
            title: 'MyApp Assistant',
            onError: (error) => {
                this.showSnackbar('Chat error: ' + error.message, 'error');
            }
        });
    },
    toggleChat() {
        if (this.chatAssistant) {
            this.chatAssistant.toggle();
        }
    }
},
mounted() {
    this.initChatAssistant();
}

React Integration

// In your React component
import { useEffect, useRef } from 'react';

function MyApp() {
    const chatAssistantRef = useRef(null);
    
    useEffect(() => {
        chatAssistantRef.current = new ChatAssistant('MyApp', {
            apiClient: apiClient,
            title: 'MyApp Assistant'
        });
    }, []);
    
    const toggleChat = () => {
        if (chatAssistantRef.current) {
            chatAssistantRef.current.toggle();
        }
    };
    
    return (
        <button onClick={toggleChat}>Toggle Chat</button>
    );
}
Webhooks for External Integration

Webhooks allow external systems to send messages directly into conversations without authentication. This enables integration with external applications, chatbots, monitoring systems, and more.

Creating Webhooks

Webhooks can be created through the ChatAssistant Settings interface or via API. Each webhook generates a unique URL that external systems can use to post messages.

Webhook API Endpoint

POST /api/v1/webhooks/:key/publish_message

Example CURL Request

# Send a message via webhook
curl -X POST "https://your-domain.com/api/v1/webhooks/your-webhook-key/publish_message" \
     -H "Content-Type: application/json" \
     -d '{
       "message": "Alert: Server CPU usage is at 85%"
     }'

Advanced Usage with @AI Mentions

# Send a message that triggers AI response
curl -X POST "https://your-domain.com/api/v1/webhooks/your-webhook-key/publish_message" \
     -H "Content-Type: application/json" \
     -d '{
       "message": "@ai Please analyze this error and suggest a solution: Database connection timeout after 30 seconds"
     }'

Creating Webhooks via API

// Create a new webhook for a conversation
const webhookData = {
  webhook: {
    name: "Server Monitoring",
    description: "Webhook for server monitoring alerts",
    related_entity_type: "LlmConversation",
    related_entity_id: conversationId,
    direction: "inbound"
  }
};

const response = await fetch('/api/v1/webhooks', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + token,
    'Tenant-Id': tenantId,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(webhookData)
});

const result = await response.json();
console.log('Webhook URL:', result.webhook.url);
Security Note: Webhook URLs contain unique keys and should be treated as sensitive. Store them securely and rotate them if compromised.
Configuration Options

ChatAssistant Configuration

apiClient (required) API client instance for making requests title Chat window title (default: "AI Assistant") placeholder Input placeholder text contextMessage Context message shown at top of chat position 'left' or 'right' (default: 'right') onToggle Callback function when chat is toggled onMessage Callback function for new messages onError Error handler callback function

MCP Tools Reference

mdi-link
About MCP Tools

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.

Note: These tools are automatically available to LLM agents configured in your tenant. External applications can also access these tools through the MCP protocol.
mdi-email Communication Tools

Tools for sending emails and managing conversation invitations.

send_email_tool

Send emails with customizable subject, body, recipients, and sender information.

Use Cases:

  • Send notifications to users
  • Email reports and summaries
  • Bulk communications to multiple recipients

Key Parameters:

  • subject - Email subject line
  • email_body - HTML email content
  • to_email - Recipient(s), semicolon-separated
  • from_email - Optional sender address
send_conversation_invitation_tool

Send single-use invitation links for one-time feedback in LLM conversations.

Use Cases:

  • Request specific feedback or answers
  • One-time input collection
  • Quick survey responses
send_guest_invitation_tool

Send guest trial invitations allowing multiple messages before signup.

Use Cases:

  • Progressive user engagement
  • Trial conversation access
  • Guest-to-member conversion flows
mdi-database Data Management Tools

Tools for CRUD operations, schema discovery, and file management.

general_crud_tool Most Used

Comprehensive CRUD operations for all data models with advanced filtering, relationships, and aggregations.

Capabilities:

  • Create, Read, Update, Delete operations
  • Advanced search with JSON query syntax
  • Relationship management (link/unlink)
  • Aggregations and analytics
  • Field-level selection for performance

Supported Models:

Party, Individual, Organization, Contact, BizTxnEvent, Project, Task, LlmConversation, and 30+ more

model_schema_tool

Discover schema information, available columns, required fields, and data types for any model.

Use Cases:

  • Understand model structure before queries
  • Identify required fields for creation
  • Discover available relationships
create_llm_file_tool

Create text-based documents (Markdown, TXT, CSV, PDF, DOCX) programmatically.

Use Cases:

  • Generate reports and summaries
  • Create documentation
  • Save analysis results
update_llm_file_tool

Update existing documents with new content, titles, or move to different directories.

read_llm_file_tool

Read file contents including text files, documents (PDF/DOCX), images, and media files.

llm_cost_stats_tool

Retrieve comprehensive LLM usage statistics, costs, and token consumption by model, user, and conversation.

apply_status_tool

Apply tracked statuses to entities (Tasks, Projects, BizTxnEvents, etc.) with proper history tracking.

mdi-robot Agent Management Tools

Tools for creating, managing, and executing autonomous AI agents.

create_agent_tool

Create complete LLM agents with custom tools, resources, prompts, and role assignments.

update_agent_tool

Modify existing agent configurations, prompts, tools, and settings.

delete_agent_tool

Permanently remove agents from the system.

list_available_agents_tool

List all available agents with their capabilities and descriptions.

execute_agent_tool

Execute an agent with specific prompts and monitor execution status.

check_agent_status_tool

Check the execution status and output of running agents.

complete_agent_run_tool

Mark agent runs as complete with success/failure status.

list_available_agent_tools_tool

List all tools that can be assigned to agents during creation.

list_available_agent_resources_tool

List all resources available for agent configuration.

list_available_llm_models_tool

List configured LLM models available for agent creation.

list_available_prompts_tool

List available system and user prompts for agents.

get_tool_configuration_tool

Get configuration requirements for specific tools before assigning to agents.

mdi-brain Memory Tools

Tools for persistent memory management across AI sessions.

store_memory_tool

Store facts, insights, decisions, preferences, and context as persistent memories.

Memory Types:

  • Fact - Specific data points and verified information
  • Preference - User settings and choices
  • Decision - Important choices made
  • Insight - Analysis and patterns
  • Solution - Technical fixes and configurations
  • Goal - User objectives
load_memories_tool

Retrieve relevant memories to provide context for AI conversations.

Retrieval Modes:

  • Search - Content-based keyword search
  • Semantic - Vector similarity search
  • Recent - Recently created memories
  • Important - High-importance memories
  • Conversation/Agent specific
mdi-chat Conversation Tools

Tools for managing LLM conversations and messaging.

conversation_chat_tool

Send messages to LLM conversations and trigger AI responses.

Use Cases:

  • External system integration
  • Automated message sending
  • Custom chat interfaces
mdi-book-open Documentation Tools

Tools for accessing platform documentation.

dmapi_assistant_tool

Ask questions about the Data Model API platform implementation and features.

Topics Covered:

  • Security and capability system
  • API endpoints and responses
  • Model relationships
  • MCP integration
  • Webhook system
app_docs_assistant_tool

Access app development documentation for building applications on the platform.

Topics Covered:

  • Authentication setup
  • API client usage
  • Shared components
  • Best practices
mdi-tools Utility & Admin Tools

Utility and administrative tools for system operations.

current_date_time_tool

Get current date and time with timezone support and multiple formats.

tail_rails_log_tool Admin Only

Root tenant only: Tail Rails application logs for debugging and monitoring.

external_mappings_by_system_tool

Get external system mappings for MDM integration and data synchronization.

mdi-function Dynamic Functions Tools

Tools for creating, managing, and executing serverless JavaScript functions.

list_dynamic_functions_tool

List available dynamic functions with their status, schedule, and recent execution info.

Filtering Options:

  • active_only - Only show active functions
  • scheduled_only - Only show scheduled functions
  • callbacks_only - Only show callback functions
  • callback_model - Filter by callback model name
  • name - Filter by function name (partial match)
get_dynamic_function_tool

Get full details of a specific function by ID or name, including JavaScript code and execution history.

Key Parameters:

  • id or name - Function identifier
  • include_executions - Include recent execution history
  • execution_limit - Number of executions to include (max 20)
execute_dynamic_function_tool

Execute a dynamic function by ID or name and return results.

Key Parameters:

  • function_id or function_name - Function to execute
  • params - Parameters passed to the function
  • async - Execute asynchronously (queued)

Returns:

  • success - Execution status
  • result - Function return value
  • execution_id - For tracking history
  • execution_time_ms - Duration
manage_dynamic_function_tool CRUD

Create, update, or delete dynamic functions with full configuration support.

Actions:

  • create - Create new function with name, code, schedule, callbacks
  • update - Modify existing function (can rename with new_name)
  • delete - Remove function

Configuration Options:

  • schedule - Cron expression for scheduled execution
  • callback_model - Model to trigger callback on
  • callback_event - Event type (create, update, destroy, all)
  • timeout_seconds - Max execution time (1-300)
  • configuration - Custom config including OAuth
dynamic_function_executions_tool

View execution history and logs for debugging and monitoring.

Filtering Options:

  • function_id or function_name - Filter by function
  • execution_id - Get specific execution details
  • trigger_type - Filter by trigger (manual, api, schedule, mcp_tool, webhook, nested_call, callback)
  • success_only / failed_only - Filter by status
  • limit - Number of records (max 100)
Tip: Dynamic Functions can access tenant data via 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.
Using MCP Tools

MCP tools can be accessed in multiple ways:

In LLM Agents

Configure tools when creating agents in LLM Manager. Agents can use these tools autonomously during execution.

In Conversations

LLMs in conversations can invoke tools as needed to answer questions, retrieve data, or perform actions.

External Applications

Connect external applications via MCP protocol to access all tools programmatically.

Custom Tools

Create custom tools in LLM Manager using JavaScript for tenant-specific functionality.

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.

API Documentation

mdi-link
RESTful API Overview

DSiloed provides a comprehensive RESTful API for building applications. All endpoints follow consistent RESTful conventions with JSON responses.

Authentication

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"

Content Types

All API requests should use JSON for request bodies and accept JSON responses.

-H "Content-Type: application/json" \
-H "Accept: application/json"

Response Format

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
  ]
}

Error Handling

Errors return a simple format with success set to false and an error message.

{
  "success": false,
  "message": "Invalid Access"
}
Core Resources Parties Contacts Business Events Security LLM Integration

Parties API

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 API

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 API

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
      }
    }'

Security API

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"

LLM Integration API

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"
Swagger Documentation

For complete API documentation, refer to the Swagger UI which provides interactive documentation for all available endpoints.

Open Swagger Documentation

Guest User Invitations

mdi-link
Overview

Guest Users allow you to invite new users who have never used the platform before. These "guest users" are created directly in your tenant with scoped access to specific resources, making them ideal for contractors, clients, and consultants who need temporary or limited access.

Guest Users vs Cross-Tenant Sharing

Factor Guest User Cross-Tenant Sharing User Status New to platform Existing tenant user Account Creation Create user in your tenant User already exists User Experience Single workspace (your tenant) Multiple workspaces (switch between) Best For Contractors, clients, consultants Partners, service providers Conversion Path Can upgrade to full tenant later Already has full tenant

Guest User Workflow

Create a new user in your tenant with the is_guest: true flag.

Basic Guest User Creation

// Create guest user account with auto-generated password
const createGuestUser = async (username, email) => {
  const response = await fetch('/api/v1/users', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      user: {
        first_name: 'John',
        last_name: 'Contractor',
        username: username,
        email: email,
        // password is OPTIONAL for guest users - auto-generated if not provided
        is_guest: true,
        custom_fields: {
          invited_by: 'Your Name',
          purpose: 'Project collaboration'
        }
      },
      guest_user_security_roles: 'basic_user,project_viewer'  // Comma-separated role IIDs
    })
  });

  const data = await response.json();
  // Returns: { success: true, user: { id: 456, username, party_id: 789, is_guest: true, has_temp_password: true, ... }}
  return data.user;
};

Advanced: Custom Password & Email Template

// Create guest user with custom password and email template
const createGuestUserCustom = async (username, email, customPassword) => {
  const customTemplate = `
    <h2>Welcome to Our Platform, {{firstName}}!</h2>
    <p>You've been invited to collaborate on a project.</p>

    <h3>Login Information:</h3>
    <ul>
      <li>Email: {{email}}</li>
      <li>Temporary Password: {{temp_password}}</li>
      <li>Login URL: {{login_link}}</li>
    </ul>

    <p>Please change your password after first login.</p>
  `;

  const response = await fetch('/api/v1/users', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      user: {
        first_name: 'John',
        last_name: 'Contractor',
        username: username,
        email: email,
        password: customPassword,  // Optional: provide custom password
        is_guest: true
      },
      guest_user_security_roles: 'basic_user,project_viewer',
      guest_invite_email_template: customTemplate,
      guest_invite_email_subject: 'Welcome to Our Project!'
    })
  });

  const data = await response.json();
  return data.user;
};
What Happens Automatically:
  • Password Generation: If password is omitted, a secure 16-character password is automatically generated
  • Security Role Assignment: Roles specified in guest_user_security_roles are assigned immediately
  • Email Sent: Guest user receives an invitation email with credentials and login URL automatically
  • Password Change Flag: The has_temp_password flag is set, requiring password change on first login

That's it! No additional steps needed for basic guest user access. The user will receive the email and can log in immediately.

Note: Guest users are created directly in your tenant, not as separate tenants. They have full user accounts but are marked with is_guest: true and has_temp_password: true. The security roles you assign determine their level of access to your system.

The guest user receives an email with their credentials and follows this login workflow:

What the Guest User Experiences:

  1. Receives Email: Guest gets an email with their username/email, temporary password, and login URL
  2. First Login: Guest logs in with the temporary credentials
  3. Password Change Prompt: The login response includes requires_password_change: true
  4. Updates Password: Guest must change password before accessing the system

Login Response for Guest Users

// Guest user login
const response = await fetch('/api/v1/users/login', {
  method: 'POST',
  headers: {
    'Tenant-Id': currentTenantId,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    email: 'john@example.com',
    password: 'temporary_password_from_email'
  })
});

const data = await response.json();
// Response: {
//   success: true,
//   token: 'jwt_token_here',
//   user: { id: 456, email: 'john@example.com', is_guest: true, ... },
//   requires_password_change: true  // Present for guest users with temp passwords
// }

// If requires_password_change is true, show password change form
if (data.requires_password_change) {
  showPasswordChangeDialog();
}

Password Change Request

// Update password after first login
const changePassword = async (newPassword) => {
  const response = await fetch('/api/v1/users/current/update_password', {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      password: newPassword
    })
  });

  const data = await response.json();
  // Response: { success: true }
  // The has_temp_password flag is automatically cleared
};
Automatic Cleanup: When the guest user changes their password, the has_temp_password flag is automatically cleared. Future logins will not require a password change.

Note: This step is optional. If the security roles assigned in Step 1 provide sufficient access, you don't need scoped capabilities. Use this approach when you need to restrict guest users to specific records (e.g., only one project or specific documents).

1. Create Scoped Capabilities

// Create project-scoped capability for guest user
const createProjectCapability = async (projectId) => {
  const response = await fetch('/api/v1/capabilities', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      capability: {
        action: 'view',
        resource: 'Project',
        accessor_record_specific: true,  // Auto-delete when assignment removed
        description: 'Guest access to specific project',
        scope: {
          where: { id: projectId },
          fields: ['id', 'name', 'description', 'status', 'created_at']
        }
      }
    })
  });

  const data = await response.json();
  return data.capability;
};

// Create task-scoped capability
const createTaskCapability = async (projectId) => {
  const response = await fetch('/api/v1/capabilities', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      capability: {
        action: 'view',
        resource: 'Task',
        accessor_record_specific: true,
        description: 'Guest access to project tasks',
        scope: {
          where: { project_id: projectId }
        }
      }
    })
  });

  const data = await response.json();
  return data.capability;
};

2. Assign Capabilities to Guest User

// Assign capability to guest user
const assignCapabilityToGuest = async (capabilityId, guestUserId) => {
  const response = await fetch('/api/v1/capability_assignments', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      capability_assignment: {
        capability_id: capabilityId,
        accessor_record_type: 'User',
        accessor_record_id: guestUserId
      }
    })
  });

  const data = await response.json();
  return data.capability_assignment;
};

3. Complete Scoped Guest User Setup

// Complete workflow with scoped capabilities
const setupGuestUserWithScoping = async (projectId) => {
  // 1. Create guest user (automatically assigns roles and sends email)
  const response = await fetch('/api/v1/users', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      user: {
        first_name: 'John',
        last_name: 'Contractor',
        username: 'contractor.john',
        email: 'john@example.com',
        is_guest: true
      },
      guest_user_security_roles: 'basic_user'  // Basic role first
    })
  });

  const guestData = await response.json();
  const guest = guestData.user;

  // 2. Create scoped capabilities for specific project access
  const projectCap = await createProjectCapability(projectId);
  const taskCap = await createTaskCapability(projectId);

  // 3. Assign scoped capabilities
  await assignCapabilityToGuest(projectCap.id, guest.id);
  await assignCapabilityToGuest(taskCap.id, guest.id);

  // Guest now has:
  // - Basic role permissions (from security role)
  // - Plus scoped access to specific project and its tasks (from capabilities)

  return guest;
};
accessor_record_specific: Set to true to automatically delete the capability when all assignments are removed. Perfect for temporary collaborations. Best Practice: Combine security roles (for general permissions) with scoped capabilities (for record-specific access). The guest user receives their email automatically in Step 1, and these additional capabilities further refine their access.

For scenarios with multiple guest users (like client portals), use dynamic scoping with current_user_id to avoid creating per-user capabilities.

// Tag entities with authorized user IDs
const tagProjectForClients = async (projectId, clientUserIds) => {
  const response = await fetch(`/api/v1/projects/${projectId}`, {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      project: {
        custom_fields: {
          client_user_ids: clientUserIds  // Array of user IDs
        }
      }
    })
  });

  return response.json();
};

// Create capability with dynamic filtering
const createDynamicClientCapability = async () => {
  const response = await fetch('/api/v1/capabilities', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      capability: {
        action: 'view',
        resource: 'Project',
        description: 'View projects assigned to current user',
        scope: {
          where: {
            'custom_fields': {
              'client_user_ids': {
                'in': ['current_user_id']  // Dynamic resolution
              }
            }
          }
        }
      }
    })
  });

  return response.json();
};

// Create security role for all clients
const setupClientPortal = async () => {
  // 1. Create role
  const roleResponse = await fetch('/api/v1/security_roles', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      security_role: {
        name: 'Client Portal Access',
        description: 'Guest client access to their projects'
      }
    })
  });
  const role = (await roleResponse.json()).security_role;

  // 2. Create dynamic capabilities
  const projectCap = await createDynamicClientCapability();

  // 3. Assign capability to role
  await fetch('/api/v1/capability_assignments', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      capability_assignment: {
        capability_id: projectCap.capability.id,
        accessor_record_type: 'SecurityRole',
        accessor_record_id: role.id
      }
    })
  });

  return role;
};

// Assign role to each client
const assignClientToRole = async (roleId, clientUserId) => {
  await fetch('/api/v1/security_role_assignments', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      security_role_assignment: {
        security_role_id: roleId,
        accessor_record_type: 'User',
        accessor_record_id: clientUserId
      }
    })
  });
};
Scalability: This pattern scales to hundreds of clients without creating individual capabilities. Just tag projects and assign the same role to new clients.

Guest users have two conversion paths: upgrading to a full user within the same tenant, or converting to their own tenant owner with automatic cross-tenant access.

Option 1: Convert to Full User

Upgrade a guest to a regular user within your tenant:

// Convert guest to full user in same tenant
const convertToFullUser = async (userId, sendNotification = false) => {
  const response = await fetch(`/api/v1/users/${userId}/convert_to_full_user`, {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      send_notification: sendNotification
    })
  });

  const data = await response.json();
  // Returns: { success: true, user: {...}, message: "Guest user successfully converted to full user" }
  return data;
};

Option 2: Convert to Tenant Owner

Create a new tenant for the guest user with automatic cross-tenant sharing:

// Convert guest to tenant owner with auto-created sharing relationship
const convertToTenant = async (userId, tenantOptions) => {
  const response = await fetch(`/api/v1/users/${userId}/convert_to_tenant`, {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      tenant_options: {
        name: tenantOptions.name,
        enterprise_identifier: tenantOptions.enterpriseId,
        shared_key: tenantOptions.sharedKey,           // Optional
        product_type_id: tenantOptions.productTypeId,   // Optional, defaults to 'free'
        pricing_plan_id: tenantOptions.pricingPlanId    // Optional, defaults to 'free'
      }
    })
  });

  const data = await response.json();
  // Returns:
  // {
  //   success: true,
  //   user: {...},
  //   tenant: {...},
  //   sharing_relationship: {...},  // Auto-created for cross-tenant access
  //   message: "Guest user successfully converted to tenant owner"
  // }
  return data;
};
Automatic Cross-Tenant Sharing: When converting to tenant owner, a sharing relationship is automatically created between the new tenant and your tenant. This allows the converted user to switch between both workspaces seamlessly. After Conversion:
  • Full User: User remains in your tenant with full access (no longer flagged as guest)
  • Tenant Owner: User gets their own tenant AND maintains access to your tenant via auto-created sharing relationship
Complete Example: See the Tenant Sharing Documentation for detailed scenarios including contractor onboarding (Doug + Rick) and client portal setup (Whit + Multiple Clients).

Cross-Tenant User Access System

mdi-link
Overview

The Cross-Tenant User Access system enables controlled user-level access between tenants. Users from one tenant can be granted specific roles and permissions in another tenant, enabling collaboration while maintaining security and data isolation.

Key Features

mdi-check-circle Request/Accept Flow: Formal relationship establishment between tenants mdi-check-circle User-Based Access: Grant specific users from other tenants access mdi-check-circle Role-Based Permissions: Control access through SecurityRoles and Capabilities mdi-check-circle Workspace Switching: Seamlessly switch between tenant workspaces mdi-check-circle Time-bound Access: Optional start/end dates for relationships
Core Concepts

mdi-handshake Tenant Relationships

Formal relationships between tenants with statuses: pending (awaiting acceptance), active (functional), suspended (temporary pause - maintains roles), revoked (permanent - removes all roles).

mdi-information Suspend for temporary pauses, revoke for permanent termination.

mdi-account-multiple User Access Control

Individual users are granted SecurityRoles in the target tenant. Standard RBAC determines what they can view, edit, or delete based on capabilities.

mdi-swap-horizontal Workspaces

Guest users can switch between their own tenant workspace and host workspaces where they've been granted access.

mdi-information Host users only see their own workspace - they provide access, not receive it.

Workflow: Request → Accept → Grant Roles → Access

Step 1: Tenant A requests access for specific users
Step 2: Tenant B accepts the relationship request
Step 3: Tenant B grants SecurityRoles to users from Tenant A
Step 4: Users switch workspaces and access Tenant B's data (within their role permissions)

API Examples Relationships Granting Access Workspaces

Request access for users to another tenant.

// Request access for specific users
const requestAccess = async (targetTenantId, userIds, message) => {
  const response = await fetch('/api/v1/tenant_sharing/request', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      target_tenant_id: targetTenantId,
      description: 'Project collaboration',
      request_message: message,
      user_ids: userIds  // [123, 456] or omit to share only current user
      // OR use: share_with_all_users: true
    })
  });

  const data = await response.json();
  return data; // Returns relationship with status "pending"
};

Accept an incoming relationship request.

// Accept a relationship request
const acceptRequest = async (relationshipId, message) => {
  const response = await fetch(`/api/v1/tenant_sharing/${relationshipId}/accept`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      acceptance_message: message
    })
  });

  const data = await response.json();
  return data; // Returns relationship with status "active"
};

List all tenant relationships for your tenant.

// List all relationships
const listRelationships = async (status = null) => {
  let url = '/api/v1/tenant_sharing';
  if (status) {
    url += `?status=${status}`; // e.g., "party_relationship_active"
  }

  const response = await fetch(url, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId
    }
  });

  const data = await response.json();
  return data; // Array of relationships
};

Add more users to an existing relationship (requesting tenant only).

// Add users to relationship
const addUsers = async (relationshipId, userIds) => {
  const response = await fetch(`/api/v1/tenant_sharing/${relationshipId}/add_users`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      user_ids: userIds  // [125, 126]
    })
  });

  const data = await response.json();
  return data; // Updated relationship
};

Permanently revoke a tenant relationship and remove all role assignments.

// Revoke a relationship (permanent - requires new invitation to re-establish)
const revokeRelationship = async (relationshipId, reason) => {
  const response = await fetch(`/api/v1/tenant_sharing/${relationshipId}/revoke`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      revocation_reason: reason
    })
  });

  const data = await response.json();
  return data; // Removes all SecurityRoleAssignments permanently
};
Permanent Action: Revoke removes all role assignments. To re-establish access, you must send a new invitation. Use suspend for temporary pauses instead.

Temporarily suspend a relationship without removing role assignments.

// Suspend a relationship (temporary - can be reactivated)
const suspendRelationship = async (relationshipId, reason) => {
  const response = await fetch(`/api/v1/tenant_sharing/${relationshipId}/suspend`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      suspension_reason: reason || 'Temporarily suspended'
    })
  });

  const data = await response.json();
  return data; // Maintains SecurityRoleAssignments for easy reactivation
};
Temporary Pause: Suspend maintains all role assignments. Use reactivate to resume access instantly. Either host or guest tenant can suspend/reactivate.

Reactivate a previously suspended relationship.

// Reactivate a suspended relationship
const reactivateRelationship = async (relationshipId) => {
  const response = await fetch(`/api/v1/tenant_sharing/${relationshipId}/reactivate`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({})  // No body required
  });

  const data = await response.json();
  return data; // Restores access with all previously assigned roles
};
Instant Restoration: Reactivate immediately restores access with all previously assigned roles. No need to reassign roles.

After accepting a relationship, the target tenant must grant SecurityRoles to users.

Get list of users who should be granted access (target tenant only).

// List shareable users
const listShareableUsers = async (relationshipId) => {
  const response = await fetch(`/api/v1/tenant_sharing/${relationshipId}/shareable_users`, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId  // Must be target tenant
    }
  });

  const data = await response.json();
  // Returns:
  // {
  //   shareable_users: [
  //     {
  //       id: 123,
  //       username: "john_doe",
  //       display_name: "John Doe",
  //       assigned_roles: [ ... ],
  //       has_access: true/false
  //     }
  //   ],
  //   share_with_all_users: false
  // }
  return data;
};

Create a SecurityRole for external users.

// Create a role for partners
const createPartnerRole = async () => {
  const response = await fetch('/api/v1/security_roles', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      security_role: {
        name: 'Partner Viewer',
        description: 'Read-only access for partners'
      }
    })
  });

  const data = await response.json();
  return data.security_role; // Returns role with ID
};

Assign capabilities to a role.

// Assign capabilities to role
const assignCapabilities = async (roleId, capabilityIds) => {
  for (const capId of capabilityIds) {
    await fetch(`/api/v1/security_roles/${roleId}/assign_capability`, {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + token,
        'Tenant-Id': currentTenantId,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        capability_id: capId
      })
    });
  }
};

Assign a role to a user from another tenant.

// Assign role to external user
const grantRoleToUser = async (roleId, userId) => {
  const response = await fetch('/api/v1/security_role_assignments', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      security_role_assignment: {
        security_role_id: roleId,
        accessor_record_type: 'User',
        accessor_record_id: userId  // User ID from requesting tenant
      }
    })
  });

  const data = await response.json();
  return data.security_role_assignment;
};
Important: Workspaces are for guest users with granted roles only. If you're a host tenant user (inviting others), you will only see your own workspace. If you're a guest user (who was shared), you'll see your own workspace plus host workspaces only after the host has assigned you SecurityRoles. Being in the shared users list is not enough.

Workspaces allow guest users to seamlessly switch between their own tenant's data and host tenants where they have been granted access.

Get all workspaces you can access.

// List all available workspaces
const listWorkspaces = async () => {
  const response = await fetch('/api/v1/workspaces', {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId
    }
  });

  const data = await response.json();

  // HOST TENANT USER - Only sees own workspace:
  // {
  //   workspaces: [
  //     {
  //       workspace_tenant_id: "my-org",
  //       workspace_name: "My Organization",
  //       relationship_id: null,
  //       assigned_roles_count: null,
  //       has_access: true
  //     }
  //   ]
  // }

  // GUEST USER WITH ROLES - Sees own + host workspaces where roles assigned:
  // {
  //   workspaces: [
  //     {
  //       workspace_tenant_id: "my-org",
  //       workspace_name: "My Organization",
  //       relationship_id: null,
  //       assigned_roles_count: null,
  //       has_access: true
  //     },
  //     {
  //       workspace_tenant_id: "partner-org",
  //       workspace_name: "Partner Organization",
  //       relationship_id: 789,
  //       assigned_roles_count: 2,
  //       has_access: true,
  //       role: "guest"
  //     }
  //   ]
  // }

  // GUEST USER WITHOUT ROLES - Only sees own workspace:
  // (Even if they're in shared_users metadata, without role assignments they don't see host workspace)
  // {
  //   workspaces: [
  //     {
  //       workspace_tenant_id: "my-org",
  //       workspace_name: "My Organization",
  //       relationship_id: null,
  //       assigned_roles_count: null,
  //       has_access: true
  //     }
  //   ]
  // }

  return data.workspaces;
};

View your roles and capabilities in a specific workspace.

// Check what access I have
const checkMyAccess = async (workspaceTenantId) => {
  const response = await fetch(`/api/v1/workspaces/${workspaceTenantId}/my_access`, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': currentTenantId
    }
  });

  const data = await response.json();
  // Returns:
  // {
  //   roles: [
  //     {
  //       role: { id, name, description },
  //       capabilities: [ ... ]
  //     }
  //   ]
  // }
  return data.roles;
};

Access workspace data by setting the Tenant-Id header.

// Access data in another workspace
const getPartnerTasks = async (partnerTenantId) => {
  const response = await fetch('/api/v1/tasks', {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Tenant-Id': partnerTenantId  // Use partner's tenant ID
    }
  });

  const data = await response.json();
  // Returns tasks from partner tenant (filtered by your capabilities)
  return data.tasks;
};

// Important: API enforces your role permissions in that workspace
// You only see/edit what your assigned roles allow
Best Practice: Always check your access in a workspace before attempting operations. Use the my_access endpoint to understand your permissions.
Security Considerations mdi-shield-alert Relationship Required: Users can only access other tenants through accepted relationships mdi-shield-alert Role-Based Access: All access controlled through SecurityRoles and Capabilities mdi-shield-alert User-Level Granularity: Individual users are granted specific roles mdi-shield-alert Audit Trail: All relationship and role assignment operations are logged mdi-shield-alert Revocation: Revoking a relationship removes all SecurityRoleAssignments

Dynamic Functions

mdi-link
Serverless JavaScript Functions

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.

mdi-shield-lock Sandboxed Execution JavaScript runs in a secure V8 sandbox with memory and CPU limits. Functions are tenant-isolated with no filesystem access. mdi-key OAuth Integration Configuration-based OAuth 2.0 support for any provider. Automatic token refresh keeps your integrations running. mdi-clock-outline Scheduled Execution Use cron expressions to schedule functions to run automatically. Perfect for data syncs, reports, and automated workflows. mdi-webhook Model Callbacks Trigger functions automatically when records are created, updated, or deleted. Build event-driven automation workflows. mdi-database Data Access Full access to tenant data via executeAction. Query, create, update, and delete records from your functions. mdi-robot MCP Integration AI agents can manage and execute functions via MCP tools. Empower your AI to automate complex workflows.
Creating Your First Function

Create a dynamic function using the REST API. Functions receive a context object with parameters, configuration, OAuth tokens, and tenant information.

Tip: Function names must be 1-128 characters using alphanumeric characters, underscores, or hyphens.
// 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
}
JavaScript Execution Context

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
});
Scheduling Functions

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 hour0 * * * * Daily at 9am0 9 * * * Every Monday at 8am0 8 * * 1 First of month at midnight0 0 1 * * Every 15 minutes*/15 * * * * Required: Scheduled functions must specify 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
  }
}
Model Lifecycle Callbacks

Functions can be triggered automatically when records are created, updated, or destroyed. This enables event-driven automation without polling.

Supported Models

Individual Organization Party Task Project TimeEntry BizTxnEvent BizTxnAccount

Callback Events

create update destroy all
Required: Callback functions must specify 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 };
    `
  }
}
OAuth Integration

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 Configuration

{
  "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 Flow

1. Configure - Set OAuth config on the function 2. Authorize - Call /oauth/authorize to get authorization URL 3. Redirect - User authorizes access at the provider 4. Callback - Provider redirects with authorization code 5. Token Exchange - System exchanges code for tokens 6. Usage - Access tokens via oauth.accessToken Auto-refresh: Tokens are automatically refreshed before execution when they are expired or expiring within 5 minutes.
REST API Reference 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 Tip: Functions can be referenced by ID (numeric) or name (string) in URLs. For example: /api/v1/dynamic_functions/my_function/execute MCP Tools for AI Agents

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.

list_dynamic_functions_tool List functions with filtering by active status, schedule, callbacks, and name. get_dynamic_function_tool Get full function details including JavaScript code and execution history. execute_dynamic_function_tool Execute a function by ID or name with parameters (sync or async). manage_dynamic_function_tool Create, update, or delete functions. Supports scheduling and callbacks. Use run_as_user_id: "current_user" for scheduled/callback functions. dynamic_function_executions_tool View execution history with filtering by function, trigger type, and status.
Example: Xero Integration Function

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`
};

Sample Applications

mdi-link
Available Sample Apps

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.name }}

{{ app.description }}

{{ feature }}
Open App
App Architecture

Each sample application follows a similar architecture pattern:

Static HTML/CSS/JavaScript Apps are built with HTML, CSS, and JavaScript without a server-side component. Vue.js + Vuetify Front-end built with Vue.js and styled with Vuetify components. RESTful API Integration Apps communicate with the DSiloed backend using RESTful endpoints. JWT Authentication Authentication managed through JWT tokens stored in localStorage. Responsive Design Applications are designed to work on desktop and mobile devices.

Building Your Own App

mdi-link
Getting Started with App Development

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.

Vue.js + Vuetify React + Material UI

Step 1: Create a directory structure for your Vue app

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

mdi-information Note: When deploying your app, make sure to place it in a location accessible to your web server. If you're using this app with DSiloed, you might place it in a directory like /apps/myapp/.

Step 2: Download Essential Components

Next, download these essential components and place them in your application directory structure:

auth.js Authentication utilities Core authentication utility for handling JWT tokens, login state, and session management.

Place in: myapp/js/auth.js
Download
LoginDialog.js Login UI component Ready-to-use login dialog component for handling user authentication and tenant selection.

Place in: myapp/js/components/LoginDialog.js
Download
Documentation API & development guides Comprehensive documentation for building applications with DSiloed, organized into focused topics.

Download and extract docs.zip to: myapp/docs/
CLAUDE.md Download Docs
ChatAssistant.js AI chat component Reusable chat assistant component for adding AI-powered chat to any application.

Place in: myapp/js/components/ChatAssistant.js
Download

Step 3: Set up basic HTML structure

<!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=1764792677">

    <!-- Auth helper -->
    <script src="js/auth.js?v=1764792677"></script>
    <script src="js/components/LoginDialog.js?v=1764792677"></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=1764792677" 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>

Step 4: Initialize Vue app with authentication

// 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');
});

Step 1: Create a new React 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

mdi-information Note: You can also use other UI libraries like Chakra UI, Ant Design, or Tailwind CSS if preferred.

Step 2: Set up Authentication Utilities

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 };
  }
}

Step 3: Create a Login Dialog Component

// 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 (
    
      Login to {authManager.appName}
      
{error && {error}} setEmail(e.target.value)} required /> setPassword(e.target.value)} required /> setTenantId(e.target.value)} required />
); } export default LoginDialog;

Step 4: Create Main App Component

// 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;

Step 5: Make API Requests

// 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 => (
        
          
        
      ))}
    
  );
}
Making API Requests Vue.js React

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...
}
Adding AI Chat to Your Application

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.

ChatAssistant Features
  • Framework independent - works with any JavaScript application
  • Responsive design with quarter-screen flyout that expands to fullscreen
  • Modern UI with dark mode support
  • Real-time chat with AI assistants
  • Model selection when multiple models are available
  • Automatic conversation management

Basic Usage

// Include the ChatAssistant component
<script src="js/components/ChatAssistant.js?v=1764792677"></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();

Vue.js Integration Example

// 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();
}

React Integration Example

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>
    );
}

Configuration Options

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.

LLM-Powered App Development

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:

LLM Prompt Template

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.

Copy Prompt Download Docs.zip

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.

Next Steps

mdi-link
Continue Your Journey

Now that you've explored the DSiloed platform, here are some next steps to continue your journey:

Create Your Tenant

Set up your tenant environment to begin building applications.
Sign Up

Explore Sample Apps

Review the sample applications to understand the platform's capabilities.
Open Dashboard

Read API Documentation

Understand the API endpoints available for your application.
API Docs

Build Your First App

Create a simple application using the DSiloed platform.
Read Guide

Launch Your Application

Deploy your application and share it with users.
Get Help

Need help with the DSiloed platform? Here are some resources to assist you:

mdi-book-open-variant Documentation

Access comprehensive documentation for the DSiloed platform.

Open Documentation
mdi-home Intro mdi-rocket-launch Start mdi-api API mdi-apps Apps mdi-code-tags Build {{ snackbar.text }}