Data Directory
Construct stores user data, configuration, and application state in a platform-specific data directory. This guide explains the directory structure, conventions, and how to customize the location.
Platform-Specific Locations
The default data directory varies by platform:
macOS (Production)
~/Library/Application Support/Construct/macOS (Development)
~/Library/Application Support/Construct Dev/The development version uses a separate directory to avoid conflicts with production data.
Windows
%APPDATA%\Construct\Typically expands to:
C:\Users\{username}\AppData\Roaming\Construct\Linux
$XDG_DATA_HOME/construct/Or if XDG_DATA_HOME is not set:
~/.local/share/construct/Override with Environment Variable
To use a custom data directory, set the CONSTRUCT_DATA_DIR environment variable:
export CONSTRUCT_DATA_DIR=~/custom-construct-data
bun run devOr on Windows:
set CONSTRUCT_DATA_DIR=C:\custom-construct-data
bun run devThis overrides the platform default for all instances of Construct.
Directory Structure
The data directory is organized as follows:
{DATA_DIR}/
├── config/ # Application configuration
│ ├── auth.json # OAuth tokens and session info
│ ├── settings.json # User preferences and settings
│ ├── window-state.json # Window size, position, maximized state
│ └── providers.json # LLM provider API keys and config
│
├── state/ # Application state
│ ├── pinned.json # Pinned items (projects, spaces, favorites)
│ ├── recent.json # Recent projects and items
│ ├── theme.json # Theme preferences (dark/light)
│ └── sidebar.json # Sidebar state (expanded/collapsed)
│
├── sessions/ # Agent session data
│ ├── {sessionId}/
│ │ ├── metadata.json # Session timestamp, space, project
│ │ ├── messages.json # All messages in session
│ │ └── tools.json # Tool calls and results
│ └── ...
│
├── chat-sessions/ # Chat history
│ ├── {chatId}/
│ │ ├── config.json # Chat metadata
│ │ ├── history.json # Conversation history
│ │ └── attachments/ # Uploaded files
│ └── ...
│
├── spaces/ # User-installed spaces
│ ├── {space-id}/ # Each space is a directory
│ │ ├── space.json # Space manifest
│ │ ├── pages/
│ │ ├── components/
│ │ ├── agent/
│ │ └── ...
│ └── ...
│
├── projects/ # Project configuration
│ ├── {projectId}/
│ │ ├── config.json # Project metadata
│ │ ├── .construct/ # Project-specific data
│ │ │ ├── agents/ # Project agents config
│ │ │ ├── tools/ # Project tools
│ │ │ └── state.json # Project state
│ │ └── ...
│ └── ...
│
├── logs/ # Application logs
│ ├── operator.log # Operator (Go) process logs
│ ├── frontend.log # Frontend (Vue) logs
│ ├── tauri.log # Tauri (shell) logs
│ └── {date}.log # Dated log files
│
├── telemetry.db # SQLite database for telemetry
│
└── cache/ # Cached data
├── http-cache/ # HTTP response cache
├── file-cache/ # File metadata cache
└── ...Directory Details
config/ Directory
auth.json — OAuth tokens and session information
{
"accessToken": "sk-...",
"refreshToken": "sk-...",
"expiresAt": "2024-12-31T23:59:59Z",
"userId": "user-123",
"provider": "anthropic"
}settings.json — User preferences
{
"theme": "dark",
"fontSize": 14,
"fontFamily": "Monaco",
"autoSave": true,
"autoSaveInterval": 10000,
"notifications": {
"enabled": true,
"sound": false,
"desktop": true
},
"editor": {
"tabSize": 2,
"useTabs": false,
"lineWrapping": true,
"minimap": true
},
"ai": {
"provider": "anthropic",
"model": "claude-3-5-sonnet-20241022",
"temperature": 0.7
}
}window-state.json — Desktop window configuration
{
"width": 1400,
"height": 900,
"x": 100,
"y": 50,
"maximized": false,
"fullscreen": false
}providers.json — LLM provider configuration
{
"anthropic": {
"apiKey": "${ANTHROPIC_API_KEY}",
"baseUrl": "https://api.anthropic.com"
},
"openai": {
"apiKey": "${OPENAI_API_KEY}",
"baseUrl": "https://api.openai.com/v1"
},
"ollama": {
"baseUrl": "http://localhost:11434"
}
}state/ Directory
Lightweight application state files for quick access:
pinned.json — Pinned projects and favorites
{
"projects": ["proj-123", "proj-456"],
"spaces": ["code", "chat"],
"folders": ["/Users/user/work", "/Users/user/projects"]
}recent.json — Recently accessed items
{
"projects": [
{
"id": "proj-123",
"name": "My App",
"path": "/Users/user/projects/my-app",
"accessedAt": "2024-03-15T14:30:00Z"
}
],
"files": [
{
"path": "/Users/user/projects/my-app/src/index.ts",
"projectId": "proj-123",
"accessedAt": "2024-03-15T14:25:00Z"
}
]
}sessions/ Directory
Agent session history, one directory per session:
metadata.json
{
"id": "session-abc123",
"spaceId": "code",
"projectId": "proj-123",
"createdAt": "2024-03-15T14:00:00Z",
"updatedAt": "2024-03-15T14:30:00Z",
"messageCount": 42,
"iterationCount": 15
}messages.json — All messages in the session
[
{
"id": "msg-1",
"role": "user",
"content": "Fix this function",
"timestamp": "2024-03-15T14:00:00Z"
},
{
"id": "msg-2",
"role": "assistant",
"content": "I'll analyze the function...",
"timestamp": "2024-03-15T14:00:05Z",
"toolCalls": ["msg-2-tool-1"]
}
]tools.json — Tool execution records
[
{
"id": "msg-2-tool-1",
"name": "read",
"input": { "path": "/src/utils.ts" },
"output": "function content...",
"executionTime": 125,
"status": "success"
}
]chat-sessions/ Directory
Chat history separate from agent sessions:
config.json
{
"id": "chat-xyz",
"name": "Project Planning",
"createdAt": "2024-03-10T09:00:00Z",
"archived": false
}history.json — Conversation turns
[
{
"turn": 1,
"user": "What files changed?",
"assistant": "Let me check...",
"timestamp": "2024-03-15T14:00:00Z"
}
]spaces/ Directory
User-installed custom spaces (marketplace or private installs).
Each space directory mirrors the space directory structure:
spaces/
├── my-productivity-space/
│ ├── space.json
│ ├── pages/
│ ├── components/
│ ├── agent/
│ └── ...
└── custom-integration/
├── space.json
└── ...projects/ Directory
Project-specific configuration and state:
config.json — Project metadata
{
"id": "proj-123",
"name": "My Application",
"path": "/Users/user/projects/my-app",
"createdAt": "2024-01-01T00:00:00Z",
"description": "A web application",
"type": "web",
"tags": ["production", "active"]
}state.json — Project-specific application state
{
"lastOpenFile": "/src/index.ts",
"expandedFolders": ["/src", "/src/components"],
"pinnedFiles": ["/README.md", "/package.json"],
"customSettings": {}
}logs/ Directory
Application logs at various levels:
operator.log — Go operator process logs
2024-03-15 14:30:00 INFO Starting operator on :60100
2024-03-15 14:30:01 DEBUG Loaded 10 agents
2024-03-15 14:30:02 INFO Ready for connectionsfrontend.log — Vue/TypeScript logs
2024-03-15 14:30:05 INFO Vue app initialized
2024-03-15 14:30:06 DEBUG Connecting to operator...
2024-03-15 14:30:07 INFO Connected to operatortauri.log — Tauri shell and native integration logs
2024-03-15 14:30:00 INFO Tauri app started
2024-03-15 14:30:01 INFO Window created
2024-03-15 14:30:02 DEBUG Spawning operator sidecarLogs are typically kept for 30 days and rotated by date.
telemetry.db
SQLite database storing:
- Feature usage (which spaces, tools, agents used)
- Error and crash reports (if telemetry enabled)
- Performance metrics
- Aggregated usage statistics
Privacy: Telemetry is local only and not sent to servers unless explicitly enabled.
Conventions and Best Practices
Reading Data
Always check for file existence before reading:
import { readFile } from 'fs/promises'
import path from 'path'
const dataDir = process.env.CONSTRUCT_DATA_DIR || DEFAULT_DATA_DIR
const settingsPath = path.join(dataDir, 'config', 'settings.json')
try {
const data = await readFile(settingsPath, 'utf-8')
return JSON.parse(data)
} catch (error) {
// File doesn't exist or is corrupted, return defaults
return getDefaultSettings()
}Writing Data
Always use atomic writes to prevent corruption:
import { writeFile } from 'fs/promises'
import path from 'path'
const dataDir = process.env.CONSTRUCT_DATA_DIR || DEFAULT_DATA_DIR
const settingsPath = path.join(dataDir, 'config', 'settings.json')
// Write to temp file first
const tempPath = settingsPath + '.tmp'
await writeFile(tempPath, JSON.stringify(settings, null, 2))
// Atomic rename
await rename(tempPath, settingsPath)Versioning Data
Include version in config files for migrations:
{
"version": "2.0.0",
"settings": { ... }
}Then handle migrations when reading:
const data = JSON.parse(...)
if (data.version === '1.0.0') {
data = migrateFromV1(data)
}Clearing Data
Users can reset Construct by removing the data directory:
rm -rf ~/Library/Application\ Support/Construct # macOS
rmdir /s %APPDATA%\Construct # Windows
rm -rf ~/.local/share/construct # LinuxOr set a custom data directory to have multiple independent instances.
Security Considerations
API Keys and Tokens
Never commit credentials to git. Store in:
config/auth.json(OAuth tokens)config/providers.json(API keys)- Environment variables (preferred for CI/CD)
File Permissions
The data directory should be readable/writable only by the current user:
# macOS/Linux
chmod 700 ~/Library/Application\ Support/Construct
chmod 600 ~/Library/Application\ Support/Construct/config/*Encryption
Currently, files are stored in plaintext. For production, consider:
- Encrypting sensitive files (auth, API keys)
- Using OS keychain for token storage
- At-rest encryption for archived sessions
Troubleshooting
"Cannot write to data directory"
# Check permissions
ls -la ~/Library/Application\ Support/Construct
# Fix ownership
sudo chown -R $(whoami) ~/Library/Application\ Support/Construct
# Make writable
chmod 700 ~/Library/Application\ Support/ConstructData directory grows too large
- Clear old sessions:
rm -rf {DATA_DIR}/sessions/{old_id} - Clear logs:
rm {DATA_DIR}/logs/*.log - Clear cache:
rm -rf {DATA_DIR}/cache - Archive chat history: Export and delete old chats
Corrupted settings.json
- Rename the file:
mv settings.json settings.json.bak - Restart Construct (creates defaults)
- Manually restore custom settings if needed
Next Steps
- Learn about Spaces and how they store data
- See Agents and Tools for session format details
- Read Operator documentation for session persistence details