@hailer/mcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/tool-builder.md +37 -0
- package/.claude/commands/ws-pull.md +44 -0
- package/.claude/settings.json +8 -0
- package/.claude/settings.local.json +49 -0
- package/.claude/skills/activity-api/SKILL.md +96 -0
- package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
- package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
- package/.claude/skills/agent-building/SKILL.md +243 -0
- package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
- package/.claude/skills/agent-building/references/code-examples.md +587 -0
- package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
- package/.claude/skills/app-api/SKILL.md +219 -0
- package/.claude/skills/app-api/references/app-endpoints.md +759 -0
- package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
- package/.claude/skills/create-app-skill/SKILL.md +1101 -0
- package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
- package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
- package/.claude/skills/hailer-api/SKILL.md +283 -0
- package/.claude/skills/hailer-api/references/activities.md +620 -0
- package/.claude/skills/hailer-api/references/authentication.md +216 -0
- package/.claude/skills/hailer-api/references/datasets.md +437 -0
- package/.claude/skills/hailer-api/references/files.md +301 -0
- package/.claude/skills/hailer-api/references/insights.md +469 -0
- package/.claude/skills/hailer-api/references/workflows.md +720 -0
- package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
- package/.claude/skills/insight-api/SKILL.md +185 -0
- package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
- package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
- package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
- package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
- package/.claude/skills/local-first-skill/SKILL.md +570 -0
- package/.claude/skills/mcp-tools/SKILL.md +419 -0
- package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
- package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
- package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
- package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
- package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
- package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
- package/.claude/skills/remove-app-skill/SKILL.md +985 -0
- package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
- package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
- package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
- package/.claude/skills/skill-testing/README.md +137 -0
- package/.claude/skills/skill-testing/SKILL.md +348 -0
- package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
- package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
- package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
- package/.claude/skills/tool-builder/SKILL.md +328 -0
- package/.claude/skills/update-app-skill/SKILL.md +970 -0
- package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
- package/.env.example +81 -0
- package/.mcp.json +13 -0
- package/README.md +297 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.js +74 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +5 -0
- package/dist/client/adaptive-documentation-bot.d.ts +108 -0
- package/dist/client/adaptive-documentation-bot.js +475 -0
- package/dist/client/adaptive-documentation-types.d.ts +66 -0
- package/dist/client/adaptive-documentation-types.js +9 -0
- package/dist/client/agent-activity-bot.d.ts +51 -0
- package/dist/client/agent-activity-bot.js +166 -0
- package/dist/client/agent-tracker.d.ts +499 -0
- package/dist/client/agent-tracker.js +659 -0
- package/dist/client/description-updater.d.ts +56 -0
- package/dist/client/description-updater.js +259 -0
- package/dist/client/log-parser.d.ts +72 -0
- package/dist/client/log-parser.js +387 -0
- package/dist/client/mcp-client.d.ts +50 -0
- package/dist/client/mcp-client.js +532 -0
- package/dist/client/message-processor.d.ts +35 -0
- package/dist/client/message-processor.js +352 -0
- package/dist/client/multi-bot-manager.d.ts +24 -0
- package/dist/client/multi-bot-manager.js +74 -0
- package/dist/client/providers/anthropic-provider.d.ts +19 -0
- package/dist/client/providers/anthropic-provider.js +631 -0
- package/dist/client/providers/llm-provider.d.ts +47 -0
- package/dist/client/providers/llm-provider.js +367 -0
- package/dist/client/providers/openai-provider.d.ts +23 -0
- package/dist/client/providers/openai-provider.js +621 -0
- package/dist/client/simple-llm-caller.d.ts +19 -0
- package/dist/client/simple-llm-caller.js +100 -0
- package/dist/client/skill-generator.d.ts +81 -0
- package/dist/client/skill-generator.js +386 -0
- package/dist/client/test-adaptive-bot.d.ts +9 -0
- package/dist/client/test-adaptive-bot.js +82 -0
- package/dist/client/token-pricing.d.ts +38 -0
- package/dist/client/token-pricing.js +127 -0
- package/dist/client/token-tracker.d.ts +232 -0
- package/dist/client/token-tracker.js +457 -0
- package/dist/client/token-usage-bot.d.ts +53 -0
- package/dist/client/token-usage-bot.js +153 -0
- package/dist/client/tool-executor.d.ts +69 -0
- package/dist/client/tool-executor.js +159 -0
- package/dist/client/tool-schema-loader.d.ts +60 -0
- package/dist/client/tool-schema-loader.js +178 -0
- package/dist/client/types.d.ts +69 -0
- package/dist/client/types.js +7 -0
- package/dist/config.d.ts +162 -0
- package/dist/config.js +296 -0
- package/dist/core.d.ts +26 -0
- package/dist/core.js +147 -0
- package/dist/lib/context-manager.d.ts +111 -0
- package/dist/lib/context-manager.js +431 -0
- package/dist/lib/logger.d.ts +74 -0
- package/dist/lib/logger.js +277 -0
- package/dist/lib/materialize.d.ts +3 -0
- package/dist/lib/materialize.js +101 -0
- package/dist/lib/normalizedName.d.ts +7 -0
- package/dist/lib/normalizedName.js +48 -0
- package/dist/lib/prompt-length-manager.d.ts +81 -0
- package/dist/lib/prompt-length-manager.js +457 -0
- package/dist/lib/terminal-prompt.d.ts +9 -0
- package/dist/lib/terminal-prompt.js +108 -0
- package/dist/mcp/UserContextCache.d.ts +56 -0
- package/dist/mcp/UserContextCache.js +163 -0
- package/dist/mcp/auth.d.ts +2 -0
- package/dist/mcp/auth.js +29 -0
- package/dist/mcp/hailer-clients.d.ts +42 -0
- package/dist/mcp/hailer-clients.js +246 -0
- package/dist/mcp/signal-handler.d.ts +45 -0
- package/dist/mcp/signal-handler.js +317 -0
- package/dist/mcp/tool-registry.d.ts +100 -0
- package/dist/mcp/tool-registry.js +306 -0
- package/dist/mcp/tools/activity.d.ts +15 -0
- package/dist/mcp/tools/activity.js +955 -0
- package/dist/mcp/tools/app.d.ts +20 -0
- package/dist/mcp/tools/app.js +1488 -0
- package/dist/mcp/tools/discussion.d.ts +19 -0
- package/dist/mcp/tools/discussion.js +950 -0
- package/dist/mcp/tools/file.d.ts +15 -0
- package/dist/mcp/tools/file.js +119 -0
- package/dist/mcp/tools/insight.d.ts +17 -0
- package/dist/mcp/tools/insight.js +806 -0
- package/dist/mcp/tools/skill.d.ts +10 -0
- package/dist/mcp/tools/skill.js +279 -0
- package/dist/mcp/tools/user.d.ts +10 -0
- package/dist/mcp/tools/user.js +108 -0
- package/dist/mcp/tools/workflow-template.d.ts +19 -0
- package/dist/mcp/tools/workflow-template.js +822 -0
- package/dist/mcp/tools/workflow.d.ts +18 -0
- package/dist/mcp/tools/workflow.js +1362 -0
- package/dist/mcp/utils/api-errors.d.ts +45 -0
- package/dist/mcp/utils/api-errors.js +160 -0
- package/dist/mcp/utils/data-transformers.d.ts +102 -0
- package/dist/mcp/utils/data-transformers.js +194 -0
- package/dist/mcp/utils/file-upload.d.ts +33 -0
- package/dist/mcp/utils/file-upload.js +148 -0
- package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
- package/dist/mcp/utils/hailer-api-client.js +323 -0
- package/dist/mcp/utils/index.d.ts +13 -0
- package/dist/mcp/utils/index.js +39 -0
- package/dist/mcp/utils/logger.d.ts +42 -0
- package/dist/mcp/utils/logger.js +103 -0
- package/dist/mcp/utils/types.d.ts +286 -0
- package/dist/mcp/utils/types.js +7 -0
- package/dist/mcp/workspace-cache.d.ts +42 -0
- package/dist/mcp/workspace-cache.js +97 -0
- package/dist/mcp-server.d.ts +42 -0
- package/dist/mcp-server.js +280 -0
- package/package.json +56 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,1317 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Creating Hailer Insights
|
|
3
|
+
description: Complete guide for creating SQL-like insights over Hailer workflow data - use when building reports, analytics, or data queries
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Creating Hailer Insights - Complete Guide
|
|
7
|
+
|
|
8
|
+
Complete reference for creating SQL-like insights that query Hailer workflow data using the `create_insight` MCP tool.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Quick Reference](#quick-reference)
|
|
12
|
+
2. [Overview](#overview)
|
|
13
|
+
3. [Core Concepts](#core-concepts)
|
|
14
|
+
4. [Meta Fields Reference](#meta-fields-reference)
|
|
15
|
+
5. [Basic Examples](#basic-examples)
|
|
16
|
+
6. [SQL Features](#sql-features)
|
|
17
|
+
7. [Advanced Queries](#advanced-queries)
|
|
18
|
+
8. [Joins and Relationships](#joins-and-relationships)
|
|
19
|
+
9. [Aggregations and Grouping](#aggregations-and-grouping)
|
|
20
|
+
10. [Best Practices](#best-practices)
|
|
21
|
+
11. [Common Patterns](#common-patterns)
|
|
22
|
+
12. [Troubleshooting](#troubleshooting)
|
|
23
|
+
|
|
24
|
+
## Quick Reference
|
|
25
|
+
|
|
26
|
+
**Simple Report (Single Workflow):**
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
create_insight({
|
|
30
|
+
name: 'All Tasks Report',
|
|
31
|
+
sources: [{
|
|
32
|
+
name: 'tasks',
|
|
33
|
+
workflowId: 'workflow-id',
|
|
34
|
+
fields: [
|
|
35
|
+
{ name: 'title', meta: 'name' },
|
|
36
|
+
{ name: 'dueDate', fieldId: 'due-date-field-id' }
|
|
37
|
+
]
|
|
38
|
+
}],
|
|
39
|
+
query: 'SELECT title, dueDate FROM tasks WHERE dueDate > "2024-01-01"'
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Cross-Workflow Join:**
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
create_insight({
|
|
47
|
+
name: 'Tasks with Projects',
|
|
48
|
+
sources: [
|
|
49
|
+
{
|
|
50
|
+
name: 'tasks',
|
|
51
|
+
workflowId: 'tasks-workflow-id',
|
|
52
|
+
fields: [
|
|
53
|
+
{ name: 'taskName', meta: 'name' },
|
|
54
|
+
{ name: 'projectLink', fieldId: 'project-field-id' }
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'projects',
|
|
59
|
+
workflowId: 'projects-workflow-id',
|
|
60
|
+
fields: [
|
|
61
|
+
{ name: 'id', meta: '_id' },
|
|
62
|
+
{ name: 'projectName', meta: 'name' }
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
query: `
|
|
67
|
+
SELECT tasks.taskName, projects.projectName
|
|
68
|
+
FROM tasks
|
|
69
|
+
LEFT JOIN projects ON tasks.projectLink = projects.id
|
|
70
|
+
`
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Key Concepts:**
|
|
75
|
+
- Workflows = Database tables
|
|
76
|
+
- Activities = Rows
|
|
77
|
+
- Fields = Columns
|
|
78
|
+
- Insights = SELECT queries with JOINs
|
|
79
|
+
- Meta fields = Built-in activity properties
|
|
80
|
+
|
|
81
|
+
## Overview
|
|
82
|
+
|
|
83
|
+
**What are Insights?**
|
|
84
|
+
|
|
85
|
+
Insights are SQL queries that run over your Hailer workflow data. They enable powerful reporting and analytics capabilities without writing custom code.
|
|
86
|
+
|
|
87
|
+
**Think of it as:**
|
|
88
|
+
- SQL SELECT queries on workflow data
|
|
89
|
+
- Virtual database views over Hailer
|
|
90
|
+
- Reports that update in real-time
|
|
91
|
+
- Cross-workflow analytics
|
|
92
|
+
|
|
93
|
+
**Common Uses:**
|
|
94
|
+
- Generate reports (tasks by status, projects by team)
|
|
95
|
+
- Analyze trends (activities created per month)
|
|
96
|
+
- Track metrics (completion rates, time to close)
|
|
97
|
+
- Cross-workflow summaries (tasks per project)
|
|
98
|
+
- Data exports for external tools
|
|
99
|
+
|
|
100
|
+
**Key Features:**
|
|
101
|
+
- Full SQL syntax support
|
|
102
|
+
- Cross-workflow JOINs
|
|
103
|
+
- Aggregations (COUNT, SUM, AVG, MIN, MAX)
|
|
104
|
+
- Filtering with WHERE clauses
|
|
105
|
+
- Sorting with ORDER BY
|
|
106
|
+
- Public/private access control
|
|
107
|
+
|
|
108
|
+
## Core Concepts
|
|
109
|
+
|
|
110
|
+
### Sources
|
|
111
|
+
|
|
112
|
+
**Sources define which workflows to query:**
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
sources: [{
|
|
116
|
+
name: 'tasks', // SQL table alias
|
|
117
|
+
workflowId: 'wf-id', // Which workflow to query
|
|
118
|
+
fields: [ // Field mappings
|
|
119
|
+
{ name: 'title', meta: 'name' },
|
|
120
|
+
{ name: 'priority', fieldId: 'field-id' }
|
|
121
|
+
]
|
|
122
|
+
}]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Think of sources as:**
|
|
126
|
+
- Table definitions in SQL
|
|
127
|
+
- Each source = one workflow
|
|
128
|
+
- Fields = column mappings
|
|
129
|
+
- Name = table alias for queries
|
|
130
|
+
|
|
131
|
+
### Field Mappings
|
|
132
|
+
|
|
133
|
+
**Two types of field mappings:**
|
|
134
|
+
|
|
135
|
+
**1. Meta Fields (Built-in):**
|
|
136
|
+
```javascript
|
|
137
|
+
{ name: 'title', meta: 'name' } // Activity name
|
|
138
|
+
{ name: 'id', meta: '_id' } // Activity ID
|
|
139
|
+
{ name: 'created', meta: 'created' } // Creation date
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**2. Custom Fields:**
|
|
143
|
+
```javascript
|
|
144
|
+
{ name: 'priority', fieldId: 'field-id' } // Custom field
|
|
145
|
+
{ name: 'dueDate', fieldId: 'field-id' } // Custom field
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Workflow โ SQL Mapping
|
|
149
|
+
|
|
150
|
+
| Hailer Concept | SQL Concept | Example |
|
|
151
|
+
|----------------|-------------|---------|
|
|
152
|
+
| Workflow | Table | `tasks` table |
|
|
153
|
+
| Activity | Row | One task row |
|
|
154
|
+
| Field | Column | `priority` column |
|
|
155
|
+
| ActivityLink | Foreign Key | JOIN on `project_id` |
|
|
156
|
+
| Insight | SELECT Query | Report query |
|
|
157
|
+
|
|
158
|
+
## Meta Fields Reference
|
|
159
|
+
|
|
160
|
+
**Built-in activity properties available in all workflows:**
|
|
161
|
+
|
|
162
|
+
### Available Meta Fields
|
|
163
|
+
|
|
164
|
+
| Meta Field | Type | Description | Usage |
|
|
165
|
+
|------------|------|-------------|-------|
|
|
166
|
+
| `_id` | string | Activity ID | For JOINs |
|
|
167
|
+
| `uid` | string | User ID (creator) | User filtering |
|
|
168
|
+
| `team` | string | Owner team ID | Team filtering |
|
|
169
|
+
| `createdBy` | string | Creator user ID | Track who created |
|
|
170
|
+
| `name` | string | Activity name/title | Display name |
|
|
171
|
+
| `created` | timestamp | Creation date/time | Sorting, filtering |
|
|
172
|
+
| `updated` | timestamp | Last update date/time | Recent changes |
|
|
173
|
+
| `phaseId` | string | Current phase ID | Status/phase grouping |
|
|
174
|
+
| `phaseName` | string | Current phase name | Display phase name |
|
|
175
|
+
| `phaseLastMove` | timestamp | Last phase change | Track phase transitions |
|
|
176
|
+
| `workflowId` | string | Workflow ID | Identify source workflow |
|
|
177
|
+
| `workflowName` | string | Workflow name | Display workflow name |
|
|
178
|
+
| `priority` | number | Activity priority | Priority filtering |
|
|
179
|
+
|
|
180
|
+
### Meta Field Examples
|
|
181
|
+
|
|
182
|
+
**Activity Name:**
|
|
183
|
+
```javascript
|
|
184
|
+
{ name: 'title', meta: 'name' }
|
|
185
|
+
// Query: SELECT title FROM tasks
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Activity ID (for JOINs):**
|
|
189
|
+
```javascript
|
|
190
|
+
{ name: 'id', meta: '_id' }
|
|
191
|
+
// Query: SELECT id FROM tasks
|
|
192
|
+
// JOIN: ON tasks.projectId = projects.id
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Created Date:**
|
|
196
|
+
```javascript
|
|
197
|
+
{ name: 'createdDate', meta: 'created' }
|
|
198
|
+
// Query: SELECT createdDate FROM tasks WHERE createdDate > '2024-01-01'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Updated Date:**
|
|
202
|
+
```javascript
|
|
203
|
+
{ name: 'lastUpdated', meta: 'updated' }
|
|
204
|
+
// Query: SELECT lastUpdated FROM tasks ORDER BY lastUpdated DESC
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Phase ID (Status):**
|
|
208
|
+
```javascript
|
|
209
|
+
{ name: 'status', meta: 'phaseId' }
|
|
210
|
+
// Query: SELECT status FROM tasks GROUP BY status
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Phase Name (Readable Status):**
|
|
214
|
+
```javascript
|
|
215
|
+
{ name: 'statusName', meta: 'phaseName' }
|
|
216
|
+
// Query: SELECT statusName FROM tasks
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Team:**
|
|
220
|
+
```javascript
|
|
221
|
+
{ name: 'ownerTeam', meta: 'team' }
|
|
222
|
+
// Query: SELECT ownerTeam FROM tasks WHERE ownerTeam = 'team-id'
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Basic Examples
|
|
226
|
+
|
|
227
|
+
### Example 1: Simple List Query
|
|
228
|
+
|
|
229
|
+
**Goal:** List all tasks with due dates.
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
create_insight({
|
|
233
|
+
name: 'Tasks with Due Dates',
|
|
234
|
+
sources: [{
|
|
235
|
+
name: 'tasks',
|
|
236
|
+
workflowId: '68446dc05b30685f67c6fcd4',
|
|
237
|
+
fields: [
|
|
238
|
+
{ name: 'taskName', meta: 'name' },
|
|
239
|
+
{ name: 'dueDate', fieldId: 'due-date-field-id' },
|
|
240
|
+
{ name: 'priority', fieldId: 'priority-field-id' }
|
|
241
|
+
]
|
|
242
|
+
}],
|
|
243
|
+
query: 'SELECT taskName, dueDate, priority FROM tasks'
|
|
244
|
+
})
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Example 2: Filtered Query
|
|
248
|
+
|
|
249
|
+
**Goal:** Show only high-priority tasks due this month.
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
create_insight({
|
|
253
|
+
name: 'High Priority Tasks Due Soon',
|
|
254
|
+
sources: [{
|
|
255
|
+
name: 'tasks',
|
|
256
|
+
workflowId: 'tasks-workflow-id',
|
|
257
|
+
fields: [
|
|
258
|
+
{ name: 'title', meta: 'name' },
|
|
259
|
+
{ name: 'dueDate', fieldId: 'due-date-field-id' },
|
|
260
|
+
{ name: 'priority', fieldId: 'priority-field-id' }
|
|
261
|
+
]
|
|
262
|
+
}],
|
|
263
|
+
query: `
|
|
264
|
+
SELECT title, dueDate, priority
|
|
265
|
+
FROM tasks
|
|
266
|
+
WHERE priority = 'High'
|
|
267
|
+
AND dueDate >= '2024-12-01'
|
|
268
|
+
AND dueDate <= '2024-12-31'
|
|
269
|
+
`
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Example 3: Sorted Query
|
|
274
|
+
|
|
275
|
+
**Goal:** Recent tasks, newest first.
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
create_insight({
|
|
279
|
+
name: 'Recently Created Tasks',
|
|
280
|
+
sources: [{
|
|
281
|
+
name: 'tasks',
|
|
282
|
+
workflowId: 'tasks-workflow-id',
|
|
283
|
+
fields: [
|
|
284
|
+
{ name: 'title', meta: 'name' },
|
|
285
|
+
{ name: 'created', meta: 'created' }
|
|
286
|
+
]
|
|
287
|
+
}],
|
|
288
|
+
query: `
|
|
289
|
+
SELECT title, created
|
|
290
|
+
FROM tasks
|
|
291
|
+
ORDER BY created DESC
|
|
292
|
+
LIMIT 50
|
|
293
|
+
`
|
|
294
|
+
})
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Example 4: Public Insight
|
|
298
|
+
|
|
299
|
+
**Goal:** Shareable report accessible without authentication.
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
create_insight({
|
|
303
|
+
name: 'Project Status Dashboard',
|
|
304
|
+
public: true, // Publicly accessible
|
|
305
|
+
sources: [{
|
|
306
|
+
name: 'projects',
|
|
307
|
+
workflowId: 'projects-workflow-id',
|
|
308
|
+
fields: [
|
|
309
|
+
{ name: 'projectName', meta: 'name' },
|
|
310
|
+
{ name: 'status', fieldId: 'status-field-id' },
|
|
311
|
+
{ name: 'budget', fieldId: 'budget-field-id' }
|
|
312
|
+
]
|
|
313
|
+
}],
|
|
314
|
+
query: 'SELECT projectName, status, budget FROM projects'
|
|
315
|
+
})
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## SQL Features
|
|
319
|
+
|
|
320
|
+
### SELECT Statement
|
|
321
|
+
|
|
322
|
+
**Basic SELECT:**
|
|
323
|
+
```sql
|
|
324
|
+
SELECT title, priority FROM tasks
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**SELECT with aliases:**
|
|
328
|
+
```sql
|
|
329
|
+
SELECT
|
|
330
|
+
title AS "Task Name",
|
|
331
|
+
priority AS "Priority Level"
|
|
332
|
+
FROM tasks
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**SELECT all columns:**
|
|
336
|
+
```sql
|
|
337
|
+
SELECT * FROM tasks
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**SELECT distinct values:**
|
|
341
|
+
```sql
|
|
342
|
+
SELECT DISTINCT priority FROM tasks
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### WHERE Clause
|
|
346
|
+
|
|
347
|
+
**Comparison operators:**
|
|
348
|
+
```sql
|
|
349
|
+
WHERE priority = 'High' -- Equal
|
|
350
|
+
WHERE dueDate > '2024-01-01' -- Greater than
|
|
351
|
+
WHERE quantity < 100 -- Less than
|
|
352
|
+
WHERE status != 'Done' -- Not equal
|
|
353
|
+
WHERE price >= 50 -- Greater than or equal
|
|
354
|
+
WHERE count <= 10 -- Less than or equal
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Logical operators:**
|
|
358
|
+
```sql
|
|
359
|
+
WHERE priority = 'High' AND status = 'Open' -- AND
|
|
360
|
+
WHERE priority = 'High' OR priority = 'Urgent' -- OR
|
|
361
|
+
WHERE NOT status = 'Done' -- NOT
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Pattern matching:**
|
|
365
|
+
```sql
|
|
366
|
+
WHERE title LIKE '%report%' -- Contains
|
|
367
|
+
WHERE email LIKE 'admin@%' -- Starts with
|
|
368
|
+
WHERE name LIKE '%Smith' -- Ends with
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**NULL checks:**
|
|
372
|
+
```sql
|
|
373
|
+
WHERE dueDate IS NULL -- No due date
|
|
374
|
+
WHERE assignee IS NOT NULL -- Has assignee
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**IN operator:**
|
|
378
|
+
```sql
|
|
379
|
+
WHERE priority IN ('High', 'Urgent')
|
|
380
|
+
WHERE status IN ('Open', 'In Progress')
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**BETWEEN operator:**
|
|
384
|
+
```sql
|
|
385
|
+
WHERE dueDate BETWEEN '2024-01-01' AND '2024-12-31'
|
|
386
|
+
WHERE quantity BETWEEN 10 AND 100
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### ORDER BY Clause
|
|
390
|
+
|
|
391
|
+
**Sort ascending:**
|
|
392
|
+
```sql
|
|
393
|
+
ORDER BY dueDate ASC
|
|
394
|
+
ORDER BY priority
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Sort descending:**
|
|
398
|
+
```sql
|
|
399
|
+
ORDER BY created DESC
|
|
400
|
+
ORDER BY quantity DESC
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Multiple columns:**
|
|
404
|
+
```sql
|
|
405
|
+
ORDER BY priority DESC, dueDate ASC
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### LIMIT and OFFSET
|
|
409
|
+
|
|
410
|
+
**Limit results:**
|
|
411
|
+
```sql
|
|
412
|
+
SELECT * FROM tasks LIMIT 10
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Pagination:**
|
|
416
|
+
```sql
|
|
417
|
+
SELECT * FROM tasks LIMIT 10 OFFSET 20 -- Skip 20, take 10
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Advanced Queries
|
|
421
|
+
|
|
422
|
+
### Complex Filtering
|
|
423
|
+
|
|
424
|
+
**Multiple conditions:**
|
|
425
|
+
```javascript
|
|
426
|
+
create_insight({
|
|
427
|
+
name: 'Complex Task Filter',
|
|
428
|
+
sources: [{
|
|
429
|
+
name: 'tasks',
|
|
430
|
+
workflowId: 'tasks-workflow-id',
|
|
431
|
+
fields: [
|
|
432
|
+
{ name: 'title', meta: 'name' },
|
|
433
|
+
{ name: 'priority', fieldId: 'priority-field-id' },
|
|
434
|
+
{ name: 'status', fieldId: 'status-field-id' },
|
|
435
|
+
{ name: 'dueDate', fieldId: 'due-date-field-id' }
|
|
436
|
+
]
|
|
437
|
+
}],
|
|
438
|
+
query: `
|
|
439
|
+
SELECT title, priority, status, dueDate
|
|
440
|
+
FROM tasks
|
|
441
|
+
WHERE (priority = 'High' OR priority = 'Urgent')
|
|
442
|
+
AND status != 'Done'
|
|
443
|
+
AND (dueDate < '2024-12-31' OR dueDate IS NULL)
|
|
444
|
+
ORDER BY priority DESC, dueDate ASC
|
|
445
|
+
`
|
|
446
|
+
})
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Calculated Columns
|
|
450
|
+
|
|
451
|
+
**String concatenation:**
|
|
452
|
+
```sql
|
|
453
|
+
SELECT
|
|
454
|
+
title || ' - ' || priority AS "Full Description"
|
|
455
|
+
FROM tasks
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Date calculations:**
|
|
459
|
+
```sql
|
|
460
|
+
SELECT
|
|
461
|
+
title,
|
|
462
|
+
dueDate,
|
|
463
|
+
JULIANDAY(dueDate) - JULIANDAY('now') AS "Days Until Due"
|
|
464
|
+
FROM tasks
|
|
465
|
+
WHERE dueDate > date('now')
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Subqueries
|
|
469
|
+
|
|
470
|
+
**Filter by subquery result:**
|
|
471
|
+
```sql
|
|
472
|
+
SELECT title, projectId
|
|
473
|
+
FROM tasks
|
|
474
|
+
WHERE projectId IN (
|
|
475
|
+
SELECT id
|
|
476
|
+
FROM projects
|
|
477
|
+
WHERE status = 'Active'
|
|
478
|
+
)
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Joins and Relationships
|
|
482
|
+
|
|
483
|
+
### INNER JOIN
|
|
484
|
+
|
|
485
|
+
**Only matching records:**
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
create_insight({
|
|
489
|
+
name: 'Tasks with Projects (Must Have Project)',
|
|
490
|
+
sources: [
|
|
491
|
+
{
|
|
492
|
+
name: 'tasks',
|
|
493
|
+
workflowId: 'tasks-workflow-id',
|
|
494
|
+
fields: [
|
|
495
|
+
{ name: 'taskName', meta: 'name' },
|
|
496
|
+
{ name: 'projectLink', fieldId: 'project-link-field-id' }
|
|
497
|
+
]
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
name: 'projects',
|
|
501
|
+
workflowId: 'projects-workflow-id',
|
|
502
|
+
fields: [
|
|
503
|
+
{ name: 'id', meta: '_id' },
|
|
504
|
+
{ name: 'projectName', meta: 'name' }
|
|
505
|
+
]
|
|
506
|
+
}
|
|
507
|
+
],
|
|
508
|
+
query: `
|
|
509
|
+
SELECT tasks.taskName, projects.projectName
|
|
510
|
+
FROM tasks
|
|
511
|
+
INNER JOIN projects ON tasks.projectLink = projects.id
|
|
512
|
+
`
|
|
513
|
+
})
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### LEFT JOIN
|
|
517
|
+
|
|
518
|
+
**All left records + matching right records:**
|
|
519
|
+
|
|
520
|
+
```javascript
|
|
521
|
+
create_insight({
|
|
522
|
+
name: 'All Tasks with Optional Projects',
|
|
523
|
+
sources: [
|
|
524
|
+
{
|
|
525
|
+
name: 'tasks',
|
|
526
|
+
workflowId: 'tasks-workflow-id',
|
|
527
|
+
fields: [
|
|
528
|
+
{ name: 'taskName', meta: 'name' },
|
|
529
|
+
{ name: 'projectLink', fieldId: 'project-link-field-id' }
|
|
530
|
+
]
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
name: 'projects',
|
|
534
|
+
workflowId: 'projects-workflow-id',
|
|
535
|
+
fields: [
|
|
536
|
+
{ name: 'id', meta: '_id' },
|
|
537
|
+
{ name: 'projectName', meta: 'name' }
|
|
538
|
+
]
|
|
539
|
+
}
|
|
540
|
+
],
|
|
541
|
+
query: `
|
|
542
|
+
SELECT
|
|
543
|
+
tasks.taskName,
|
|
544
|
+
COALESCE(projects.projectName, 'No Project') AS projectName
|
|
545
|
+
FROM tasks
|
|
546
|
+
LEFT JOIN projects ON tasks.projectLink = projects.id
|
|
547
|
+
`
|
|
548
|
+
})
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Multiple Joins
|
|
552
|
+
|
|
553
|
+
**Three-level hierarchy:**
|
|
554
|
+
|
|
555
|
+
```javascript
|
|
556
|
+
create_insight({
|
|
557
|
+
name: 'Tasks โ Topics โ Projects',
|
|
558
|
+
sources: [
|
|
559
|
+
{
|
|
560
|
+
name: 'tasks',
|
|
561
|
+
workflowId: 'tasks-workflow-id',
|
|
562
|
+
fields: [
|
|
563
|
+
{ name: 'taskName', meta: 'name' },
|
|
564
|
+
{ name: 'topicLink', fieldId: 'topic-field-id' }
|
|
565
|
+
]
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
name: 'topics',
|
|
569
|
+
workflowId: 'topics-workflow-id',
|
|
570
|
+
fields: [
|
|
571
|
+
{ name: 'id', meta: '_id' },
|
|
572
|
+
{ name: 'topicName', meta: 'name' },
|
|
573
|
+
{ name: 'projectLink', fieldId: 'project-field-id' }
|
|
574
|
+
]
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
name: 'projects',
|
|
578
|
+
workflowId: 'projects-workflow-id',
|
|
579
|
+
fields: [
|
|
580
|
+
{ name: 'id', meta: '_id' },
|
|
581
|
+
{ name: 'projectName', meta: 'name' }
|
|
582
|
+
]
|
|
583
|
+
}
|
|
584
|
+
],
|
|
585
|
+
query: `
|
|
586
|
+
SELECT
|
|
587
|
+
tasks.taskName,
|
|
588
|
+
topics.topicName,
|
|
589
|
+
projects.projectName
|
|
590
|
+
FROM tasks
|
|
591
|
+
LEFT JOIN topics ON tasks.topicLink = topics.id
|
|
592
|
+
LEFT JOIN projects ON topics.projectLink = projects.id
|
|
593
|
+
`
|
|
594
|
+
})
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
## Aggregations and Grouping
|
|
598
|
+
|
|
599
|
+
### COUNT
|
|
600
|
+
|
|
601
|
+
**Count all activities:**
|
|
602
|
+
```javascript
|
|
603
|
+
create_insight({
|
|
604
|
+
name: 'Total Task Count',
|
|
605
|
+
sources: [{
|
|
606
|
+
name: 'tasks',
|
|
607
|
+
workflowId: 'tasks-workflow-id',
|
|
608
|
+
fields: [
|
|
609
|
+
{ name: 'id', meta: '_id' }
|
|
610
|
+
]
|
|
611
|
+
}],
|
|
612
|
+
query: 'SELECT COUNT(*) AS total FROM tasks'
|
|
613
|
+
})
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**Count by group:**
|
|
617
|
+
```javascript
|
|
618
|
+
create_insight({
|
|
619
|
+
name: 'Tasks by Priority',
|
|
620
|
+
sources: [{
|
|
621
|
+
name: 'tasks',
|
|
622
|
+
workflowId: 'tasks-workflow-id',
|
|
623
|
+
fields: [
|
|
624
|
+
{ name: 'priority', fieldId: 'priority-field-id' }
|
|
625
|
+
]
|
|
626
|
+
}],
|
|
627
|
+
query: `
|
|
628
|
+
SELECT priority, COUNT(*) AS count
|
|
629
|
+
FROM tasks
|
|
630
|
+
GROUP BY priority
|
|
631
|
+
ORDER BY count DESC
|
|
632
|
+
`
|
|
633
|
+
})
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### SUM
|
|
637
|
+
|
|
638
|
+
**Sum numeric values:**
|
|
639
|
+
```javascript
|
|
640
|
+
create_insight({
|
|
641
|
+
name: 'Total Project Budget',
|
|
642
|
+
sources: [{
|
|
643
|
+
name: 'projects',
|
|
644
|
+
workflowId: 'projects-workflow-id',
|
|
645
|
+
fields: [
|
|
646
|
+
{ name: 'budget', fieldId: 'budget-field-id' }
|
|
647
|
+
]
|
|
648
|
+
}],
|
|
649
|
+
query: 'SELECT SUM(budget) AS totalBudget FROM projects'
|
|
650
|
+
})
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
**Sum by group:**
|
|
654
|
+
```javascript
|
|
655
|
+
create_insight({
|
|
656
|
+
name: 'Budget by Status',
|
|
657
|
+
sources: [{
|
|
658
|
+
name: 'projects',
|
|
659
|
+
workflowId: 'projects-workflow-id',
|
|
660
|
+
fields: [
|
|
661
|
+
{ name: 'status', fieldId: 'status-field-id' },
|
|
662
|
+
{ name: 'budget', fieldId: 'budget-field-id' }
|
|
663
|
+
]
|
|
664
|
+
}],
|
|
665
|
+
query: `
|
|
666
|
+
SELECT status, SUM(budget) AS totalBudget
|
|
667
|
+
FROM projects
|
|
668
|
+
GROUP BY status
|
|
669
|
+
`
|
|
670
|
+
})
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### AVG, MIN, MAX
|
|
674
|
+
|
|
675
|
+
**Statistical aggregations:**
|
|
676
|
+
```javascript
|
|
677
|
+
create_insight({
|
|
678
|
+
name: 'Project Budget Statistics',
|
|
679
|
+
sources: [{
|
|
680
|
+
name: 'projects',
|
|
681
|
+
workflowId: 'projects-workflow-id',
|
|
682
|
+
fields: [
|
|
683
|
+
{ name: 'budget', fieldId: 'budget-field-id' }
|
|
684
|
+
]
|
|
685
|
+
}],
|
|
686
|
+
query: `
|
|
687
|
+
SELECT
|
|
688
|
+
AVG(budget) AS avgBudget,
|
|
689
|
+
MIN(budget) AS minBudget,
|
|
690
|
+
MAX(budget) AS maxBudget,
|
|
691
|
+
COUNT(*) AS projectCount
|
|
692
|
+
FROM projects
|
|
693
|
+
`
|
|
694
|
+
})
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### HAVING Clause
|
|
698
|
+
|
|
699
|
+
**Filter aggregated results:**
|
|
700
|
+
```javascript
|
|
701
|
+
create_insight({
|
|
702
|
+
name: 'Priorities with 5+ Tasks',
|
|
703
|
+
sources: [{
|
|
704
|
+
name: 'tasks',
|
|
705
|
+
workflowId: 'tasks-workflow-id',
|
|
706
|
+
fields: [
|
|
707
|
+
{ name: 'priority', fieldId: 'priority-field-id' }
|
|
708
|
+
]
|
|
709
|
+
}],
|
|
710
|
+
query: `
|
|
711
|
+
SELECT priority, COUNT(*) AS taskCount
|
|
712
|
+
FROM tasks
|
|
713
|
+
GROUP BY priority
|
|
714
|
+
HAVING COUNT(*) >= 5
|
|
715
|
+
ORDER BY taskCount DESC
|
|
716
|
+
`
|
|
717
|
+
})
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
## Best Practices
|
|
721
|
+
|
|
722
|
+
### 1. Test with preview_insight First
|
|
723
|
+
|
|
724
|
+
**Always test queries before creating:**
|
|
725
|
+
|
|
726
|
+
```javascript
|
|
727
|
+
// 1. Test with preview
|
|
728
|
+
preview_insight({
|
|
729
|
+
sources: [...],
|
|
730
|
+
query: 'SELECT ...'
|
|
731
|
+
})
|
|
732
|
+
|
|
733
|
+
// 2. If successful, create insight
|
|
734
|
+
create_insight({
|
|
735
|
+
name: 'My Insight',
|
|
736
|
+
sources: [...],
|
|
737
|
+
query: 'SELECT ...'
|
|
738
|
+
})
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
### 2. Use Descriptive Source Names
|
|
742
|
+
|
|
743
|
+
**Bad:**
|
|
744
|
+
```javascript
|
|
745
|
+
sources: [
|
|
746
|
+
{ name: 't1', workflowId: '...' },
|
|
747
|
+
{ name: 't2', workflowId: '...' }
|
|
748
|
+
]
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
**Good:**
|
|
752
|
+
```javascript
|
|
753
|
+
sources: [
|
|
754
|
+
{ name: 'tasks', workflowId: '...' },
|
|
755
|
+
{ name: 'projects', workflowId: '...' }
|
|
756
|
+
]
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
### 3. Use Descriptive Column Names
|
|
760
|
+
|
|
761
|
+
**Bad:**
|
|
762
|
+
```sql
|
|
763
|
+
SELECT t.a, p.b FROM tasks t JOIN projects p ON t.c = p.d
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
**Good:**
|
|
767
|
+
```sql
|
|
768
|
+
SELECT
|
|
769
|
+
tasks.taskName AS "Task Name",
|
|
770
|
+
projects.projectName AS "Project Name"
|
|
771
|
+
FROM tasks
|
|
772
|
+
LEFT JOIN projects ON tasks.projectId = projects.id
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### 4. Include id Field for JOINs
|
|
776
|
+
|
|
777
|
+
**Always include _id in sources used for joins:**
|
|
778
|
+
|
|
779
|
+
```javascript
|
|
780
|
+
sources: [
|
|
781
|
+
{
|
|
782
|
+
name: 'projects',
|
|
783
|
+
workflowId: 'projects-workflow-id',
|
|
784
|
+
fields: [
|
|
785
|
+
{ name: 'id', meta: '_id' }, // Required for JOINs
|
|
786
|
+
{ name: 'projectName', meta: 'name' }
|
|
787
|
+
]
|
|
788
|
+
}
|
|
789
|
+
]
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
### 5. Use LEFT JOIN for Optional Relationships
|
|
793
|
+
|
|
794
|
+
```javascript
|
|
795
|
+
// Good: Shows all tasks, even without projects
|
|
796
|
+
LEFT JOIN projects ON tasks.projectId = projects.id
|
|
797
|
+
|
|
798
|
+
// Bad: Only shows tasks with projects
|
|
799
|
+
INNER JOIN projects ON tasks.projectId = projects.id
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
### 6. Get Field IDs from get_workflow_schema
|
|
803
|
+
|
|
804
|
+
```javascript
|
|
805
|
+
// 1. Get schema
|
|
806
|
+
const schema = get_workflow_schema({
|
|
807
|
+
workflowId: 'workflow-id'
|
|
808
|
+
})
|
|
809
|
+
|
|
810
|
+
// 2. Find field IDs
|
|
811
|
+
const priorityField = schema.fields.find(f => f.key === 'priority')
|
|
812
|
+
console.log('Priority field ID:', priorityField._id)
|
|
813
|
+
|
|
814
|
+
// 3. Use in insight
|
|
815
|
+
create_insight({
|
|
816
|
+
sources: [{
|
|
817
|
+
fields: [
|
|
818
|
+
{ name: 'priority', fieldId: priorityField._id }
|
|
819
|
+
]
|
|
820
|
+
}],
|
|
821
|
+
query: '...'
|
|
822
|
+
})
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
### 7. Handle NULL Values
|
|
826
|
+
|
|
827
|
+
**Use COALESCE for defaults:**
|
|
828
|
+
```sql
|
|
829
|
+
SELECT
|
|
830
|
+
taskName,
|
|
831
|
+
COALESCE(priority, 'Not Set') AS priority
|
|
832
|
+
FROM tasks
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**Check for NULL explicitly:**
|
|
836
|
+
```sql
|
|
837
|
+
SELECT taskName
|
|
838
|
+
FROM tasks
|
|
839
|
+
WHERE dueDate IS NOT NULL
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
### 8. Limit Large Result Sets
|
|
843
|
+
|
|
844
|
+
```sql
|
|
845
|
+
-- Good: Limit results
|
|
846
|
+
SELECT * FROM tasks ORDER BY created DESC LIMIT 100
|
|
847
|
+
|
|
848
|
+
-- Bad: Could return thousands of rows
|
|
849
|
+
SELECT * FROM tasks
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
### 9. Use Meaningful Insight Names
|
|
853
|
+
|
|
854
|
+
**Bad:**
|
|
855
|
+
- "Report 1"
|
|
856
|
+
- "Query"
|
|
857
|
+
- "Test"
|
|
858
|
+
|
|
859
|
+
**Good:**
|
|
860
|
+
- "High Priority Tasks Due This Month"
|
|
861
|
+
- "Projects by Team and Budget"
|
|
862
|
+
- "Task Completion Rate by Priority"
|
|
863
|
+
|
|
864
|
+
### 10. Document Complex Queries
|
|
865
|
+
|
|
866
|
+
```javascript
|
|
867
|
+
create_insight({
|
|
868
|
+
name: 'Task Status Report',
|
|
869
|
+
sources: [...],
|
|
870
|
+
query: `
|
|
871
|
+
-- Show all tasks with their project and priority
|
|
872
|
+
-- Excludes tasks in 'Done' status
|
|
873
|
+
-- Sorted by priority (High first) and due date
|
|
874
|
+
SELECT
|
|
875
|
+
tasks.taskName,
|
|
876
|
+
projects.projectName,
|
|
877
|
+
tasks.priority,
|
|
878
|
+
tasks.dueDate
|
|
879
|
+
FROM tasks
|
|
880
|
+
LEFT JOIN projects ON tasks.projectId = projects.id
|
|
881
|
+
WHERE tasks.status != 'Done'
|
|
882
|
+
ORDER BY
|
|
883
|
+
CASE tasks.priority
|
|
884
|
+
WHEN 'Urgent' THEN 1
|
|
885
|
+
WHEN 'High' THEN 2
|
|
886
|
+
WHEN 'Medium' THEN 3
|
|
887
|
+
ELSE 4
|
|
888
|
+
END,
|
|
889
|
+
tasks.dueDate ASC
|
|
890
|
+
`
|
|
891
|
+
})
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
## Common Patterns
|
|
895
|
+
|
|
896
|
+
### Pattern 1: Recent Activities Report
|
|
897
|
+
|
|
898
|
+
```javascript
|
|
899
|
+
create_insight({
|
|
900
|
+
name: 'Recently Created Tasks',
|
|
901
|
+
sources: [{
|
|
902
|
+
name: 'tasks',
|
|
903
|
+
workflowId: 'tasks-workflow-id',
|
|
904
|
+
fields: [
|
|
905
|
+
{ name: 'title', meta: 'name' },
|
|
906
|
+
{ name: 'created', meta: 'created' },
|
|
907
|
+
{ name: 'priority', fieldId: 'priority-field-id' }
|
|
908
|
+
]
|
|
909
|
+
}],
|
|
910
|
+
query: `
|
|
911
|
+
SELECT title, created, priority
|
|
912
|
+
FROM tasks
|
|
913
|
+
WHERE created >= date('now', '-7 days')
|
|
914
|
+
ORDER BY created DESC
|
|
915
|
+
`
|
|
916
|
+
})
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
### Pattern 2: Status Distribution
|
|
920
|
+
|
|
921
|
+
```javascript
|
|
922
|
+
create_insight({
|
|
923
|
+
name: 'Task Status Distribution',
|
|
924
|
+
sources: [{
|
|
925
|
+
name: 'tasks',
|
|
926
|
+
workflowId: 'tasks-workflow-id',
|
|
927
|
+
fields: [
|
|
928
|
+
{ name: 'status', meta: 'phase' }
|
|
929
|
+
]
|
|
930
|
+
}],
|
|
931
|
+
query: `
|
|
932
|
+
SELECT
|
|
933
|
+
status,
|
|
934
|
+
COUNT(*) AS count,
|
|
935
|
+
ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM tasks), 2) AS percentage
|
|
936
|
+
FROM tasks
|
|
937
|
+
GROUP BY status
|
|
938
|
+
ORDER BY count DESC
|
|
939
|
+
`
|
|
940
|
+
})
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
### Pattern 3: Overdue Tasks
|
|
944
|
+
|
|
945
|
+
```javascript
|
|
946
|
+
create_insight({
|
|
947
|
+
name: 'Overdue Tasks',
|
|
948
|
+
sources: [{
|
|
949
|
+
name: 'tasks',
|
|
950
|
+
workflowId: 'tasks-workflow-id',
|
|
951
|
+
fields: [
|
|
952
|
+
{ name: 'title', meta: 'name' },
|
|
953
|
+
{ name: 'dueDate', fieldId: 'due-date-field-id' },
|
|
954
|
+
{ name: 'priority', fieldId: 'priority-field-id' }
|
|
955
|
+
]
|
|
956
|
+
}],
|
|
957
|
+
query: `
|
|
958
|
+
SELECT title, dueDate, priority
|
|
959
|
+
FROM tasks
|
|
960
|
+
WHERE dueDate < date('now')
|
|
961
|
+
AND status != 'Done'
|
|
962
|
+
ORDER BY dueDate ASC
|
|
963
|
+
`
|
|
964
|
+
})
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
### Pattern 4: Monthly Trends
|
|
968
|
+
|
|
969
|
+
```javascript
|
|
970
|
+
create_insight({
|
|
971
|
+
name: 'Tasks Created Per Month',
|
|
972
|
+
sources: [{
|
|
973
|
+
name: 'tasks',
|
|
974
|
+
workflowId: 'tasks-workflow-id',
|
|
975
|
+
fields: [
|
|
976
|
+
{ name: 'created', meta: 'created' }
|
|
977
|
+
]
|
|
978
|
+
}],
|
|
979
|
+
query: `
|
|
980
|
+
SELECT
|
|
981
|
+
strftime('%Y-%m', created) AS month,
|
|
982
|
+
COUNT(*) AS taskCount
|
|
983
|
+
FROM tasks
|
|
984
|
+
GROUP BY month
|
|
985
|
+
ORDER BY month DESC
|
|
986
|
+
`
|
|
987
|
+
})
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
### Pattern 5: Top N Report
|
|
991
|
+
|
|
992
|
+
```javascript
|
|
993
|
+
create_insight({
|
|
994
|
+
name: 'Top 10 Projects by Task Count',
|
|
995
|
+
sources: [
|
|
996
|
+
{
|
|
997
|
+
name: 'tasks',
|
|
998
|
+
workflowId: 'tasks-workflow-id',
|
|
999
|
+
fields: [
|
|
1000
|
+
{ name: 'projectId', fieldId: 'project-field-id' }
|
|
1001
|
+
]
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
name: 'projects',
|
|
1005
|
+
workflowId: 'projects-workflow-id',
|
|
1006
|
+
fields: [
|
|
1007
|
+
{ name: 'id', meta: '_id' },
|
|
1008
|
+
{ name: 'projectName', meta: 'name' }
|
|
1009
|
+
]
|
|
1010
|
+
}
|
|
1011
|
+
],
|
|
1012
|
+
query: `
|
|
1013
|
+
SELECT
|
|
1014
|
+
projects.projectName,
|
|
1015
|
+
COUNT(tasks.projectId) AS taskCount
|
|
1016
|
+
FROM projects
|
|
1017
|
+
LEFT JOIN tasks ON projects.id = tasks.projectId
|
|
1018
|
+
GROUP BY projects.id, projects.projectName
|
|
1019
|
+
ORDER BY taskCount DESC
|
|
1020
|
+
LIMIT 10
|
|
1021
|
+
`
|
|
1022
|
+
})
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
### Pattern 6: Missing Data Report
|
|
1026
|
+
|
|
1027
|
+
```javascript
|
|
1028
|
+
create_insight({
|
|
1029
|
+
name: 'Tasks Without Due Date',
|
|
1030
|
+
sources: [{
|
|
1031
|
+
name: 'tasks',
|
|
1032
|
+
workflowId: 'tasks-workflow-id',
|
|
1033
|
+
fields: [
|
|
1034
|
+
{ name: 'title', meta: 'name' },
|
|
1035
|
+
{ name: 'dueDate', fieldId: 'due-date-field-id' },
|
|
1036
|
+
{ name: 'created', meta: 'created' }
|
|
1037
|
+
]
|
|
1038
|
+
}],
|
|
1039
|
+
query: `
|
|
1040
|
+
SELECT title, created
|
|
1041
|
+
FROM tasks
|
|
1042
|
+
WHERE dueDate IS NULL
|
|
1043
|
+
ORDER BY created DESC
|
|
1044
|
+
`
|
|
1045
|
+
})
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
## Troubleshooting
|
|
1049
|
+
|
|
1050
|
+
### Error: "SQL Query Error"
|
|
1051
|
+
|
|
1052
|
+
**Cause:** Invalid SQL syntax.
|
|
1053
|
+
|
|
1054
|
+
**Solutions:**
|
|
1055
|
+
|
|
1056
|
+
1. **Test with preview_insight first:**
|
|
1057
|
+
```javascript
|
|
1058
|
+
preview_insight({
|
|
1059
|
+
sources: [...],
|
|
1060
|
+
query: 'SELECT ...'
|
|
1061
|
+
})
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
2. **Check common syntax errors:**
|
|
1065
|
+
```sql
|
|
1066
|
+
-- Missing FROM clause
|
|
1067
|
+
SELECT title -- โ Missing FROM
|
|
1068
|
+
SELECT title FROM tasks -- โ
Correct
|
|
1069
|
+
|
|
1070
|
+
-- Invalid column name
|
|
1071
|
+
SELECT titleee FROM tasks -- โ Typo
|
|
1072
|
+
SELECT title FROM tasks -- โ
Correct
|
|
1073
|
+
|
|
1074
|
+
-- Missing quotes around strings
|
|
1075
|
+
WHERE priority = High -- โ No quotes
|
|
1076
|
+
WHERE priority = 'High' -- โ
Quoted
|
|
1077
|
+
|
|
1078
|
+
-- Unmatched parentheses
|
|
1079
|
+
WHERE (priority = 'High' -- โ Missing )
|
|
1080
|
+
WHERE (priority = 'High') -- โ
Matched
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
3. **Verify field names match source definitions:**
|
|
1084
|
+
```javascript
|
|
1085
|
+
sources: [{
|
|
1086
|
+
fields: [
|
|
1087
|
+
{ name: 'priority', fieldId: '...' } // Name must match query
|
|
1088
|
+
]
|
|
1089
|
+
}],
|
|
1090
|
+
query: 'SELECT priority FROM tasks' // Must use 'priority'
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
### Error: "Invalid field IDs or workflow IDs"
|
|
1094
|
+
|
|
1095
|
+
**Cause:** Field IDs don't exist in workflow.
|
|
1096
|
+
|
|
1097
|
+
**Solution:**
|
|
1098
|
+
|
|
1099
|
+
```javascript
|
|
1100
|
+
// 1. Get correct field IDs
|
|
1101
|
+
const schema = get_workflow_schema({
|
|
1102
|
+
workflowId: 'workflow-id'
|
|
1103
|
+
})
|
|
1104
|
+
|
|
1105
|
+
// 2. Find field
|
|
1106
|
+
const field = schema.fields.find(f => f.key === 'priority')
|
|
1107
|
+
console.log('Field ID:', field._id)
|
|
1108
|
+
|
|
1109
|
+
// 3. Use correct ID
|
|
1110
|
+
create_insight({
|
|
1111
|
+
sources: [{
|
|
1112
|
+
fields: [
|
|
1113
|
+
{ name: 'priority', fieldId: field._id } // Correct ID
|
|
1114
|
+
]
|
|
1115
|
+
}]
|
|
1116
|
+
})
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
### Error: "Permission Denied"
|
|
1120
|
+
|
|
1121
|
+
**Cause:** Don't have permission to create insights or access workflows.
|
|
1122
|
+
|
|
1123
|
+
**Solution:**
|
|
1124
|
+
- Check workspace permissions
|
|
1125
|
+
- Verify access to all workflows in sources
|
|
1126
|
+
- Contact workspace administrator
|
|
1127
|
+
|
|
1128
|
+
### Insight Created But Returns No Data
|
|
1129
|
+
|
|
1130
|
+
**Causes:**
|
|
1131
|
+
1. No activities match WHERE clause
|
|
1132
|
+
2. JOIN eliminates all rows
|
|
1133
|
+
3. Field values are NULL
|
|
1134
|
+
|
|
1135
|
+
**Solutions:**
|
|
1136
|
+
|
|
1137
|
+
1. **Check activity count:**
|
|
1138
|
+
```javascript
|
|
1139
|
+
list_activities({
|
|
1140
|
+
workflowId: 'workflow-id',
|
|
1141
|
+
limit: 1
|
|
1142
|
+
})
|
|
1143
|
+
```
|
|
1144
|
+
|
|
1145
|
+
2. **Simplify query to test:**
|
|
1146
|
+
```sql
|
|
1147
|
+
-- Start simple
|
|
1148
|
+
SELECT * FROM tasks LIMIT 10
|
|
1149
|
+
|
|
1150
|
+
-- Then add filters one by one
|
|
1151
|
+
SELECT * FROM tasks WHERE priority = 'High' LIMIT 10
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
3. **Use LEFT JOIN instead of INNER JOIN:**
|
|
1155
|
+
```sql
|
|
1156
|
+
-- Shows all tasks, even without projects
|
|
1157
|
+
LEFT JOIN projects ON tasks.projectId = projects.id
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
### JOIN Not Working
|
|
1161
|
+
|
|
1162
|
+
**Cause:** ActivityLink field ID used instead of activity ID.
|
|
1163
|
+
|
|
1164
|
+
**Solution:**
|
|
1165
|
+
|
|
1166
|
+
```javascript
|
|
1167
|
+
// Correct: Join on activity _id
|
|
1168
|
+
sources: [
|
|
1169
|
+
{
|
|
1170
|
+
name: 'projects',
|
|
1171
|
+
fields: [
|
|
1172
|
+
{ name: 'id', meta: '_id' } // Use _id for joins
|
|
1173
|
+
]
|
|
1174
|
+
}
|
|
1175
|
+
],
|
|
1176
|
+
query: 'LEFT JOIN projects ON tasks.projectId = projects.id'
|
|
1177
|
+
|
|
1178
|
+
// Note: projectId field should contain activity ID, not field ID
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
### Aggregation Returns Unexpected Results
|
|
1182
|
+
|
|
1183
|
+
**Cause:** Missing GROUP BY or incorrect grouping.
|
|
1184
|
+
|
|
1185
|
+
**Solution:**
|
|
1186
|
+
|
|
1187
|
+
```sql
|
|
1188
|
+
-- Correct: Group by all non-aggregated columns
|
|
1189
|
+
SELECT priority, COUNT(*) AS count
|
|
1190
|
+
FROM tasks
|
|
1191
|
+
GROUP BY priority
|
|
1192
|
+
|
|
1193
|
+
-- Incorrect: Missing GROUP BY
|
|
1194
|
+
SELECT priority, COUNT(*) AS count -- โ Error
|
|
1195
|
+
FROM tasks
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
## Integration with Other Tools
|
|
1199
|
+
|
|
1200
|
+
### With preview_insight
|
|
1201
|
+
|
|
1202
|
+
Test before creating:
|
|
1203
|
+
|
|
1204
|
+
```javascript
|
|
1205
|
+
// 1. Preview first
|
|
1206
|
+
preview_insight({
|
|
1207
|
+
sources: [...],
|
|
1208
|
+
query: 'SELECT ...'
|
|
1209
|
+
})
|
|
1210
|
+
|
|
1211
|
+
// 2. If successful, create
|
|
1212
|
+
create_insight({
|
|
1213
|
+
name: 'My Insight',
|
|
1214
|
+
sources: [...],
|
|
1215
|
+
query: 'SELECT ...'
|
|
1216
|
+
})
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
### With get_insight_data
|
|
1220
|
+
|
|
1221
|
+
Execute after creation:
|
|
1222
|
+
|
|
1223
|
+
```javascript
|
|
1224
|
+
// 1. Create insight
|
|
1225
|
+
const result = create_insight({...})
|
|
1226
|
+
// Returns: { insightId: '...' }
|
|
1227
|
+
|
|
1228
|
+
// 2. Get data
|
|
1229
|
+
get_insight_data({
|
|
1230
|
+
insightId: result.insightId
|
|
1231
|
+
})
|
|
1232
|
+
```
|
|
1233
|
+
|
|
1234
|
+
### With get_workflow_schema
|
|
1235
|
+
|
|
1236
|
+
Get field IDs:
|
|
1237
|
+
|
|
1238
|
+
```javascript
|
|
1239
|
+
// 1. Get schema
|
|
1240
|
+
const schema = get_workflow_schema({
|
|
1241
|
+
workflowId: 'workflow-id'
|
|
1242
|
+
})
|
|
1243
|
+
|
|
1244
|
+
// 2. Map fields to IDs
|
|
1245
|
+
const fieldMappings = schema.fields
|
|
1246
|
+
.filter(f => f.key)
|
|
1247
|
+
.map(f => ({
|
|
1248
|
+
name: f.key,
|
|
1249
|
+
fieldId: f._id
|
|
1250
|
+
}))
|
|
1251
|
+
|
|
1252
|
+
// 3. Use in insight
|
|
1253
|
+
create_insight({
|
|
1254
|
+
sources: [{
|
|
1255
|
+
workflowId: 'workflow-id',
|
|
1256
|
+
fields: fieldMappings
|
|
1257
|
+
}],
|
|
1258
|
+
query: '...'
|
|
1259
|
+
})
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
### With list_workflows
|
|
1263
|
+
|
|
1264
|
+
Find workflow IDs:
|
|
1265
|
+
|
|
1266
|
+
```javascript
|
|
1267
|
+
// 1. List workflows
|
|
1268
|
+
const workflows = list_workflows()
|
|
1269
|
+
|
|
1270
|
+
// 2. Find specific workflows
|
|
1271
|
+
const tasks = workflows.find(w => w.name === 'Tasks')
|
|
1272
|
+
const projects = workflows.find(w => w.name === 'Projects')
|
|
1273
|
+
|
|
1274
|
+
// 3. Create insight
|
|
1275
|
+
create_insight({
|
|
1276
|
+
sources: [
|
|
1277
|
+
{ name: 'tasks', workflowId: tasks._id, ... },
|
|
1278
|
+
{ name: 'projects', workflowId: projects._id, ... }
|
|
1279
|
+
],
|
|
1280
|
+
query: '...'
|
|
1281
|
+
})
|
|
1282
|
+
```
|
|
1283
|
+
|
|
1284
|
+
## Summary
|
|
1285
|
+
|
|
1286
|
+
**Key Takeaways:**
|
|
1287
|
+
1. ๐ **SQL queries** - Full SQL syntax over workflow data
|
|
1288
|
+
2. ๐ **Cross-workflow joins** - Relate data across workflows
|
|
1289
|
+
3. ๐ **Aggregations** - COUNT, SUM, AVG, MIN, MAX
|
|
1290
|
+
4. ๐ **Meta fields** - Built-in activity properties (_id, name, created, etc.)
|
|
1291
|
+
5. ๐งช **Preview first** - Test queries with preview_insight
|
|
1292
|
+
6. ๐ **Public option** - Share insights without authentication
|
|
1293
|
+
7. ๐ **Real-time** - Insights update as activity data changes
|
|
1294
|
+
|
|
1295
|
+
**Quick Decision Tree:**
|
|
1296
|
+
|
|
1297
|
+
```
|
|
1298
|
+
Need to create an insight?
|
|
1299
|
+
โ
|
|
1300
|
+
โโ Single workflow? โ Use one source, simple SELECT
|
|
1301
|
+
โโ Multiple workflows? โ Use multiple sources with JOIN
|
|
1302
|
+
โโ Count/aggregate? โ Use GROUP BY with COUNT/SUM/AVG
|
|
1303
|
+
โโ Filter data? โ Add WHERE clause
|
|
1304
|
+
โโ Sort results? โ Add ORDER BY
|
|
1305
|
+
โโ Complex query? โ Test with preview_insight first
|
|
1306
|
+
โโ Share publicly? โ Set public: true
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
## Additional Resources
|
|
1310
|
+
|
|
1311
|
+
- See `preview-insight-skill` for testing queries
|
|
1312
|
+
- See `get-insight-data-skill` for executing insights
|
|
1313
|
+
- See `remove-insight-skill` for deleting insights
|
|
1314
|
+
- See `insight-api` skill for comprehensive Insight API documentation
|
|
1315
|
+
- See `hailer-api` skill for Hailer API reference
|
|
1316
|
+
- Use `get_workflow_schema` to find field IDs
|
|
1317
|
+
- Use `list_workflows` to find workflow IDs
|