inistate-core 0.1.0
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/LICENSE +82 -0
- package/README.md +283 -0
- package/data/inistate-schema.json +1197 -0
- package/dist/index.js +350 -0
- package/package.json +56 -0
|
@@ -0,0 +1,1197 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "INISTATE — Initial State Module Schema",
|
|
4
|
+
"description": "Subset of the FACTS schema for defining module structure without listings. All identifiers use display names — internal IDs, GUIDs, and numeric enums are resolved automatically by the MCP layer.",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
|
|
7
|
+
"definitions": {
|
|
8
|
+
"FieldType": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Human-readable field type. The MCP layer maps these to/from internal numeric enums automatically.",
|
|
11
|
+
"enum": [
|
|
12
|
+
"Text", "YesNo", "Integer", "Number", "Currency",
|
|
13
|
+
"Date", "DateTime", "DateRange",
|
|
14
|
+
"Selection", "Tag",
|
|
15
|
+
"User", "Users", "Module", "Modules",
|
|
16
|
+
"Image", "Images", "File", "Files",
|
|
17
|
+
"Table",
|
|
18
|
+
"MultiText",
|
|
19
|
+
"Email", "Phone", "Link", "Signature", "Formula"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
"FieldDefinition": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"description": "A module field as seen through the MCP abstraction.",
|
|
26
|
+
"required": ["name", "type"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"id": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Stable opaque identifier. Absent on create, present on read/update. Enables renaming — the MCP layer matches by id when present, falling back to name for new fields."
|
|
31
|
+
},
|
|
32
|
+
"name": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "Display name. Used as the key in all MCP input/output payloads (e.g. 'Leave Type', not 'xKfLmNpQ')."
|
|
35
|
+
},
|
|
36
|
+
"type": { "$ref": "#/definitions/FieldType" },
|
|
37
|
+
"options": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"items": { "type": "string" },
|
|
40
|
+
"description": "Available option names for Selection/Tag fields. Each option may optionally start with an emoji prefix (e.g. '🏖️ Annual Leave', '🏥 Sick Leave', '💰 Cash'). Shorthand: Selection(Option1/Option2/Option3)."
|
|
41
|
+
},
|
|
42
|
+
"fields": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": { "$ref": "#/definitions/SubFieldDefinition" },
|
|
45
|
+
"description": "Sub-field definitions for Table type. Each sub-field defines a column in the table."
|
|
46
|
+
},
|
|
47
|
+
"ai_hint": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "Natural-language guidance for AI agents on how to interpret or populate this field."
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"additionalProperties": false
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
"SubFieldDefinition": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"description": "Sub-field (column) within a Table field.",
|
|
58
|
+
"required": ["name", "type"],
|
|
59
|
+
"properties": {
|
|
60
|
+
"id": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"description": "Stable opaque identifier. Absent on create, present on read/update."
|
|
63
|
+
},
|
|
64
|
+
"name": { "type": "string", "description": "Display name of the sub-field." },
|
|
65
|
+
"type": { "$ref": "#/definitions/FieldType" },
|
|
66
|
+
"options": {
|
|
67
|
+
"type": "array",
|
|
68
|
+
"items": { "type": "string" },
|
|
69
|
+
"description": "Options for Selection/Tag sub-fields. Each option may optionally start with an emoji prefix (e.g. '🏖️ Annual Leave')."
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"additionalProperties": false
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
"StateDefinition": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"description": "A workflow state. MCP resolves names to internal GUIDs automatically.",
|
|
78
|
+
"required": ["name"],
|
|
79
|
+
"properties": {
|
|
80
|
+
"id": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"description": "Stable opaque identifier. Absent on create, present on read/update. Enables renaming states without breaking flows."
|
|
83
|
+
},
|
|
84
|
+
"name": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"description": "State display name (e.g. 'Approved', not a GUID)."
|
|
87
|
+
},
|
|
88
|
+
"color": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"description": "Hex color code for the state badge (white text on colored background). Choose based on attention level and sentiment: #5A6070 (grey) = not started/idle, #2968A8 (blue) = waiting for action, #2A7B50 (green) = active work in progress, #A07828 (amber) = at risk/deadline approaching, #C0392B (red) = urgent/SLA breached, #6B4D91 (purple) = externally blocked, #1E6B45 (dark green) = terminal success, #8B2D2D (dark red) = terminal failure/rejected. Rules: terminal success states must use #1E6B45, terminal failure/rejection/cancellation must use #8B2D2D, only use #2A7B50 for states where work is actively being executed, use #2968A8 for approved/completed states still awaiting next action."
|
|
91
|
+
},
|
|
92
|
+
"initial": {
|
|
93
|
+
"type": "boolean",
|
|
94
|
+
"description": "When true, new entries default to this state. Only one state should be initial.",
|
|
95
|
+
"default": false
|
|
96
|
+
},
|
|
97
|
+
"ai_hint": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Guidance for AI agents on when an entry should be in this state."
|
|
100
|
+
},
|
|
101
|
+
"ai_instruction": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"description": "Instruction for AI agents to execute when an entry reaches this state. Describes what the AI should do automatically (e.g. 'Notify the approver via email', 'Generate a summary report', 'Check inventory levels and flag if below threshold'). Unlike ai_hint (which describes the state), ai_instruction prescribes an action."
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"additionalProperties": false
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
"ActivityDefinition": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"description": "A custom activity (e.g. Approve, Reject). Standard activities (create, edit, delete, etc.) are implicit.",
|
|
112
|
+
"required": ["name"],
|
|
113
|
+
"properties": {
|
|
114
|
+
"id": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"description": "Stable opaque identifier. Absent on create, present on read/update. Enables renaming activities without breaking flows."
|
|
117
|
+
},
|
|
118
|
+
"name": {
|
|
119
|
+
"type": "string",
|
|
120
|
+
"description": "Activity display name. MCP resolves to internal activity ID."
|
|
121
|
+
},
|
|
122
|
+
"fields": {
|
|
123
|
+
"type": "array",
|
|
124
|
+
"description": "Fields included in this activity's form. Each item is either a field name string (shorthand) or an ActivityFieldRef object with constraints.",
|
|
125
|
+
"items": {
|
|
126
|
+
"oneOf": [
|
|
127
|
+
{
|
|
128
|
+
"type": "string",
|
|
129
|
+
"description": "Field display name (shorthand — defaults to required=false, readOnly=false)."
|
|
130
|
+
},
|
|
131
|
+
{ "$ref": "#/definitions/ActivityFieldRef" }
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"ai_hint": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"description": "Guidance for AI agents on when/how to perform this activity."
|
|
138
|
+
},
|
|
139
|
+
"ai_instruction": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"description": "Instruction for AI agents to execute when this activity is performed (e.g. 'Validate all required documents are attached before approving', 'Send notification to the finance team'). Unlike ai_hint (which guides when/how to trigger the activity), ai_instruction prescribes what to do when executing it."
|
|
142
|
+
},
|
|
143
|
+
"actor": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"enum": ["human", "ai", "hybrid"],
|
|
146
|
+
"description": "Who is expected to perform this activity. 'human' = only a person can execute it, 'ai' = an AI agent performs it autonomously, 'hybrid' = either a person or AI agent may perform it. Defaults to 'human' when omitted."
|
|
147
|
+
},
|
|
148
|
+
"confidence_threshold": {
|
|
149
|
+
"type": "number",
|
|
150
|
+
"minimum": 0,
|
|
151
|
+
"maximum": 1,
|
|
152
|
+
"description": "Minimum AI confidence required for this activity to proceed with a state transition. If ai_confidence < confidence_threshold, the state change is suppressed and the entry is flagged for human intervention. Omit or set to 0 to disable the gate."
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"additionalProperties": false
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
"ActivityFieldRef": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"description": "A field reference within an activity form, with per-field constraints.",
|
|
161
|
+
"required": ["name"],
|
|
162
|
+
"properties": {
|
|
163
|
+
"name": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"description": "Field display name. References FieldDefinition.name."
|
|
166
|
+
},
|
|
167
|
+
"required": {
|
|
168
|
+
"type": "boolean",
|
|
169
|
+
"description": "When true, this field must be filled to submit the activity.",
|
|
170
|
+
"default": false
|
|
171
|
+
},
|
|
172
|
+
"readOnly": {
|
|
173
|
+
"type": "boolean",
|
|
174
|
+
"description": "When true, the field is visible but not editable in this activity.",
|
|
175
|
+
"default": false
|
|
176
|
+
},
|
|
177
|
+
"options": {
|
|
178
|
+
"type": "array",
|
|
179
|
+
"items": { "type": "string" },
|
|
180
|
+
"description": "Subset of allowed options for Selection/Tag fields in this activity. Options may include emoji prefixes. Omit to allow all options."
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"additionalProperties": false
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
"FlowDefinition": {
|
|
187
|
+
"type": "object",
|
|
188
|
+
"description": "A state transition rule. All references use display names — MCP resolves to internal IDs.",
|
|
189
|
+
"required": ["from", "to", "activity"],
|
|
190
|
+
"properties": {
|
|
191
|
+
"from": {
|
|
192
|
+
"type": "string",
|
|
193
|
+
"description": "Source state name (matches StateDefinition.name). Empty string = any state."
|
|
194
|
+
},
|
|
195
|
+
"to": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"description": "Target state name (matches StateDefinition.name)."
|
|
198
|
+
},
|
|
199
|
+
"activity": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"description": "Activity name that triggers this transition (matches ActivityDefinition.name)."
|
|
202
|
+
},
|
|
203
|
+
"ai_hint": { "type": "string" }
|
|
204
|
+
},
|
|
205
|
+
"additionalProperties": false
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
"ModuleSchema": {
|
|
209
|
+
"type": "object",
|
|
210
|
+
"description": "INISTATE module definition — used for both input (create/update) and output (GET/POST/PUT responses). The configure endpoints accept and return this same shape. On output, 'id' is added and all elements include stable IDs for round-tripping. A module can be either a workflow module (with states, activities, and flows) or a record list module (master data, lookup tables, registries) that simply stores entries without any workflow. Record list modules omit states, activities, and flows entirely.",
|
|
211
|
+
"required": ["name"],
|
|
212
|
+
"properties": {
|
|
213
|
+
"id": {
|
|
214
|
+
"type": "integer",
|
|
215
|
+
"description": "Module ID. Present on responses, absent on create input. Required for update operations to identify which module to update."
|
|
216
|
+
},
|
|
217
|
+
"name": {
|
|
218
|
+
"type": "string",
|
|
219
|
+
"description": "Module name. On create, this is the new module's name. On update, this can rename the module."
|
|
220
|
+
},
|
|
221
|
+
"icon": {
|
|
222
|
+
"type": "string",
|
|
223
|
+
"description": "Emoji identifier for the module."
|
|
224
|
+
},
|
|
225
|
+
"description": {
|
|
226
|
+
"type": "string",
|
|
227
|
+
"description": "Human-readable module description for discovery."
|
|
228
|
+
},
|
|
229
|
+
"information": {
|
|
230
|
+
"type": "array",
|
|
231
|
+
"items": { "$ref": "#/definitions/FieldDefinition" },
|
|
232
|
+
"description": "Field definitions. Order determines default display order."
|
|
233
|
+
},
|
|
234
|
+
"states": {
|
|
235
|
+
"type": "array",
|
|
236
|
+
"items": { "$ref": "#/definitions/StateDefinition" },
|
|
237
|
+
"description": "Workflow states. First state with initial=true (or first state if none specified) is the default. Omit for record list modules that do not need workflow."
|
|
238
|
+
},
|
|
239
|
+
"activities": {
|
|
240
|
+
"type": "array",
|
|
241
|
+
"items": { "$ref": "#/definitions/ActivityDefinition" },
|
|
242
|
+
"description": "Custom activities (e.g. Approve, Reject). Standard activities (create, edit, delete, view, assign, comment, etc.) are always available. Omit for record list modules that only need standard activities."
|
|
243
|
+
},
|
|
244
|
+
"flows": {
|
|
245
|
+
"type": "array",
|
|
246
|
+
"items": { "$ref": "#/definitions/FlowDefinition" },
|
|
247
|
+
"description": "State transition rules linking activities to state changes. Omit for record list modules with no workflow."
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"_note": "Responses may include additional properties (updatedDate, version, summary, changes) beyond these base fields."
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
"FileUploadResult": {
|
|
254
|
+
"type": "object",
|
|
255
|
+
"description": "Response from uploading a file via MCP.",
|
|
256
|
+
"properties": {
|
|
257
|
+
"path": {
|
|
258
|
+
"type": "string",
|
|
259
|
+
"description": "Relative file path in /s/{shortId}/{fileName} format. Same key as FileFieldValue.path. To download, prepend /api/mcp/download/{moduleName}."
|
|
260
|
+
},
|
|
261
|
+
"filename": { "type": "string", "description": "Sanitized filename." },
|
|
262
|
+
"mimeType": { "type": "string", "description": "MIME type of the uploaded file." },
|
|
263
|
+
"size": { "type": "integer", "description": "File size in bytes." }
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
"PresignedUploadResult": {
|
|
268
|
+
"type": "object",
|
|
269
|
+
"description": "Response from requesting a presigned upload URL.",
|
|
270
|
+
"properties": {
|
|
271
|
+
"uploadUrl": { "type": "string", "description": "Presigned S3 PUT URL. Upload the file with HTTP PUT to this URL. Content-Type MUST match contentType exactly or S3 returns 403." },
|
|
272
|
+
"s3Key": { "type": "string", "description": "Internal S3 object key. Pass this to confirm_upload after uploading." },
|
|
273
|
+
"path": { "type": "string", "description": "Relative file path in /s/{shortId}/{fileName} format. Use this as the File/Image field value in submit_activity (same key as FileFieldValue.path)." },
|
|
274
|
+
"filename": { "type": "string", "description": "Sanitized filename." },
|
|
275
|
+
"contentType": { "type": "string", "description": "MIME type — use this exact value as the Content-Type header in the PUT request." },
|
|
276
|
+
"expiresIn": { "type": "integer", "description": "Seconds until the presigned URL expires (3600 = 1 hour)." }
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
"FileFieldValue": {
|
|
281
|
+
"type": "object",
|
|
282
|
+
"description": "Value shape for File/Image fields as stored and returned by MCP.",
|
|
283
|
+
"properties": {
|
|
284
|
+
"name": { "type": "string", "description": "Original filename (e.g. 'report.pdf')." },
|
|
285
|
+
"path": { "type": "string", "description": "Relative download path in /s/{shortId}/{fileName} format. To download, prepend /api/mcp/download/{moduleName}." }
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
"FileFieldInput": {
|
|
290
|
+
"type": "object",
|
|
291
|
+
"description": "Input shape for File/Image fields when submitting an activity. Provide a path from request_upload_url()+confirm_upload() (default) or an external URL. upload_file() is a fallback only.",
|
|
292
|
+
"required": ["name", "path"],
|
|
293
|
+
"properties": {
|
|
294
|
+
"name": { "type": "string", "description": "Filename (e.g. 'report.pdf'). Required." },
|
|
295
|
+
"path": { "type": "string", "description": "Either a path from request_upload_url()+confirm_upload() / upload_file() (fallback) (e.g. '/s/xK8m/report.pdf') or an external URL (e.g. 'https://example.com/report.pdf')." },
|
|
296
|
+
"type": { "type": "string", "description": "MIME type (optional, e.g. 'application/pdf')." }
|
|
297
|
+
},
|
|
298
|
+
"_notes": [
|
|
299
|
+
"For File/Image (single): value is one FileFieldInput object",
|
|
300
|
+
"For Files/Images (multiple): value is an array of FileFieldInput objects"
|
|
301
|
+
]
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
"ModuleFieldValue": {
|
|
305
|
+
"type": "object",
|
|
306
|
+
"description": "Value shape for Module (singular) fields. Round-trippable: output and input use the same shape.",
|
|
307
|
+
"properties": {
|
|
308
|
+
"value": { "type": "string", "description": "Display value of the referenced entry." },
|
|
309
|
+
"id": { "oneOf": [{ "type": "integer" }, { "type": "string" }], "description": "Entry ID of the referenced entry." }
|
|
310
|
+
},
|
|
311
|
+
"_notes": [
|
|
312
|
+
"Module (singular): value is one ModuleFieldValue object",
|
|
313
|
+
"Modules (plural): value is an array of ModuleFieldValue objects"
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
"UserFieldValue": {
|
|
318
|
+
"type": "object",
|
|
319
|
+
"description": "Value shape for User (singular) fields. Round-trippable: output and input use the same shape.",
|
|
320
|
+
"properties": {
|
|
321
|
+
"value": { "type": "string", "description": "Display name of the user." },
|
|
322
|
+
"id": { "oneOf": [{ "type": "integer" }, { "type": "string" }], "description": "Entry ID of the user entry." },
|
|
323
|
+
"username": { "type": "string", "description": "Username of the user." }
|
|
324
|
+
},
|
|
325
|
+
"_notes": [
|
|
326
|
+
"User (singular): value is one UserFieldValue object",
|
|
327
|
+
"Users (plural): value is an array of UserFieldValue objects"
|
|
328
|
+
]
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
"EntryData": {
|
|
332
|
+
"type": "object",
|
|
333
|
+
"description": "Entry field values as returned by MCP. Keys are field display names, values are typed according to FieldType. For File/Image fields, values are FileFieldValue objects ({ name, path }). For Module fields, values are ModuleFieldValue objects ({ value, id }). For User fields, values are UserFieldValue objects ({ value, id, username }). Plural variants (Files/Images/Modules/Users) use arrays of these objects.",
|
|
334
|
+
"additionalProperties": true
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
"Entry": {
|
|
338
|
+
"type": "object",
|
|
339
|
+
"description": "A single module entry as seen through MCP. All field values use display names as keys.",
|
|
340
|
+
"properties": {
|
|
341
|
+
"module": { "type": "string", "description": "Module name." },
|
|
342
|
+
"entryId": {
|
|
343
|
+
"oneOf": [{ "type": "integer" }, { "type": "string" }],
|
|
344
|
+
"description": "Unique entry identifier."
|
|
345
|
+
},
|
|
346
|
+
"documentId": {
|
|
347
|
+
"type": "string",
|
|
348
|
+
"description": "Auto-generated document ID (e.g. LV-2026-0001)."
|
|
349
|
+
},
|
|
350
|
+
"state": {
|
|
351
|
+
"type": "string",
|
|
352
|
+
"description": "Current state display name."
|
|
353
|
+
},
|
|
354
|
+
"date": {
|
|
355
|
+
"type": ["string", "null"],
|
|
356
|
+
"format": "date-time",
|
|
357
|
+
"description": "Entry date (business date, distinct from audit timestamps)."
|
|
358
|
+
},
|
|
359
|
+
"data": {
|
|
360
|
+
"$ref": "#/definitions/EntryData",
|
|
361
|
+
"description": "Field values keyed by display name."
|
|
362
|
+
},
|
|
363
|
+
"createdBy": { "type": "string" },
|
|
364
|
+
"createdDate": { "type": "string", "format": "date-time" },
|
|
365
|
+
"updatedBy": { "type": "string" },
|
|
366
|
+
"updatedDate": { "type": "string", "format": "date-time" },
|
|
367
|
+
"assignees": {
|
|
368
|
+
"type": "array",
|
|
369
|
+
"items": { "type": "string" },
|
|
370
|
+
"description": "Assigned usernames."
|
|
371
|
+
},
|
|
372
|
+
"due": {
|
|
373
|
+
"type": ["string", "null"],
|
|
374
|
+
"format": "date-time",
|
|
375
|
+
"description": "Due date, if assigned."
|
|
376
|
+
},
|
|
377
|
+
"availableActivities": {
|
|
378
|
+
"$ref": "#/definitions/AvailableActivities",
|
|
379
|
+
"description": "Activities available on this entry based on current state and user authorization."
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
"EntryList": {
|
|
385
|
+
"type": "object",
|
|
386
|
+
"description": "Paginated list of entries.",
|
|
387
|
+
"properties": {
|
|
388
|
+
"moduleId": { "type": "string" },
|
|
389
|
+
"page": { "type": "integer" },
|
|
390
|
+
"pageSize": { "type": "integer" },
|
|
391
|
+
"totalItems": { "type": "integer" },
|
|
392
|
+
"list": {
|
|
393
|
+
"type": "array",
|
|
394
|
+
"items": { "$ref": "#/definitions/Entry" }
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
|
|
399
|
+
"ActivityForm": {
|
|
400
|
+
"type": "object",
|
|
401
|
+
"description": "Form definition returned when preparing to perform an activity.",
|
|
402
|
+
"properties": {
|
|
403
|
+
"module": { "type": "string" },
|
|
404
|
+
"activity": { "type": "string" },
|
|
405
|
+
"entryId": {
|
|
406
|
+
"oneOf": [{ "type": "integer" }, { "type": "string" }, { "type": "null" }],
|
|
407
|
+
"description": "Entry ID when editing an existing entry. Null for create."
|
|
408
|
+
},
|
|
409
|
+
"documentId": { "type": ["string", "null"], "description": "Document ID of the entry, if applicable." },
|
|
410
|
+
"form": {
|
|
411
|
+
"type": "array",
|
|
412
|
+
"description": "Form fields. Each item is an object keyed by field display name, containing field definition properties.",
|
|
413
|
+
"items": {
|
|
414
|
+
"type": "object",
|
|
415
|
+
"description": "Single field: { \"Field Name\": { type, required?, readOnly?, options?, module?, fields? } }",
|
|
416
|
+
"additionalProperties": {
|
|
417
|
+
"type": "object",
|
|
418
|
+
"properties": {
|
|
419
|
+
"type": { "$ref": "#/definitions/FieldType" },
|
|
420
|
+
"required": { "type": "boolean" },
|
|
421
|
+
"readOnly": { "type": "boolean" },
|
|
422
|
+
"options": {
|
|
423
|
+
"type": "array",
|
|
424
|
+
"items": { "type": "string" },
|
|
425
|
+
"description": "Available options for Selection/Tag fields. Options may include emoji prefixes (e.g. '🏖️ Annual Leave')."
|
|
426
|
+
},
|
|
427
|
+
"module": {
|
|
428
|
+
"type": "string",
|
|
429
|
+
"description": "Referenced module name for Module/User field types."
|
|
430
|
+
},
|
|
431
|
+
"fields": {
|
|
432
|
+
"type": "array",
|
|
433
|
+
"description": "Sub-fields for Table/List types. Same keyed-by-name structure.",
|
|
434
|
+
"items": { "type": "object", "additionalProperties": true }
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
"_example": [
|
|
440
|
+
{ "Leave Type": { "type": "Selection", "required": true, "options": ["🏖️ Annual Leave", "🏥 Sick Leave", "📋 Unpaid Leave"] } },
|
|
441
|
+
{ "Start Date": { "type": "Date", "required": true } },
|
|
442
|
+
{ "Reason": { "type": "MultiText" } },
|
|
443
|
+
{ "Approver": { "type": "Text" } }
|
|
444
|
+
]
|
|
445
|
+
},
|
|
446
|
+
"defaults": {
|
|
447
|
+
"$ref": "#/definitions/EntryData",
|
|
448
|
+
"description": "Current/default values for pre-populating the form, keyed by display name."
|
|
449
|
+
},
|
|
450
|
+
"states": {
|
|
451
|
+
"type": "array",
|
|
452
|
+
"items": { "type": "string" },
|
|
453
|
+
"description": "Available target states for this activity."
|
|
454
|
+
},
|
|
455
|
+
"confidence_threshold": {
|
|
456
|
+
"type": "number",
|
|
457
|
+
"minimum": 0,
|
|
458
|
+
"maximum": 1,
|
|
459
|
+
"description": "The activity's confidence threshold for AI-driven state transitions. Present only when the activity has a threshold configured (> 0). AI agents should compare their confidence against this value before submitting."
|
|
460
|
+
},
|
|
461
|
+
"availableActivities": {
|
|
462
|
+
"$ref": "#/definitions/AvailableActivities",
|
|
463
|
+
"description": "Activities available on the entry in its current state."
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
"ActivitySubmission": {
|
|
469
|
+
"type": "object",
|
|
470
|
+
"description": "Payload for performing an activity on an entry. All keys use display names.",
|
|
471
|
+
"required": ["module"],
|
|
472
|
+
"properties": {
|
|
473
|
+
"module": { "type": "string", "description": "Module name." },
|
|
474
|
+
"activity": {
|
|
475
|
+
"type": "string",
|
|
476
|
+
"default": "create",
|
|
477
|
+
"description": "Activity name: create, edit, delete, or any custom activity name."
|
|
478
|
+
},
|
|
479
|
+
"entryId": {
|
|
480
|
+
"oneOf": [{ "type": "integer" }, { "type": "string" }],
|
|
481
|
+
"description": "Required for edit/delete/custom activities. Omit for create."
|
|
482
|
+
},
|
|
483
|
+
"entryIds": {
|
|
484
|
+
"type": "array",
|
|
485
|
+
"items": { "oneOf": [{ "type": "integer" }, { "type": "string" }] },
|
|
486
|
+
"description": "Multiple entry IDs for bulk operations."
|
|
487
|
+
},
|
|
488
|
+
"input": {
|
|
489
|
+
"type": "object",
|
|
490
|
+
"additionalProperties": true,
|
|
491
|
+
"description": "Field values keyed by display name. For File/Image fields, use FileFieldInput objects ({ name, path }). For Module fields, use ModuleFieldValue objects ({ value, id }). For User fields, use UserFieldValue objects ({ value, id, username }). Plural variants (Files/Images/Modules/Users) use arrays of these objects."
|
|
492
|
+
},
|
|
493
|
+
"state": {
|
|
494
|
+
"type": "string",
|
|
495
|
+
"description": "Target state name (resolved to internal ID automatically)."
|
|
496
|
+
},
|
|
497
|
+
"comment": { "type": "string" },
|
|
498
|
+
"assignees": {
|
|
499
|
+
"type": "array",
|
|
500
|
+
"items": { "type": "string" },
|
|
501
|
+
"description": "Usernames to assign."
|
|
502
|
+
},
|
|
503
|
+
"due": {
|
|
504
|
+
"type": "string",
|
|
505
|
+
"format": "date-time",
|
|
506
|
+
"description": "Due date for assignment."
|
|
507
|
+
},
|
|
508
|
+
"ai": {
|
|
509
|
+
"type": "object",
|
|
510
|
+
"description": "AI agent traceability context. Include when the submission is made by an AI agent.",
|
|
511
|
+
"properties": {
|
|
512
|
+
"reasoning": {
|
|
513
|
+
"type": "string",
|
|
514
|
+
"description": "Natural language explanation of the AI's decision."
|
|
515
|
+
},
|
|
516
|
+
"sources": {
|
|
517
|
+
"type": "array",
|
|
518
|
+
"items": {
|
|
519
|
+
"type": "object",
|
|
520
|
+
"properties": {
|
|
521
|
+
"type": { "type": "string", "description": "Source type (e.g. 'field', 'document', 'policy')." },
|
|
522
|
+
"reference": { "type": "string", "description": "Identifier or location of the source." },
|
|
523
|
+
"excerpt": { "type": "string", "description": "Relevant excerpt from the source." }
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
"description": "What data the AI used and from where."
|
|
527
|
+
},
|
|
528
|
+
"model": {
|
|
529
|
+
"type": "string",
|
|
530
|
+
"description": "Which model made this decision (e.g. claude-sonnet-4-20250514)."
|
|
531
|
+
},
|
|
532
|
+
"model_version": {
|
|
533
|
+
"type": "string",
|
|
534
|
+
"description": "Model version / checkpoint for reproducibility."
|
|
535
|
+
},
|
|
536
|
+
"prompt_hash": {
|
|
537
|
+
"type": "string",
|
|
538
|
+
"description": "Hash of the system prompt used, for version tracking."
|
|
539
|
+
},
|
|
540
|
+
"confidence": {
|
|
541
|
+
"type": "number",
|
|
542
|
+
"minimum": 0,
|
|
543
|
+
"maximum": 1,
|
|
544
|
+
"description": "Confidence score (0–1). If below the activity's confidence_threshold, the state transition is suppressed and the entry is flagged for human intervention."
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
|
|
551
|
+
"AvailableActivities": {
|
|
552
|
+
"type": "object",
|
|
553
|
+
"description": "Activities the current user can perform on the entry, based on authorization and current state.",
|
|
554
|
+
"properties": {
|
|
555
|
+
"standard": {
|
|
556
|
+
"type": "array",
|
|
557
|
+
"items": { "type": "string" },
|
|
558
|
+
"description": "Standard activities available (e.g. create, edit, delete, changeState, duplicate, comment, manage)."
|
|
559
|
+
},
|
|
560
|
+
"custom": {
|
|
561
|
+
"type": "array",
|
|
562
|
+
"items": { "type": "string" },
|
|
563
|
+
"description": "Custom activities available based on current state and flows."
|
|
564
|
+
},
|
|
565
|
+
"stateFlow": {
|
|
566
|
+
"type": "object",
|
|
567
|
+
"description": "Current state and possible transitions. Present only when the module has states.",
|
|
568
|
+
"properties": {
|
|
569
|
+
"currentState": { "type": "string", "description": "Current state name of the entry." },
|
|
570
|
+
"transitions": {
|
|
571
|
+
"type": "object",
|
|
572
|
+
"description": "Per-activity target state names. Keys are activity names, values are arrays of possible target state names.",
|
|
573
|
+
"additionalProperties": {
|
|
574
|
+
"type": "array",
|
|
575
|
+
"items": { "type": "string" }
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
|
|
583
|
+
"ActivityResult": {
|
|
584
|
+
"type": "object",
|
|
585
|
+
"description": "Response after performing an activity.",
|
|
586
|
+
"properties": {
|
|
587
|
+
"module": { "type": "string" },
|
|
588
|
+
"activity": { "type": "string" },
|
|
589
|
+
"entryId": { "oneOf": [{ "type": "integer" }, { "type": "string" }] },
|
|
590
|
+
"documentId": { "type": "string" },
|
|
591
|
+
"state": { "type": ["string", "null"] },
|
|
592
|
+
"message": { "type": ["string", "null"] },
|
|
593
|
+
"flagged": {
|
|
594
|
+
"type": "boolean",
|
|
595
|
+
"description": "True when AI confidence was below the activity's confidence_threshold. State transition was suppressed and the entry is flagged for human intervention (collaboration flags: WithIntention + LastIntention, history type: intention). Only present when true."
|
|
596
|
+
},
|
|
597
|
+
"ai_instruction": {
|
|
598
|
+
"type": "string",
|
|
599
|
+
"description": "Instruction for AI agents to execute, from the new state's ai_instruction field. Only present when the activity caused a state change and the target state has an ai_instruction defined."
|
|
600
|
+
},
|
|
601
|
+
"availableActivities": {
|
|
602
|
+
"$ref": "#/definitions/AvailableActivities",
|
|
603
|
+
"description": "Activities available on the entry after this activity was performed."
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
|
|
608
|
+
"HistoryEvent": {
|
|
609
|
+
"type": "object",
|
|
610
|
+
"description": "A single audit trail event.",
|
|
611
|
+
"properties": {
|
|
612
|
+
"id": { "type": "string" },
|
|
613
|
+
"type": {
|
|
614
|
+
"type": "string",
|
|
615
|
+
"enum": ["create", "edit", "activity", "changeStatus", "delete", "duplicate", "assign", "import", "intention", "comment", "clone", "manage"],
|
|
616
|
+
"description": "Event type."
|
|
617
|
+
},
|
|
618
|
+
"by": { "type": "string", "description": "Username who performed the action." },
|
|
619
|
+
"on": { "type": "string", "format": "date-time" },
|
|
620
|
+
"activity": { "type": ["string", "null"], "description": "Custom activity name, if applicable." },
|
|
621
|
+
"state": { "type": ["string", "null"], "description": "Resulting state name." },
|
|
622
|
+
"comment": { "type": ["string", "null"] },
|
|
623
|
+
"changes": {
|
|
624
|
+
"type": "array",
|
|
625
|
+
"items": {
|
|
626
|
+
"type": "object",
|
|
627
|
+
"properties": {
|
|
628
|
+
"field": { "type": "string", "description": "Field display name." },
|
|
629
|
+
"from": {},
|
|
630
|
+
"to": {}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
"replies": {
|
|
635
|
+
"type": "array",
|
|
636
|
+
"items": {
|
|
637
|
+
"type": "object",
|
|
638
|
+
"properties": {
|
|
639
|
+
"id": { "type": "string" },
|
|
640
|
+
"by": { "type": "string" },
|
|
641
|
+
"on": { "type": "string", "format": "date-time" },
|
|
642
|
+
"comment": { "type": "string" }
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
"ai": {
|
|
647
|
+
"type": "object",
|
|
648
|
+
"description": "AI agent traceability context captured at submission time. Present only on events submitted by an AI agent.",
|
|
649
|
+
"properties": {
|
|
650
|
+
"reasoning": { "type": "string", "description": "Natural language explanation of the AI's decision." },
|
|
651
|
+
"sources": {
|
|
652
|
+
"type": "array",
|
|
653
|
+
"items": {
|
|
654
|
+
"type": "object",
|
|
655
|
+
"properties": {
|
|
656
|
+
"type": { "type": "string" },
|
|
657
|
+
"reference": { "type": "string" },
|
|
658
|
+
"excerpt": { "type": "string" }
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
"model": { "type": "string" },
|
|
663
|
+
"model_version": { "type": "string" },
|
|
664
|
+
"prompt_hash": { "type": "string" },
|
|
665
|
+
"confidence": { "type": "number", "minimum": 0, "maximum": 1 }
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
|
|
671
|
+
"EntryHistory": {
|
|
672
|
+
"type": "object",
|
|
673
|
+
"description": "Paginated audit trail for an entry.",
|
|
674
|
+
"properties": {
|
|
675
|
+
"moduleId": { "type": "string" },
|
|
676
|
+
"entryId": { "oneOf": [{ "type": "integer" }, { "type": "string" }] },
|
|
677
|
+
"histories": {
|
|
678
|
+
"type": "array",
|
|
679
|
+
"items": { "$ref": "#/definitions/HistoryEvent" }
|
|
680
|
+
},
|
|
681
|
+
"hasMore": { "type": "boolean" },
|
|
682
|
+
"page": { "type": "integer" }
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
|
|
686
|
+
"FilterOperators": {
|
|
687
|
+
"type": "object",
|
|
688
|
+
"description": "Available filter operators for list_entries. Keys are field display names. Simple value = equality match.",
|
|
689
|
+
"properties": {
|
|
690
|
+
"_string": {
|
|
691
|
+
"type": "object",
|
|
692
|
+
"description": "String field operators",
|
|
693
|
+
"properties": {
|
|
694
|
+
"contains": { "type": "string" },
|
|
695
|
+
"startsWith": { "type": "string" },
|
|
696
|
+
"endsWith": { "type": "string" },
|
|
697
|
+
"is": { "type": "string" },
|
|
698
|
+
"not": { "type": "string" },
|
|
699
|
+
"excludes": { "type": "string" }
|
|
700
|
+
}
|
|
701
|
+
},
|
|
702
|
+
"_numeric": {
|
|
703
|
+
"type": "object",
|
|
704
|
+
"description": "Numeric/currency field operators",
|
|
705
|
+
"properties": {
|
|
706
|
+
"min": { "type": "number" },
|
|
707
|
+
"max": { "type": "number" },
|
|
708
|
+
"above": { "type": "number" },
|
|
709
|
+
"below": { "type": "number" },
|
|
710
|
+
"between": {
|
|
711
|
+
"type": "object",
|
|
712
|
+
"properties": {
|
|
713
|
+
"min": { "type": "number" },
|
|
714
|
+
"max": { "type": "number" }
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
"_date": {
|
|
720
|
+
"type": "object",
|
|
721
|
+
"description": "Date/DateTime field operators",
|
|
722
|
+
"properties": {
|
|
723
|
+
"after": { "type": "string", "format": "date" },
|
|
724
|
+
"before": { "type": "string", "format": "date" }
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
"_existence": {
|
|
728
|
+
"type": "object",
|
|
729
|
+
"description": "Presence/absence operators (any field type)",
|
|
730
|
+
"properties": {
|
|
731
|
+
"empty": { "type": "boolean" },
|
|
732
|
+
"exists": { "type": "boolean" }
|
|
733
|
+
}
|
|
734
|
+
},
|
|
735
|
+
"_boolean": {
|
|
736
|
+
"type": "object",
|
|
737
|
+
"description": "YesNo field operators",
|
|
738
|
+
"properties": {
|
|
739
|
+
"yes": { "type": "boolean" },
|
|
740
|
+
"no": { "type": "boolean" }
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
|
|
746
|
+
"ErrorResponse": {
|
|
747
|
+
"type": "object",
|
|
748
|
+
"description": "Standard error shape returned by all MCP endpoints.",
|
|
749
|
+
"properties": {
|
|
750
|
+
"error": { "type": "string", "description": "Short error code." },
|
|
751
|
+
"message": { "type": "string", "description": "Human-readable description." },
|
|
752
|
+
"details": {
|
|
753
|
+
"type": "array",
|
|
754
|
+
"description": "Validation details (422 only).",
|
|
755
|
+
"items": {
|
|
756
|
+
"type": "object",
|
|
757
|
+
"properties": {
|
|
758
|
+
"field": { "type": "string" },
|
|
759
|
+
"message": { "type": "string" }
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
"operations": {
|
|
768
|
+
"_description": "INISTATE operations map to MCP endpoints. Each operation uses display names exclusively — the MCP layer handles all internal ID resolution.",
|
|
769
|
+
|
|
770
|
+
"list_workspaces": {
|
|
771
|
+
"description": "List workspaces the current user can access. Call this first when no workspace is set — the chosen workspace ID must be passed on subsequent calls via the wsid header or the workspaceId tool parameter, otherwise every downstream call scopes to the wrong tenant.",
|
|
772
|
+
"parameters": {
|
|
773
|
+
"search": { "type": "string", "description": "Optional case-insensitive name filter. Use when the user names a workspace and you need to resolve it to an ID." }
|
|
774
|
+
},
|
|
775
|
+
"returns": {
|
|
776
|
+
"type": "array",
|
|
777
|
+
"items": {
|
|
778
|
+
"type": "object",
|
|
779
|
+
"properties": {
|
|
780
|
+
"id": { "type": "integer" },
|
|
781
|
+
"name": { "type": "string" }
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
"_maps_to": "GET /api/mcp/workspace"
|
|
786
|
+
},
|
|
787
|
+
|
|
788
|
+
"get_workspace": {
|
|
789
|
+
"description": "Get workspace details including its modules, states, and company info.",
|
|
790
|
+
"parameters": {
|
|
791
|
+
"id": { "type": "string", "description": "Workspace ID." }
|
|
792
|
+
},
|
|
793
|
+
"returns": {
|
|
794
|
+
"type": "object",
|
|
795
|
+
"properties": {
|
|
796
|
+
"id": { "type": "integer" },
|
|
797
|
+
"name": { "type": "string" },
|
|
798
|
+
"company": {
|
|
799
|
+
"type": "object",
|
|
800
|
+
"properties": {
|
|
801
|
+
"name": { "type": "string" },
|
|
802
|
+
"logo": { "type": "string" },
|
|
803
|
+
"phone": { "type": "string" }
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
"modules": {
|
|
807
|
+
"type": "array",
|
|
808
|
+
"items": {
|
|
809
|
+
"type": "object",
|
|
810
|
+
"properties": {
|
|
811
|
+
"id": { "type": "integer" },
|
|
812
|
+
"emoji": { "type": "string" },
|
|
813
|
+
"name": { "type": "string" },
|
|
814
|
+
"states": { "type": "array" }
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
},
|
|
818
|
+
"states": { "type": "array" },
|
|
819
|
+
"country": { "type": "string" }
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
"_maps_to": "GET /api/mcp/workspace/{id}"
|
|
823
|
+
},
|
|
824
|
+
|
|
825
|
+
"discover_modules": {
|
|
826
|
+
"description": "List every module in the active workspace. Use this first to discover what's available before calling get_module, list_entries, or submit_activity — the user may refer to modules informally ('leave requests', 'the PO module') and you need the exact module name. Returns lightweight entries with name and emoji only; call get_module for fields, states, and activities.",
|
|
827
|
+
"returns": {
|
|
828
|
+
"type": "array",
|
|
829
|
+
"items": {
|
|
830
|
+
"type": "object",
|
|
831
|
+
"properties": {
|
|
832
|
+
"name": { "type": "string" },
|
|
833
|
+
"emoji": { "type": "string" }
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
"_maps_to": "GET /api/mcp/"
|
|
838
|
+
},
|
|
839
|
+
|
|
840
|
+
"get_module": {
|
|
841
|
+
"description": "Get a module's schema: fields, states, and (with tier=extended) activities and flows. Field, state, and activity names returned here are the keys to pass into get_form, list_entries, and submit_activity — use display names, never internal IDs. Use tier=basic by default to minimize context; request tier=extended only when you need activity forms or state-transition flows.",
|
|
842
|
+
"parameters": {
|
|
843
|
+
"module": { "type": "string", "description": "Module name from discover_modules. Case-sensitive, may contain spaces (e.g. 'Leave Requests')." },
|
|
844
|
+
"tier": {
|
|
845
|
+
"type": "string",
|
|
846
|
+
"enum": ["basic", "extended"],
|
|
847
|
+
"default": "basic",
|
|
848
|
+
"description": "basic = fields + states only (smaller response, enough for reading/listing entries). extended = adds activities and flows (needed before submit_activity on a module you haven't seen before)."
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
"returns": { "$ref": "#/definitions/ModuleSchema" },
|
|
852
|
+
"_maps_to": "GET /api/mcp/{moduleName}",
|
|
853
|
+
"_notes": [
|
|
854
|
+
"Record list modules (master data, lookup tables) have no states/activities/flows — an empty states array in the response means you use standard create/edit/delete only",
|
|
855
|
+
"Field order in the response is the display order — preserve it when rendering forms to the user"
|
|
856
|
+
]
|
|
857
|
+
},
|
|
858
|
+
|
|
859
|
+
"list_entries": {
|
|
860
|
+
"description": "Query entries in a module with filters, pagination, and sorting. Filter keys are field display names (from get_module); simple values match exactly, object values use operators. Always prefer specific filters over fetching everything — responses >100KB are auto-truncated to 20 items with _truncated=true. Each entry in the response includes availableActivities, so you can chain directly into submit_activity without an extra get_form call.",
|
|
861
|
+
"parameters": {
|
|
862
|
+
"module": { "type": "string", "description": "Module name from discover_modules." },
|
|
863
|
+
"filters": {
|
|
864
|
+
"type": "object",
|
|
865
|
+
"description": "Field display names as keys. Simple value = equality ({'Priority': 'High'}). Object value = operator — text: {contains,startsWith,endsWith,excludes,is,not}; number: {min,max,above,below,between}; date: {after,before,upcoming,past,within}; boolean: true/false; user: {is,isMe,not,includes}; module: by referenced entry ID. Combine multiple keys for AND; use {or: [...]} for OR.",
|
|
866
|
+
"additionalProperties": true
|
|
867
|
+
},
|
|
868
|
+
"state": { "type": "string", "description": "Filter by state display name (e.g. 'Pending Approval'). MCP resolves to internal state ID." },
|
|
869
|
+
"search": { "type": "string", "description": "Free-text search against document ID and indexed text fields." },
|
|
870
|
+
"sortBy": { "type": "string", "description": "Field display name to sort by. Defaults to createdDate descending." },
|
|
871
|
+
"sortDirection": { "type": "string", "enum": ["asc", "desc"] },
|
|
872
|
+
"currentPage": { "type": "integer", "description": "0-based page index." },
|
|
873
|
+
"pageSize": { "type": "integer", "description": "Items per page. Default 50, max 500. Use small pages (20–50) when summarizing for the user; larger pages only when exporting or aggregating." }
|
|
874
|
+
},
|
|
875
|
+
"returns": { "$ref": "#/definitions/EntryList" },
|
|
876
|
+
"_maps_to": "POST /api/mcp/list",
|
|
877
|
+
"_notes": [
|
|
878
|
+
"Use 'me'/'myself'/'currentUser' as filter values for User fields to match the calling user without knowing their ID",
|
|
879
|
+
"Response includes totalItems and hasMore; paginate when hasMore=true rather than raising pageSize past 500",
|
|
880
|
+
"For Module reference fields, filter by the referenced entry's ID, not its display name"
|
|
881
|
+
]
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
"get_entry": {
|
|
885
|
+
"description": "Read a single entry's field values, current state, and availableActivities. Use the response's availableActivities.standard and .custom directly when deciding the next submit_activity call — do not hard-code activity names, because what's allowed depends on current state, user permissions, and workflow rules.",
|
|
886
|
+
"parameters": {
|
|
887
|
+
"module": { "type": "string", "description": "Module name from discover_modules." },
|
|
888
|
+
"entryId": { "oneOf": [{ "type": "integer" }, { "type": "string" }], "description": "Entry ID (numeric) or documentId (string like 'LR-2026-0042'). Both are accepted." }
|
|
889
|
+
},
|
|
890
|
+
"returns": { "$ref": "#/definitions/Entry" },
|
|
891
|
+
"_maps_to": "POST /api/mcp/entry",
|
|
892
|
+
"_notes": [
|
|
893
|
+
"Field values use display names as keys (e.g. 'Leave Type', not an internal ID)",
|
|
894
|
+
"File/Image fields return FileFieldValue objects; Module fields return ModuleFieldValue ({value,id}); User fields return UserFieldValue ({value,id,username}) — these shapes are round-trippable: pass the same objects back to submit_activity.input"
|
|
895
|
+
]
|
|
896
|
+
},
|
|
897
|
+
|
|
898
|
+
"get_form": {
|
|
899
|
+
"description": "Get the form definition for an activity: required fields, types, options, per-field readOnly/required constraints, the activity's confidence_threshold, and (for edit) current field values as defaults. REQUIRED STEP before submit_activity — skipping it leads to 422 validation failures that are entirely avoidable. Pass entryId for edit/custom activities so defaults are populated from the current entry state.",
|
|
900
|
+
"parameters": {
|
|
901
|
+
"module": { "type": "string", "description": "Module name from discover_modules." },
|
|
902
|
+
"activity": { "type": "string", "default": "create", "description": "Activity name. Standard: create, edit, delete, changeStatus, comment, duplicate, manage. Custom: any activity defined in the module (from get_module tier=extended)." },
|
|
903
|
+
"entryId": { "description": "Required for edit and custom activities that operate on an existing entry. Omit for create." }
|
|
904
|
+
},
|
|
905
|
+
"returns": { "$ref": "#/definitions/ActivityForm" },
|
|
906
|
+
"_maps_to": "POST /api/mcp/form"
|
|
907
|
+
},
|
|
908
|
+
|
|
909
|
+
"submit_activity": {
|
|
910
|
+
"description": "Perform an activity on an entry: create (no entryId), edit, delete, changeStatus, comment, duplicate, manage, or any custom activity from the module. ALWAYS call get_form first — it returns the required fields, valid options, per-field constraints, and the activity's confidence_threshold. Submitting without get_form risks 422 validation errors and unknown field rejections. For bulk operations, pass entryIds instead of entryId.",
|
|
911
|
+
"parameters": { "$ref": "#/definitions/ActivitySubmission" },
|
|
912
|
+
"returns": { "$ref": "#/definitions/ActivityResult" },
|
|
913
|
+
"_maps_to": "POST /api/mcp/activity",
|
|
914
|
+
"_notes": [
|
|
915
|
+
"Input shapes by field type — File/Image: { name, path } where path is from confirm_upload (default via request_upload_url+confirm_upload) or upload_file (fallback only) or an external URL. Files/Images: array of those. Module: { value, id } (id is the referenced entry ID). User: { value, id, username }. Modules/Users: arrays. Table: array of row objects keyed by sub-field display name. Other types: plain values matching FieldType.",
|
|
916
|
+
"Always include the `ai` object (reasoning, sources, model, confidence) when an AI agent is the actor — it's the audit trail the user relies on to trust automated actions",
|
|
917
|
+
"Confidence gate: if ai.confidence < the activity's confidence_threshold (from get_form), the state transition is SUPPRESSED and the response returns flagged: true. The entry is saved but stays in the original state and is flagged for human review. Do NOT retry automatically — surface the situation to the user",
|
|
918
|
+
"The response includes availableActivities — use it to decide the next legal action on the entry without another round-trip to get_entry",
|
|
919
|
+
"For Selection/Tag fields, pass option names exactly as returned by get_form.options (case-sensitive, including any emoji prefix)",
|
|
920
|
+
"State names are resolved automatically from the `state` parameter — pass the display name (e.g. 'Approved'), never an internal GUID"
|
|
921
|
+
]
|
|
922
|
+
},
|
|
923
|
+
|
|
924
|
+
"get_history": {
|
|
925
|
+
"description": "Get the chronological audit trail for an entry: create/edit/delete events, state transitions, comments, assignments, and AI audit records (reasoning, sources, model, confidence) when an `ai` object was submitted. Use this to explain how an entry reached its current state, answer 'who did what and when' questions, or surface why a transition was flagged.",
|
|
926
|
+
"parameters": {
|
|
927
|
+
"module": { "type": "string", "description": "Module name from discover_modules." },
|
|
928
|
+
"entryId": { "oneOf": [{ "type": "integer" }, { "type": "string" }], "description": "Entry ID or documentId." },
|
|
929
|
+
"page": { "type": "integer", "default": 0, "description": "0-based page index. 50 events per page." }
|
|
930
|
+
},
|
|
931
|
+
"returns": { "$ref": "#/definitions/EntryHistory" },
|
|
932
|
+
"_maps_to": "POST /api/mcp/history",
|
|
933
|
+
"_notes": [
|
|
934
|
+
"History entries with type='intention' indicate a confidence-gated action — the AI tried to perform an activity but ai.confidence was below confidence_threshold, so the state transition was suppressed and the entry was flagged for human review",
|
|
935
|
+
"Field-level changes are in the 'changes' object (before/after values) on edit events — use to answer 'what changed between X and Y'",
|
|
936
|
+
"AI audit context (ai.reasoning, ai.sources, ai.confidence) is preserved verbatim from what was submitted — useful for post-hoc review of automated decisions"
|
|
937
|
+
]
|
|
938
|
+
},
|
|
939
|
+
|
|
940
|
+
"upload_file": {
|
|
941
|
+
"description": "FALLBACK ONLY — do NOT use this by default. Always use request_upload_url + confirm_upload first; call this tool only after the presigned flow has actually failed. Uploads a file to S3 via multipart/form-data. Returns a /s/ path usable as a File/Image field value in submit_activity.",
|
|
942
|
+
"parameters": {
|
|
943
|
+
"required": ["module", "file"],
|
|
944
|
+
"module": { "type": "string", "description": "Module name. Required — scopes the file to the module's storage folder." },
|
|
945
|
+
"file": { "type": "string", "format": "binary", "description": "The file to upload. Must be sent as multipart/form-data." }
|
|
946
|
+
},
|
|
947
|
+
"returns": { "$ref": "#/definitions/FileUploadResult" },
|
|
948
|
+
"_maps_to": "POST /api/mcp/upload",
|
|
949
|
+
"_notes": [
|
|
950
|
+
"Fallback path — only use after request_upload_url + confirm_upload has failed",
|
|
951
|
+
"Request must be multipart/form-data — no other content types are supported",
|
|
952
|
+
"Required 'module' form field scopes the file to the module's S3 folder",
|
|
953
|
+
"Maximum file size: 50MB",
|
|
954
|
+
"Blocked extensions: .exe, .bat, .cmd, .dll, .msi, and other executable types",
|
|
955
|
+
"Filenames are sanitized (path traversal characters stripped)"
|
|
956
|
+
]
|
|
957
|
+
},
|
|
958
|
+
|
|
959
|
+
"request_upload_url": {
|
|
960
|
+
"description": "DEFAULT upload path — ALWAYS use this for every file upload (any size, up to 500 MB). Only fall back to upload_file if this flow actually fails. Returns an uploadUrl for the client to PUT the file directly to S3, plus a path to use in File/Image fields. After uploading, call confirm_upload to finalize.",
|
|
961
|
+
"parameters": {
|
|
962
|
+
"required": ["module", "fileName", "fileSize"],
|
|
963
|
+
"module": { "type": "string", "description": "Module name. Required — scopes the file to the module's storage folder." },
|
|
964
|
+
"fileName": { "type": "string", "description": "Original filename including extension." },
|
|
965
|
+
"contentType": { "type": "string", "description": "MIME type of the file. Defaults to application/octet-stream." },
|
|
966
|
+
"fileSize": { "type": "integer", "description": "File size in bytes. Must be > 0 and ≤ 500 MB.", "minimum": 1, "maximum": 524288000 }
|
|
967
|
+
},
|
|
968
|
+
"returns": { "$ref": "#/definitions/PresignedUploadResult" },
|
|
969
|
+
"_maps_to": "POST /api/mcp/request-upload-url",
|
|
970
|
+
"_notes": [
|
|
971
|
+
"Default for every file upload regardless of size — always attempt this flow first; only fall back to upload_file if this actually fails",
|
|
972
|
+
"IMPORTANT: The PUT request Content-Type header MUST exactly match the contentType from this response. S3 presigned URLs sign headers — a mismatch causes 403 SignatureDoesNotMatch with no useful error message",
|
|
973
|
+
"The uploadUrl expires in 1 hour (expiresIn seconds). If the PUT fails with 403 after expiry, call request_upload_url again — presigned URLs cannot be renewed",
|
|
974
|
+
"Maximum file size: 500 MB",
|
|
975
|
+
"Blocked extensions: .exe, .bat, .cmd, .dll, .msi, and other executable types",
|
|
976
|
+
"Filenames are sanitized (path traversal characters stripped)",
|
|
977
|
+
"After the PUT upload completes, call confirm_upload with the s3Key from this response",
|
|
978
|
+
"Server should have an S3 lifecycle policy to expire unconfirmed uploads (e.g. 24h) — if a client crashes between PUT and confirm_upload, the S3 object is orphaned",
|
|
979
|
+
"Worked example: 1. request_upload_url({ module, fileName, fileSize, contentType }) → { uploadUrl, s3Key, path, filename } 2. PUT uploadUrl with body=<bytes>, headers Content-Type=<contentType> 3. confirm_upload({ s3Key }) → { path, filename, mimeType, size } 4. submit_activity({ input: { \"Attachment\": { name: filename, path } } })"
|
|
980
|
+
]
|
|
981
|
+
},
|
|
982
|
+
|
|
983
|
+
"confirm_upload": {
|
|
984
|
+
"description": "Confirm that a presigned upload completed. Verifies the file exists in S3, reads its metadata, and tracks workspace storage. Only s3Key is required — filename, size, and content type are resolved from S3.",
|
|
985
|
+
"parameters": {
|
|
986
|
+
"required": ["s3Key"],
|
|
987
|
+
"s3Key": { "type": "string", "description": "The s3Key returned from request_upload_url." }
|
|
988
|
+
},
|
|
989
|
+
"returns": { "$ref": "#/definitions/FileUploadResult" },
|
|
990
|
+
"_maps_to": "POST /api/mcp/confirm-upload",
|
|
991
|
+
"_notes": [
|
|
992
|
+
"Must be called after the file has been uploaded to the presigned URL",
|
|
993
|
+
"Returns 400 if the file is not found in S3 — ensure the PUT upload completed before calling",
|
|
994
|
+
"If the presigned URL expired (403 from S3), call request_upload_url again before retrying",
|
|
995
|
+
"Response format matches upload_file — path can be used identically in File/Image fields"
|
|
996
|
+
]
|
|
997
|
+
},
|
|
998
|
+
|
|
999
|
+
"download_file": {
|
|
1000
|
+
"description": "Download a file by module name. AI agents construct the download URL by prepending /api/mcp/download/{moduleName} to a /s/{shortId}/{fileName} path.",
|
|
1001
|
+
"parameters": {
|
|
1002
|
+
"moduleName": { "type": "string", "description": "Module name (resolved to vectorId internally)." },
|
|
1003
|
+
"guid": { "type": "string", "description": "Short ID from the file URL." },
|
|
1004
|
+
"fileName": { "type": "string", "description": "Original filename." }
|
|
1005
|
+
},
|
|
1006
|
+
"returns": { "type": "string", "description": "Redirects to a pre-signed S3 URL (1hr TTL) or streams the file directly for Office applications." },
|
|
1007
|
+
"_maps_to": "GET /api/mcp/download/{moduleName}/s/{guid}/{fileName}",
|
|
1008
|
+
"_notes": [
|
|
1009
|
+
"Returns 404 with MCP error format if file not found in S3",
|
|
1010
|
+
"Office user-agents receive direct stream; all others get a 302 redirect to a pre-signed URL"
|
|
1011
|
+
]
|
|
1012
|
+
},
|
|
1013
|
+
|
|
1014
|
+
"get_module_schema": {
|
|
1015
|
+
"description": "Get an existing module definition as a ModuleSchema with stable IDs. The output is round-trippable — modify and send back via update_module.",
|
|
1016
|
+
"parameters": {
|
|
1017
|
+
"module": { "type": "string", "description": "Module name or numeric ID." }
|
|
1018
|
+
},
|
|
1019
|
+
"returns": { "$ref": "#/definitions/ModuleSchema" },
|
|
1020
|
+
"_maps_to": "GET /api/configure/{moduleName}"
|
|
1021
|
+
},
|
|
1022
|
+
|
|
1023
|
+
"create_module": {
|
|
1024
|
+
"description": "Create a new module from a ModuleSchema definition. Returns the created module as a ModuleSchema with generated IDs.",
|
|
1025
|
+
"parameters": { "$ref": "#/definitions/ModuleSchema" },
|
|
1026
|
+
"returns": {
|
|
1027
|
+
"allOf": [
|
|
1028
|
+
{ "$ref": "#/definitions/ModuleSchema" },
|
|
1029
|
+
{
|
|
1030
|
+
"type": "object",
|
|
1031
|
+
"properties": {
|
|
1032
|
+
"updatedDate": { "type": "string", "format": "date-time" },
|
|
1033
|
+
"version": { "type": "string" },
|
|
1034
|
+
"summary": {
|
|
1035
|
+
"type": "object",
|
|
1036
|
+
"description": "Summary of what was created.",
|
|
1037
|
+
"properties": {
|
|
1038
|
+
"fields": { "type": "integer" },
|
|
1039
|
+
"states": { "type": "array", "items": { "type": "string" } },
|
|
1040
|
+
"activities": { "type": "array", "items": { "type": "string" } },
|
|
1041
|
+
"flows": { "type": "integer" }
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
]
|
|
1047
|
+
},
|
|
1048
|
+
"_maps_to": "POST /api/configure"
|
|
1049
|
+
},
|
|
1050
|
+
|
|
1051
|
+
"update_module": {
|
|
1052
|
+
"description": "Update an existing module. Send a ModuleSchema with id. Returns the full updated ModuleSchema.",
|
|
1053
|
+
"parameters": { "$ref": "#/definitions/ModuleSchema" },
|
|
1054
|
+
"returns": {
|
|
1055
|
+
"allOf": [
|
|
1056
|
+
{ "$ref": "#/definitions/ModuleSchema" },
|
|
1057
|
+
{
|
|
1058
|
+
"type": "object",
|
|
1059
|
+
"properties": {
|
|
1060
|
+
"updatedDate": { "type": "string", "format": "date-time" },
|
|
1061
|
+
"version": { "type": "string" },
|
|
1062
|
+
"changes": {
|
|
1063
|
+
"type": "object",
|
|
1064
|
+
"description": "What the update changed.",
|
|
1065
|
+
"properties": {
|
|
1066
|
+
"renamed": { "type": "array", "items": { "type": "object" } },
|
|
1067
|
+
"added": { "type": "array", "items": { "type": "object" } },
|
|
1068
|
+
"updated": { "type": "array", "items": { "type": "string" } }
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
]
|
|
1074
|
+
},
|
|
1075
|
+
"_maps_to": "PUT /api/configure"
|
|
1076
|
+
}
|
|
1077
|
+
},
|
|
1078
|
+
|
|
1079
|
+
"workflow_guide": {
|
|
1080
|
+
"_description": "Recommended sequence for AI agents interacting through INISTATE.",
|
|
1081
|
+
"steps": [
|
|
1082
|
+
"1. list_workspaces(?search=) → find accessible workspaces (id and name)",
|
|
1083
|
+
"2. get_workspace(id) → get workspace details with modules and states",
|
|
1084
|
+
"3. discover_modules() → find available module names",
|
|
1085
|
+
"4. get_module(module, tier='basic') → understand fields and states",
|
|
1086
|
+
"5. get_module(module, tier='extended') → understand activities (only when needed)",
|
|
1087
|
+
"6. get_form(module, activity) → get required fields, types, options, defaults, and confidence_threshold before submitting",
|
|
1088
|
+
"7. request_upload_url(module, fileName, fileSize, contentType) → PUT bytes to uploadUrl → confirm_upload(s3Key) → returns /s/ path. ALWAYS use this flow for File/Image fields. Only fall back to upload_file(module, file) if this flow fails.",
|
|
1089
|
+
"8. submit_activity(module, activity, input) → create/edit/delete/custom operations. Use /s/ paths from confirm_upload (or upload_file fallback) for File/Image fields.",
|
|
1090
|
+
"9. list_entries(module, filters) → query and browse entries",
|
|
1091
|
+
"10. get_entry(module, entryId) → read a specific entry",
|
|
1092
|
+
"11. get_history(module, entryId) → audit trail and comments",
|
|
1093
|
+
"12. download_file(moduleName, guid, fileName) → download a file. Construct URL: /api/mcp/download/{moduleName}/s/{guid}/{fileName} from any /s/{guid}/{fileName} value",
|
|
1094
|
+
"--- Module Configuration (via /api/configure/ endpoints, uses INISTATE ModuleSchema format) ---",
|
|
1095
|
+
"13. get_module_schema(moduleName) → GET /api/configure/{moduleName} — get the module's current definition as ModuleSchema with stable IDs. Round-trippable: modify and send back via update_module.",
|
|
1096
|
+
"14. create_module(ModuleSchema) → POST /api/configure — create a new module using the ModuleSchema definition from this schema",
|
|
1097
|
+
"15. update_module(ModuleSchema) → PUT /api/configure — update an existing module. Use get_module_schema() first, modify, then send back."
|
|
1098
|
+
],
|
|
1099
|
+
"key_rules": [
|
|
1100
|
+
"All input/output keys use field DISPLAY NAMES, never internal IDs",
|
|
1101
|
+
"State references use state NAMES, never GUIDs",
|
|
1102
|
+
"Activity references use activity NAMES, resolved to IDs internally",
|
|
1103
|
+
"Always call get_form() before submit_activity() to discover required fields and valid options",
|
|
1104
|
+
"Use tier='basic' by default; only request 'extended' when activity details are needed",
|
|
1105
|
+
"Not all modules have workflows — record list modules (master data, lookup tables) have no states, activities, or flows. Use standard create/edit/delete activities directly.",
|
|
1106
|
+
"File/Image fields use object values, not plain strings. Retrieval returns { name, path }. Submission accepts { name, path } where path is from request_upload_url()+confirm_upload() (always the default flow; fall back to upload_file() only if it fails) or an external URL. Files/Images (plural) use arrays of these objects. To download, prepend /api/mcp/download/{moduleName} to any /s/ path.",
|
|
1107
|
+
"Module/User fields use object values. Retrieval returns { value, id } for Module and { value, id, username } for User. Submission accepts the same shape — the MCP layer decomposes these into internal storage format. Modules/Users (plural) use arrays of these objects."
|
|
1108
|
+
],
|
|
1109
|
+
"module_types": {
|
|
1110
|
+
"_description": "Modules fall into two categories based on their purpose.",
|
|
1111
|
+
"workflow_module": {
|
|
1112
|
+
"description": "Modules with states, custom activities, and flows that define a process lifecycle (e.g. Leave Request, Purchase Order, Support Ticket). Entries move through states via activities and transition rules.",
|
|
1113
|
+
"has_states": true,
|
|
1114
|
+
"has_activities": true,
|
|
1115
|
+
"has_flows": true
|
|
1116
|
+
},
|
|
1117
|
+
"record_list_module": {
|
|
1118
|
+
"description": "Modules used purely to maintain a list of entries — master data, lookup tables, registries, catalogs (e.g. Employee Directory, Department List, Product Catalog, Holiday Calendar). No workflow, no state transitions, no custom activities. Entries are managed with standard create/edit/delete operations only.",
|
|
1119
|
+
"has_states": false,
|
|
1120
|
+
"has_activities": false,
|
|
1121
|
+
"has_flows": false,
|
|
1122
|
+
"examples": [
|
|
1123
|
+
"Employee Directory — master list of employees and their details",
|
|
1124
|
+
"Department List — organizational departments for reference",
|
|
1125
|
+
"Product Catalog — items available for selection in other modules",
|
|
1126
|
+
"Holiday Calendar — list of holiday dates used by leave/attendance modules",
|
|
1127
|
+
"Cost Centers — finance lookup table referenced by expense and budget modules"
|
|
1128
|
+
]
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
|
|
1132
|
+
"confidence_gate": {
|
|
1133
|
+
"_description": "When an AI agent submits an activity with ai.confidence below the activity's confidence_threshold:",
|
|
1134
|
+
"behavior": [
|
|
1135
|
+
"State transition is suppressed — the entry stays in its current state",
|
|
1136
|
+
"The history event is recorded with type 'intention' instead of the normal activity type",
|
|
1137
|
+
"The entry's collaboration flags are set to WithIntention + LastIntention",
|
|
1138
|
+
"The response includes flagged: true so the AI agent knows the action requires human review",
|
|
1139
|
+
"Entries flagged for intervention can be filtered using the collaboration filter: 'intention' or 'lastIntention'",
|
|
1140
|
+
"get_form() returns confidence_threshold when configured, so agents can check the threshold before submitting"
|
|
1141
|
+
]
|
|
1142
|
+
},
|
|
1143
|
+
"ai_audit_trail": {
|
|
1144
|
+
"_description": "AI agent traceability in history events:",
|
|
1145
|
+
"behavior": [
|
|
1146
|
+
"Every history event submitted by an AI agent includes the full 'ai' object (reasoning, sources, model, model_version, prompt_hash, confidence)",
|
|
1147
|
+
"get_history() returns the ai context on each event, enabling full chain-of-reasoning reconstruction",
|
|
1148
|
+
"The ai object is only present on events that were submitted with AI context — human actions have no ai field"
|
|
1149
|
+
]
|
|
1150
|
+
},
|
|
1151
|
+
"state_color_system": {
|
|
1152
|
+
"_description": "Color assignment rules for states based on attention level and sentiment. Use hex codes.",
|
|
1153
|
+
"palette": {
|
|
1154
|
+
"#5A6070": "Grey — not started, idle, queued, no action expected",
|
|
1155
|
+
"#2968A8": "Blue — waiting for an actor to take next action, no urgency",
|
|
1156
|
+
"#2A7B50": "Green — work is actively being executed by an actor right now",
|
|
1157
|
+
"#A07828": "Amber — deadline approaching, condition flagged, action needed soon",
|
|
1158
|
+
"#C0392B": "Red — SLA breached, escalation required, process stuck",
|
|
1159
|
+
"#6B4D91": "Purple — blocked by external dependency outside this workflow",
|
|
1160
|
+
"#1E6B45": "Dark green — terminal success (approved, completed, closed)",
|
|
1161
|
+
"#8B2D2D": "Dark red — terminal failure (rejected, cancelled, failed)"
|
|
1162
|
+
},
|
|
1163
|
+
"_note": "All colors are designed for white text on colored background (WCAG AA 4.5:1+ contrast).",
|
|
1164
|
+
"decision_order": [
|
|
1165
|
+
"1. Terminal success → #1E6B45",
|
|
1166
|
+
"2. Terminal failure/rejection/cancellation → #8B2D2D",
|
|
1167
|
+
"3. Active work being executed → #2A7B50",
|
|
1168
|
+
"4. SLA breached or escalation required → #C0392B",
|
|
1169
|
+
"5. Deadline approaching or flagged → #A07828",
|
|
1170
|
+
"6. Blocked by external dependency → #6B4D91",
|
|
1171
|
+
"7. Waiting for next action, no urgency → #2968A8",
|
|
1172
|
+
"8. Not started, queued, idle → #5A6070"
|
|
1173
|
+
],
|
|
1174
|
+
"rules": [
|
|
1175
|
+
"Never use #2A7B50 (green) for states where no actor is actively working — use #2968A8 (blue) for approved/completed states awaiting next action",
|
|
1176
|
+
"Terminal states must always be #1E6B45 or #8B2D2D — never grey, blue, or green",
|
|
1177
|
+
"Never use #C0392B (red) unless a real SLA breach or escalation condition exists",
|
|
1178
|
+
"Only one state in a linear workflow should typically be green — the active work state",
|
|
1179
|
+
"When unsure, default to #2968A8 (blue) — it is the safest general-purpose color",
|
|
1180
|
+
"In parallel/branching workflows, multiple states may use #2A7B50 (green) if each represents genuinely concurrent active work by different actors"
|
|
1181
|
+
],
|
|
1182
|
+
"default_when_unsure": "#2968A8",
|
|
1183
|
+
"strict_palette": "Only use the 8 hex codes listed in the palette. Never generate custom hex values.",
|
|
1184
|
+
"keyword_hints": {
|
|
1185
|
+
"_description": "When a state name contains these keywords, use the mapped color. Always check terminal rules first — a state named 'Completed' is terminal success even if it contains 'complete' from the green list.",
|
|
1186
|
+
"#5A6070": ["draft", "new", "open", "backlog", "queued", "not started", "inactive", "parked", "unassigned"],
|
|
1187
|
+
"#2968A8": ["pending", "submitted", "awaiting", "assigned", "ready", "scheduled", "planned", "under review", "to do"],
|
|
1188
|
+
"#2A7B50": ["in progress", "processing", "working", "executing", "building", "running", "reviewing", "implementing", "testing"],
|
|
1189
|
+
"#A07828": ["due soon", "at risk", "warning", "expiring", "needs attention", "follow up", "reminder"],
|
|
1190
|
+
"#C0392B": ["overdue", "escalated", "breached", "stuck", "critical", "urgent", "sla"],
|
|
1191
|
+
"#6B4D91": ["blocked", "waiting on", "on hold", "external", "vendor", "third party", "dependency"],
|
|
1192
|
+
"#1E6B45": ["approved", "completed", "done", "resolved", "closed", "delivered", "passed", "accepted", "verified", "fulfilled", "signed off"],
|
|
1193
|
+
"#8B2D2D": ["rejected", "cancelled", "failed", "denied", "expired", "voided", "abandoned", "withdrawn", "terminated", "declined"]
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|