motia 0.7.2-beta.135-745094 → 0.7.3-beta.136

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.
Files changed (145) hide show
  1. package/dist/cjs/create/templates/generate.js +2 -2
  2. package/dist/cjs/create/templates/generate.ts +2 -2
  3. package/dist/cjs/create/templates/nodejs/services/pet-store.ts.txt +29 -0
  4. package/dist/cjs/create/templates/nodejs/steps/{petstore/api.step.ts-features.json.txt → api.step.ts-features.json.txt} +9 -9
  5. package/dist/{esm/create/templates/nodejs/steps/petstore → cjs/create/templates/nodejs/steps}/api.step.ts.txt +2 -1
  6. package/dist/cjs/create/templates/nodejs/steps/{petstore/process-food-order.step.ts.txt → process-food-order.step.ts.txt} +1 -1
  7. package/dist/cjs/cursor-rules/dot-files/.claude/CLAUDE.md +467 -0
  8. package/dist/cjs/cursor-rules/dot-files/.claude/README.md +97 -0
  9. package/dist/cjs/cursor-rules/dot-files/.claude/agents/code-reviewer.md +153 -0
  10. package/dist/cjs/cursor-rules/dot-files/.claude/agents/debugger.md +259 -0
  11. package/dist/cjs/cursor-rules/dot-files/.claude/agents/test-runner.md +268 -0
  12. package/dist/cjs/cursor-rules/dot-files/.claude/commands/add-authentication.md +491 -0
  13. package/dist/cjs/cursor-rules/dot-files/.claude/commands/ai-ml-patterns.md +748 -0
  14. package/dist/cjs/cursor-rules/dot-files/.claude/commands/authentication.md +515 -0
  15. package/dist/cjs/cursor-rules/dot-files/.claude/commands/backend-types.md +719 -0
  16. package/dist/cjs/cursor-rules/dot-files/.claude/commands/build-api.md +407 -0
  17. package/dist/cjs/cursor-rules/dot-files/.claude/commands/claude-workflows.md +1032 -0
  18. package/dist/cjs/cursor-rules/dot-files/.claude/commands/complete-backend.md +345 -0
  19. package/dist/cjs/cursor-rules/dot-files/.claude/commands/create-api.md +96 -0
  20. package/dist/cjs/cursor-rules/dot-files/.claude/commands/data-processing.md +977 -0
  21. package/dist/cjs/cursor-rules/dot-files/.claude/commands/integrate-ai.md +852 -0
  22. package/dist/cjs/cursor-rules/dot-files/.claude/commands/javascript-patterns.md +678 -0
  23. package/dist/cjs/cursor-rules/dot-files/.claude/commands/multi-language-workflow.md +756 -0
  24. package/dist/cjs/cursor-rules/dot-files/.claude/commands/multi-language.md +141 -0
  25. package/dist/cjs/cursor-rules/dot-files/.claude/commands/process-background-jobs.md +587 -0
  26. package/dist/cjs/cursor-rules/dot-files/.claude/commands/process-events.md +89 -0
  27. package/dist/cjs/cursor-rules/dot-files/.claude/hooks/pre-commit.sh +84 -0
  28. package/dist/cjs/cursor-rules/dot-files/.claude/settings.json +37 -0
  29. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/ai-agent-patterns.mdc +725 -0
  30. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/api-design-patterns.mdc +740 -0
  31. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/api-steps.mdc +230 -0
  32. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/architecture.mdc +189 -0
  33. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/authentication-patterns.mdc +620 -0
  34. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/background-job-patterns.mdc +628 -0
  35. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/complete-application-patterns.mdc +433 -0
  36. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/complete-backend-generator.mdc +415 -0
  37. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/cron-steps.mdc +257 -0
  38. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/event-steps.mdc +504 -0
  39. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/instructions.mdc +15 -0
  40. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/multi-language-workflows.mdc +1059 -0
  41. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/noop-steps.mdc +57 -0
  42. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/production-deployment.mdc +668 -0
  43. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/realtime-streaming.mdc +656 -0
  44. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/state-management.mdc +371 -0
  45. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/steps.mdc +373 -0
  46. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/testing.mdc +329 -0
  47. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/typescript.mdc +409 -0
  48. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/ui-steps.mdc +429 -0
  49. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/workflow-patterns.mdc +938 -0
  50. package/dist/cjs/cursor-rules/dot-files/AGENTS.md +397 -0
  51. package/dist/cjs/cursor-rules/dot-files/README.md +58 -0
  52. package/dist/esm/create/templates/generate.js +2 -2
  53. package/dist/esm/create/templates/generate.ts +2 -2
  54. package/dist/esm/create/templates/nodejs/services/pet-store.ts.txt +29 -0
  55. package/dist/esm/create/templates/nodejs/steps/{petstore/api.step.ts-features.json.txt → api.step.ts-features.json.txt} +9 -9
  56. package/dist/{cjs/create/templates/nodejs/steps/petstore → esm/create/templates/nodejs/steps}/api.step.ts.txt +2 -1
  57. package/dist/esm/create/templates/nodejs/steps/{petstore/process-food-order.step.ts.txt → process-food-order.step.ts.txt} +1 -1
  58. package/dist/esm/cursor-rules/dot-files/.claude/CLAUDE.md +467 -0
  59. package/dist/esm/cursor-rules/dot-files/.claude/README.md +97 -0
  60. package/dist/esm/cursor-rules/dot-files/.claude/agents/code-reviewer.md +153 -0
  61. package/dist/esm/cursor-rules/dot-files/.claude/agents/debugger.md +259 -0
  62. package/dist/esm/cursor-rules/dot-files/.claude/agents/test-runner.md +268 -0
  63. package/dist/esm/cursor-rules/dot-files/.claude/commands/add-authentication.md +491 -0
  64. package/dist/esm/cursor-rules/dot-files/.claude/commands/ai-ml-patterns.md +748 -0
  65. package/dist/esm/cursor-rules/dot-files/.claude/commands/authentication.md +515 -0
  66. package/dist/esm/cursor-rules/dot-files/.claude/commands/backend-types.md +719 -0
  67. package/dist/esm/cursor-rules/dot-files/.claude/commands/build-api.md +407 -0
  68. package/dist/esm/cursor-rules/dot-files/.claude/commands/claude-workflows.md +1032 -0
  69. package/dist/esm/cursor-rules/dot-files/.claude/commands/complete-backend.md +345 -0
  70. package/dist/esm/cursor-rules/dot-files/.claude/commands/create-api.md +96 -0
  71. package/dist/esm/cursor-rules/dot-files/.claude/commands/data-processing.md +977 -0
  72. package/dist/esm/cursor-rules/dot-files/.claude/commands/integrate-ai.md +852 -0
  73. package/dist/esm/cursor-rules/dot-files/.claude/commands/javascript-patterns.md +678 -0
  74. package/dist/esm/cursor-rules/dot-files/.claude/commands/multi-language-workflow.md +756 -0
  75. package/dist/esm/cursor-rules/dot-files/.claude/commands/multi-language.md +141 -0
  76. package/dist/esm/cursor-rules/dot-files/.claude/commands/process-background-jobs.md +587 -0
  77. package/dist/esm/cursor-rules/dot-files/.claude/commands/process-events.md +89 -0
  78. package/dist/esm/cursor-rules/dot-files/.claude/hooks/pre-commit.sh +84 -0
  79. package/dist/esm/cursor-rules/dot-files/.claude/settings.json +37 -0
  80. package/dist/esm/cursor-rules/dot-files/.cursor/rules/ai-agent-patterns.mdc +725 -0
  81. package/dist/esm/cursor-rules/dot-files/.cursor/rules/api-design-patterns.mdc +740 -0
  82. package/dist/esm/cursor-rules/dot-files/.cursor/rules/api-steps.mdc +230 -0
  83. package/dist/esm/cursor-rules/dot-files/.cursor/rules/architecture.mdc +189 -0
  84. package/dist/esm/cursor-rules/dot-files/.cursor/rules/authentication-patterns.mdc +620 -0
  85. package/dist/esm/cursor-rules/dot-files/.cursor/rules/background-job-patterns.mdc +628 -0
  86. package/dist/esm/cursor-rules/dot-files/.cursor/rules/complete-application-patterns.mdc +433 -0
  87. package/dist/esm/cursor-rules/dot-files/.cursor/rules/complete-backend-generator.mdc +415 -0
  88. package/dist/esm/cursor-rules/dot-files/.cursor/rules/cron-steps.mdc +257 -0
  89. package/dist/esm/cursor-rules/dot-files/.cursor/rules/event-steps.mdc +504 -0
  90. package/dist/esm/cursor-rules/dot-files/.cursor/rules/instructions.mdc +15 -0
  91. package/dist/esm/cursor-rules/dot-files/.cursor/rules/multi-language-workflows.mdc +1059 -0
  92. package/dist/esm/cursor-rules/dot-files/.cursor/rules/noop-steps.mdc +57 -0
  93. package/dist/esm/cursor-rules/dot-files/.cursor/rules/production-deployment.mdc +668 -0
  94. package/dist/esm/cursor-rules/dot-files/.cursor/rules/realtime-streaming.mdc +656 -0
  95. package/dist/esm/cursor-rules/dot-files/.cursor/rules/state-management.mdc +371 -0
  96. package/dist/esm/cursor-rules/dot-files/.cursor/rules/steps.mdc +373 -0
  97. package/dist/esm/cursor-rules/dot-files/.cursor/rules/testing.mdc +329 -0
  98. package/dist/esm/cursor-rules/dot-files/.cursor/rules/typescript.mdc +409 -0
  99. package/dist/esm/cursor-rules/dot-files/.cursor/rules/ui-steps.mdc +429 -0
  100. package/dist/esm/cursor-rules/dot-files/.cursor/rules/workflow-patterns.mdc +938 -0
  101. package/dist/esm/cursor-rules/dot-files/AGENTS.md +397 -0
  102. package/dist/esm/cursor-rules/dot-files/README.md +58 -0
  103. package/package.json +4 -4
  104. package/dist/cjs/create/templates/nodejs/.cursor/architecture/database/database-migration.mdc +0 -49
  105. package/dist/cjs/create/templates/nodejs/.cursor/architecture/database/database.mdc +0 -83
  106. package/dist/cjs/create/templates/nodejs/src/services/pet-store/create-order.ts.txt +0 -15
  107. package/dist/cjs/create/templates/nodejs/src/services/pet-store/create-pet.ts.txt +0 -14
  108. package/dist/cjs/create/templates/nodejs/src/services/pet-store/index.ts.txt +0 -9
  109. package/dist/cjs/cursor-rules/dot-files/.cursor/architecture/architecture.mdc +0 -96
  110. package/dist/cjs/cursor-rules/dot-files/.cursor/architecture/error-handling.mdc +0 -122
  111. package/dist/cjs/cursor-rules/dot-files/.cursor/index.mdc +0 -26
  112. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/api-steps.mdc +0 -317
  113. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/cron-steps.mdc +0 -144
  114. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/event-steps.mdc +0 -157
  115. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/middlewares.mdc +0 -122
  116. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/realtime-streaming.mdc +0 -231
  117. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/state-management.mdc +0 -73
  118. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/ui-steps.mdc +0 -76
  119. package/dist/cjs/cursor-rules/dot-files/.cursor/rules/motia/virtual-steps.mdc +0 -172
  120. package/dist/esm/create/templates/nodejs/.cursor/architecture/database/database-migration.mdc +0 -49
  121. package/dist/esm/create/templates/nodejs/.cursor/architecture/database/database.mdc +0 -83
  122. package/dist/esm/create/templates/nodejs/src/services/pet-store/create-order.ts.txt +0 -15
  123. package/dist/esm/create/templates/nodejs/src/services/pet-store/create-pet.ts.txt +0 -14
  124. package/dist/esm/create/templates/nodejs/src/services/pet-store/index.ts.txt +0 -9
  125. package/dist/esm/cursor-rules/dot-files/.cursor/architecture/architecture.mdc +0 -96
  126. package/dist/esm/cursor-rules/dot-files/.cursor/architecture/error-handling.mdc +0 -122
  127. package/dist/esm/cursor-rules/dot-files/.cursor/index.mdc +0 -26
  128. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/api-steps.mdc +0 -317
  129. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/cron-steps.mdc +0 -144
  130. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/event-steps.mdc +0 -157
  131. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/middlewares.mdc +0 -122
  132. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/realtime-streaming.mdc +0 -231
  133. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/state-management.mdc +0 -73
  134. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/ui-steps.mdc +0 -76
  135. package/dist/esm/cursor-rules/dot-files/.cursor/rules/motia/virtual-steps.mdc +0 -172
  136. /package/dist/cjs/create/templates/nodejs/{src/services/pet-store → services}/types.ts.txt +0 -0
  137. /package/dist/cjs/create/templates/nodejs/steps/{petstore/notification.step.ts.txt → notification.step.ts.txt} +0 -0
  138. /package/dist/cjs/create/templates/nodejs/steps/{petstore/process-food-order.step.ts-features.json.txt → process-food-order.step.ts-features.json.txt} +0 -0
  139. /package/dist/cjs/create/templates/nodejs/steps/{petstore/state-audit-cron.step.ts-features.json.txt → state-audit-cron.step.ts-features.json.txt} +0 -0
  140. /package/dist/cjs/create/templates/nodejs/steps/{petstore/state-audit-cron.step.ts.txt → state-audit-cron.step.ts.txt} +0 -0
  141. /package/dist/esm/create/templates/nodejs/{src/services/pet-store → services}/types.ts.txt +0 -0
  142. /package/dist/esm/create/templates/nodejs/steps/{petstore/notification.step.ts.txt → notification.step.ts.txt} +0 -0
  143. /package/dist/esm/create/templates/nodejs/steps/{petstore/process-food-order.step.ts-features.json.txt → process-food-order.step.ts-features.json.txt} +0 -0
  144. /package/dist/esm/create/templates/nodejs/steps/{petstore/state-audit-cron.step.ts-features.json.txt → state-audit-cron.step.ts-features.json.txt} +0 -0
  145. /package/dist/esm/create/templates/nodejs/steps/{petstore/state-audit-cron.step.ts.txt → state-audit-cron.step.ts.txt} +0 -0
@@ -40,7 +40,7 @@ const glob_1 = require("glob");
40
40
  const generateTemplateSteps = (templateFolder) => {
41
41
  return async (rootDir, context) => {
42
42
  const templatePath = path.join(__dirname, templateFolder);
43
- const files = (0, glob_1.globSync)('**/*', { absolute: false, cwd: templatePath, dot: true });
43
+ const files = (0, glob_1.globSync)('**/*', { absolute: false, cwd: templatePath });
44
44
  try {
45
45
  for (const fileName of files) {
46
46
  const filePath = path.join(templatePath, fileName);
@@ -54,7 +54,7 @@ const generateTemplateSteps = (templateFolder) => {
54
54
  (0, fs_1.mkdirSync)(targetDir, { recursive: true });
55
55
  }
56
56
  if ((0, fs_1.statSync)(filePath).isDirectory()) {
57
- const folderPath = filePath.replace(templatePath, '');
57
+ const folderPath = path.basename(filePath);
58
58
  (0, fs_1.mkdirSync)(path.join(rootDir, folderPath), { recursive: true });
59
59
  continue;
60
60
  }
@@ -8,7 +8,7 @@ export type Generator = (rootDir: string, context: CliContext) => Promise<void>
8
8
  export const generateTemplateSteps = (templateFolder: string): Generator => {
9
9
  return async (rootDir: string, context: CliContext): Promise<void> => {
10
10
  const templatePath = path.join(__dirname, templateFolder)
11
- const files = globSync('**/*', { absolute: false, cwd: templatePath, dot: true })
11
+ const files = globSync('**/*', { absolute: false, cwd: templatePath })
12
12
 
13
13
  try {
14
14
  for (const fileName of files) {
@@ -24,7 +24,7 @@ export const generateTemplateSteps = (templateFolder: string): Generator => {
24
24
  }
25
25
 
26
26
  if (statSync(filePath).isDirectory()) {
27
- const folderPath = filePath.replace(templatePath, '')
27
+ const folderPath = path.basename(filePath)
28
28
  mkdirSync(path.join(rootDir, folderPath), { recursive: true })
29
29
  continue
30
30
  }
@@ -0,0 +1,29 @@
1
+ import { Order, Pet } from './types'
2
+
3
+ export const petStoreService = {
4
+ createPet: async (pet: Omit<Pet, 'id'>): Promise<Pet> => {
5
+ const response = await fetch('https://petstore.swagger.io/v2/pet', {
6
+ method: 'POST',
7
+ body: JSON.stringify({
8
+ name: pet?.name ?? '',
9
+ photoUrls: [pet?.photoUrl ?? ''],
10
+ status: 'available',
11
+ }),
12
+ headers: { 'Content-Type': 'application/json' },
13
+ })
14
+ return response.json()
15
+ },
16
+ createOrder: async (order: Omit<Order, 'id'>): Promise<Order> => {
17
+ const response = await fetch('https://petstore.swagger.io/v2/store/order', {
18
+ method: 'POST',
19
+ body: JSON.stringify({
20
+ quantity: order?.quantity ?? 1,
21
+ petId: 1,
22
+ shipDate: order?.shipDate ?? new Date().toISOString(),
23
+ status: order?.status ?? 'placed',
24
+ }),
25
+ headers: { 'Content-Type': 'application/json' },
26
+ })
27
+ return response.json()
28
+ },
29
+ }
@@ -4,7 +4,7 @@
4
4
  "title": "Step Configuration",
5
5
  "description": "All steps should have a defined configuration, this is how you define the step's behavior and how it will be triggered.",
6
6
  "lines": [
7
- "5-29"
7
+ "6-30"
8
8
  ]
9
9
  },
10
10
  {
@@ -12,7 +12,7 @@
12
12
  "title": "API Step",
13
13
  "description": "Definition of an API endpoint",
14
14
  "lines": [
15
- "11-12"
15
+ "12-13"
16
16
  ]
17
17
  },
18
18
  {
@@ -20,7 +20,7 @@
20
20
  "title": "Request body",
21
21
  "description": "Definition of the expected request body. Motia will automatically generate types based on this schema.",
22
22
  "lines": [
23
- "13-24"
23
+ "14-25"
24
24
  ]
25
25
  },
26
26
  {
@@ -28,7 +28,7 @@
28
28
  "title": "Response Payload",
29
29
  "description": "Definition of the expected response payload, Motia will generate the types automatically based on this schema. This is also important to create the Open API spec later.",
30
30
  "lines": [
31
- "25-27"
31
+ "26-28"
32
32
  ]
33
33
  },
34
34
  {
@@ -36,8 +36,8 @@
36
36
  "title": "Emits",
37
37
  "description": "We can define the events that this step will emit, this is how we can trigger other Motia Steps.",
38
38
  "lines": [
39
- "28",
40
- "38-45"
39
+ "29",
40
+ "39-46"
41
41
  ]
42
42
  },
43
43
  {
@@ -45,7 +45,7 @@
45
45
  "title": "Handler",
46
46
  "description": "The handler is the function that will be executed when the step is triggered. This one receives the request body and emits events.",
47
47
  "lines": [
48
- "31-49"
48
+ "32-50"
49
49
  ]
50
50
  },
51
51
  {
@@ -53,7 +53,7 @@
53
53
  "title": "Logger",
54
54
  "description": "The logger is a utility that allows you to log messages to the console. It is available in the handler function. We encourage you to use it instead of console.log. It will automatically be tied to the trace id of the request.",
55
55
  "lines": [
56
- "32"
56
+ "33"
57
57
  ]
58
58
  },
59
59
  {
@@ -61,7 +61,7 @@
61
61
  "title": "HTTP Response",
62
62
  "description": "The handler can return a response to the client. This is how we can return a response to the client. It must comply with the responseSchema defined in the step configuration.",
63
63
  "lines": [
64
- "48"
64
+ "49"
65
65
  ]
66
66
  }
67
67
  ]
@@ -1,6 +1,7 @@
1
1
  import { ApiRouteConfig, Handlers } from 'motia'
2
2
  import { z } from 'zod'
3
- import { petStoreService, petSchema } from '../../src/services/pet-store'
3
+ import { petStoreService } from '../services/pet-store'
4
+ import { petSchema } from '../services/types'
4
5
 
5
6
  export const config: ApiRouteConfig = {
6
7
  type: 'api',
@@ -1,6 +1,6 @@
1
1
  import { EventConfig, Handlers } from 'motia'
2
2
  import { z } from 'zod'
3
- import { petStoreService } from '../../src/services/pet-store'
3
+ import { petStoreService } from '../services/pet-store'
4
4
 
5
5
  export const config: EventConfig = {
6
6
  type: 'event',
@@ -0,0 +1,467 @@
1
+ # Motia Framework Development Assistant
2
+
3
+ You are helping develop a **Motia project** - a unified backend framework that uses event-driven architecture with multiple programming languages.
4
+
5
+ ## Core Motia Concepts
6
+
7
+ ### Steps Architecture
8
+
9
+ - **Steps** are the fundamental building blocks - each has `config` and `handler`
10
+ - **API Steps**: HTTP endpoints (`type: 'api'`)
11
+ - **Event Steps**: Event processors (`type: 'event'`)
12
+ - **Cron Steps**: Scheduled tasks (`type: 'cron'`)
13
+ - **Stream Steps**: Real-time data (`type: 'stream'`)
14
+ - **NOOP Steps**: Workflow routing (`type: 'noop'`)
15
+
16
+ ### Event-Driven Communication
17
+
18
+ - Steps communicate via `emit({ topic: 'event-name', data: {...} })`
19
+ - Subscribe to events: `subscribes: ['topic-name']` in config
20
+ - Creates loose coupling and parallel execution
21
+
22
+ ### State Management
23
+
24
+ - Persistent state via `state.set(group, key, value)` and `state.get(group, key)`
25
+ - State is scoped by groups ('orders', 'users', etc.) and keys
26
+ - Supports trace-scoped and global persistence
27
+
28
+ ## File Structure
29
+
30
+ ```
31
+ steps/ # All step implementations
32
+ ├── *.step.ts # Step files (config + handler)
33
+ ├── *-features.json # Tutorial/workbench metadata
34
+ services/ # Shared business logic
35
+ types.d.ts # Auto-generated types from step configs
36
+ motia-workbench.json # Visual flow configuration
37
+ ```
38
+
39
+ ## Step Implementation Patterns
40
+
41
+ Motia supports **multiple programming languages** in the same project. Choose the best language for each task:
42
+
43
+ - **TypeScript/JavaScript**: APIs, web logic, real-time features
44
+ - **Python**: AI/ML, data science, image processing, analytics
45
+ - **Ruby**: Reports, data exports, file processing, templating
46
+
47
+ ### TypeScript API Step
48
+
49
+ ```typescript
50
+ import { z } from 'zod'
51
+ import type { ApiRouteConfig, Handlers } from '@motia/core'
52
+
53
+ export const config: ApiRouteConfig = {
54
+ type: 'api',
55
+ name: 'CreateOrder',
56
+ method: 'POST',
57
+ path: '/orders',
58
+ bodySchema: z.object({
59
+ productId: z.string(),
60
+ quantity: z.number(),
61
+ }),
62
+ emits: ['order.created'],
63
+ flows: ['ecommerce'],
64
+ }
65
+
66
+ export const handler: Handlers['CreateOrder'] = async (req, { logger, emit, state, traceId }) => {
67
+ const order = { id: crypto.randomUUID(), ...req.body, createdAt: new Date() }
68
+ await state.set('orders', order.id, order)
69
+ await emit({ topic: 'order.created', data: order })
70
+ return { status: 201, body: order }
71
+ }
72
+ ```
73
+
74
+ ### JavaScript Event Step
75
+
76
+ ```javascript
77
+ // steps/process-payment.step.js
78
+ exports.config = {
79
+ type: 'event',
80
+ name: 'ProcessPayment',
81
+ subscribes: ['order.created'],
82
+ emits: ['payment.processed', 'payment.failed'],
83
+ input: {
84
+ id: 'string',
85
+ amount: 'number',
86
+ currency: 'string',
87
+ },
88
+ }
89
+
90
+ exports.handler = async (order, { logger, emit, state }) => {
91
+ try {
92
+ logger.info('Processing payment', { orderId: order.id })
93
+
94
+ // Simulate payment processing
95
+ const paymentResult = await processPayment(order)
96
+
97
+ await state.set('payments', order.id, paymentResult)
98
+ await emit({
99
+ topic: 'payment.processed',
100
+ data: { orderId: order.id, paymentId: paymentResult.id },
101
+ })
102
+ } catch (error) {
103
+ logger.error('Payment failed', { orderId: order.id, error: error.message })
104
+ await emit({ topic: 'payment.failed', data: { orderId: order.id, error: error.message } })
105
+ }
106
+ }
107
+ ```
108
+
109
+ ### Python AI/ML Event Step
110
+
111
+ ```python
112
+ # steps/analyze_sentiment.step.py
113
+ import asyncio
114
+ from transformers import pipeline
115
+
116
+ config = {
117
+ "type": "event",
118
+ "name": "AnalyzeSentiment",
119
+ "subscribes": ["review.submitted"],
120
+ "emits": ["sentiment.analyzed"],
121
+ "input": {
122
+ "reviewId": "string",
123
+ "text": "string",
124
+ "userId": "string"
125
+ }
126
+ }
127
+
128
+ # Initialize ML model
129
+ sentiment_analyzer = pipeline("sentiment-analysis")
130
+
131
+ async def handler(review_data, context):
132
+ logger = context["logger"]
133
+ emit = context["emit"]
134
+ state = context["state"]
135
+
136
+ try:
137
+ logger.info(f"Analyzing sentiment for review {review_data['reviewId']}")
138
+
139
+ # Run sentiment analysis
140
+ result = sentiment_analyzer(review_data["text"])
141
+ sentiment_score = result[0]["score"]
142
+ sentiment_label = result[0]["label"]
143
+
144
+ analysis = {
145
+ "reviewId": review_data["reviewId"],
146
+ "sentiment": sentiment_label,
147
+ "confidence": sentiment_score,
148
+ "analyzedAt": datetime.now().isoformat()
149
+ }
150
+
151
+ await state.set("sentiment_analyses", review_data["reviewId"], analysis)
152
+ await emit({
153
+ "topic": "sentiment.analyzed",
154
+ "data": analysis
155
+ })
156
+
157
+ except Exception as error:
158
+ logger.error(f"Sentiment analysis failed: {str(error)}")
159
+ await emit({
160
+ "topic": "analysis.failed",
161
+ "data": {"reviewId": review_data["reviewId"], "error": str(error)}
162
+ })
163
+ ```
164
+
165
+ ### Python Data Processing Step
166
+
167
+ ```python
168
+ # steps/generate_analytics.step.py
169
+ import pandas as pd
170
+ import numpy as np
171
+ from datetime import datetime, timedelta
172
+
173
+ config = {
174
+ "type": "cron",
175
+ "name": "GenerateAnalytics",
176
+ "cron": "0 0 * * 1", # Weekly on Monday
177
+ "emits": ["analytics.generated"]
178
+ }
179
+
180
+ async def handler(context):
181
+ logger = context["logger"]
182
+ emit = context["emit"]
183
+ state = context["state"]
184
+
185
+ try:
186
+ # Fetch all orders from state
187
+ orders_data = await state.get_group("orders")
188
+
189
+ if not orders_data:
190
+ logger.info("No orders data available")
191
+ return
192
+
193
+ # Convert to pandas DataFrame for analysis
194
+ df = pd.DataFrame(list(orders_data.values()))
195
+ df['createdAt'] = pd.to_datetime(df['createdAt'])
196
+
197
+ # Generate analytics
198
+ last_week = datetime.now() - timedelta(days=7)
199
+ recent_orders = df[df['createdAt'] >= last_week]
200
+
201
+ analytics = {
202
+ "totalOrders": len(df),
203
+ "weeklyOrders": len(recent_orders),
204
+ "averageOrderValue": float(df['amount'].mean()) if 'amount' in df else 0,
205
+ "topProducts": df['productId'].value_counts().head(5).to_dict(),
206
+ "generatedAt": datetime.now().isoformat()
207
+ }
208
+
209
+ await state.set("analytics", "weekly", analytics)
210
+ await emit({"topic": "analytics.generated", "data": analytics})
211
+
212
+ logger.info("Analytics generated successfully")
213
+
214
+ except Exception as error:
215
+ logger.error(f"Analytics generation failed: {str(error)}")
216
+ ```
217
+
218
+ ### Ruby Report Generation Step
219
+
220
+ ```ruby
221
+ # steps/generate_report.step.rb
222
+ require 'csv'
223
+ require 'json'
224
+
225
+ def config
226
+ {
227
+ type: 'event',
228
+ name: 'GenerateReport',
229
+ subscribes: ['analytics.generated'],
230
+ emits: ['report.generated'],
231
+ input: {
232
+ totalOrders: 'number',
233
+ weeklyOrders: 'number',
234
+ topProducts: 'object'
235
+ }
236
+ }
237
+ end
238
+
239
+ def handler(analytics_data, context)
240
+ logger = context[:logger]
241
+ emit = context[:emit]
242
+ state = context[:state]
243
+
244
+ begin
245
+ logger.info("Generating CSV report from analytics")
246
+
247
+ # Generate CSV report
248
+ csv_data = CSV.generate do |csv|
249
+ csv << ['Metric', 'Value']
250
+ csv << ['Total Orders', analytics_data['totalOrders']]
251
+ csv << ['Weekly Orders', analytics_data['weeklyOrders']]
252
+ csv << ['Average Order Value', analytics_data['averageOrderValue']]
253
+
254
+ # Add top products
255
+ analytics_data['topProducts'].each do |product, count|
256
+ csv << ["Product #{product}", count]
257
+ end
258
+ end
259
+
260
+ # Generate HTML report
261
+ html_report = generate_html_template(analytics_data)
262
+
263
+ report = {
264
+ id: SecureRandom.uuid,
265
+ csv_data: csv_data,
266
+ html_report: html_report,
267
+ generated_at: Time.now.iso8601
268
+ }
269
+
270
+ state.set('reports', report[:id], report)
271
+ emit.call(topic: 'report.generated', data: report)
272
+
273
+ logger.info("Report generated successfully", report_id: report[:id])
274
+
275
+ rescue => error
276
+ logger.error("Report generation failed", error: error.message)
277
+ emit.call(topic: 'report.failed', data: { error: error.message })
278
+ end
279
+ end
280
+
281
+ private
282
+
283
+ def generate_html_template(data)
284
+ <<~HTML
285
+ <html>
286
+ <head><title>Analytics Report</title></head>
287
+ <body>
288
+ <h1>Weekly Analytics Report</h1>
289
+ <p>Total Orders: #{data['totalOrders']}</p>
290
+ <p>Weekly Orders: #{data['weeklyOrders']}</p>
291
+ <p>Generated: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}</p>
292
+ </body>
293
+ </html>
294
+ HTML
295
+ end
296
+ ```
297
+
298
+ ## Development Commands
299
+
300
+ ```bash
301
+ # Start development server with workbench UI
302
+ npm run dev
303
+
304
+ # Run specific step
305
+ motia run step-name
306
+
307
+ # Build for production
308
+ motia build
309
+ ```
310
+
311
+ ## Code Standards
312
+
313
+ ### Multi-Language File Naming
314
+
315
+ - **TypeScript**: `step-name.step.ts`
316
+ - **JavaScript**: `step-name.step.js`
317
+ - **Python**: `step_name.step.py`
318
+ - **Ruby**: `step-name.step.rb`
319
+
320
+ ### Language-Specific Patterns
321
+
322
+ #### TypeScript/JavaScript
323
+
324
+ - Use Zod schemas for validation (TypeScript) or simple objects (JavaScript)
325
+ - Leverage auto-generated types from `types.d.ts` (TypeScript only)
326
+ - Use `async/await` for all async operations
327
+ - Export `config` and `handler` using ES6 modules (TypeScript) or CommonJS (JavaScript)
328
+
329
+ #### Python
330
+
331
+ - Use dictionary for config with snake_case keys
332
+ - Use `async def handler()` for async operations
333
+ - Access context via dictionary: `context["logger"]`, `context["emit"]`
334
+ - Use type hints where helpful for clarity
335
+ - Follow PEP 8 naming conventions
336
+
337
+ #### Ruby
338
+
339
+ - Use method `config` returning a hash
340
+ - Use method `handler(input, context)`
341
+ - Access context via hash: `context[:logger]`, `context[:emit]`
342
+ - Follow Ruby naming conventions (snake_case)
343
+ - Use proper exception handling with `rescue`
344
+
345
+ ### Universal Naming Conventions
346
+
347
+ - Step names: `CamelCase` across all languages
348
+ - Topics: `category.action` (e.g., `order.created`, `user.updated`)
349
+ - State groups: `plural-noun` (e.g., `orders`, `users`)
350
+ - File names follow language conventions but descriptive
351
+
352
+ ### Error Handling by Language
353
+
354
+ #### TypeScript/JavaScript
355
+
356
+ ```typescript
357
+ try {
358
+ // Step logic
359
+ } catch (error) {
360
+ logger.error('Operation failed', { error: error.message, traceId })
361
+ // For API steps: return error response
362
+ // For Event steps: emit error event or rethrow
363
+ }
364
+ ```
365
+
366
+ #### Python
367
+
368
+ ```python
369
+ try:
370
+ # Step logic
371
+ pass
372
+ except Exception as error:
373
+ logger.error(f"Operation failed: {str(error)}")
374
+ # Emit error event or re-raise
375
+ await emit({"topic": "error.occurred", "data": {"error": str(error)}})
376
+ ```
377
+
378
+ #### Ruby
379
+
380
+ ```ruby
381
+ begin
382
+ # Step logic
383
+ rescue => error
384
+ logger.error("Operation failed", error: error.message)
385
+ # Emit error event or re-raise
386
+ emit.call(topic: 'error.occurred', data: { error: error.message })
387
+ end
388
+ ```
389
+
390
+ ### State Management Best Practices
391
+
392
+ - Use semantic group names for state organization
393
+ - Store complex objects, not just primitives
394
+ - Consider trace-scoped vs global state based on use case
395
+ - Clean up unused state in cron jobs
396
+
397
+ ## Testing & Debugging
398
+
399
+ ### Workbench Features
400
+
401
+ - Visual flow representation and editing
402
+ - API endpoint testing with real data
403
+ - Real-time logging and tracing
404
+ - State inspection and management
405
+ - Tutorial system integration
406
+
407
+ ### Logging
408
+
409
+ ```typescript
410
+ logger.info('Processing started', { userId, traceId })
411
+ logger.error('Validation failed', { errors, input, traceId })
412
+ ```
413
+
414
+ ## Project-Specific Context
415
+
416
+ This project implements a **pet store ordering system** with:
417
+
418
+ - API endpoint for pet creation and food orders
419
+ - Event processing for order fulfillment
420
+ - Notification system for order updates
421
+ - Scheduled auditing for overdue orders
422
+
423
+ When working on this codebase:
424
+
425
+ - Follow the existing event flow patterns
426
+ - Use the established state groups (`orders`, `pets`)
427
+ - Maintain the tutorial-friendly structure for the workbench
428
+ - Test changes using the development workbench UI
429
+
430
+ ## Multi-Language Workflow Examples
431
+
432
+ ### Complete E-commerce Flow
433
+
434
+ ```
435
+ TypeScript API → JavaScript Payment → Python ML → Ruby Reports
436
+ ```
437
+
438
+ 1. **API Endpoint** (TypeScript): Handle orders with validation
439
+ 2. **Payment Processing** (JavaScript): Fast payment logic
440
+ 3. **Recommendation Engine** (Python): ML-based product recommendations
441
+ 4. **Report Generation** (Ruby): Beautiful HTML/PDF reports
442
+
443
+ ### AI-Powered Content Pipeline
444
+
445
+ ```
446
+ JavaScript API → Python AI → Ruby Templates → TypeScript Notifications
447
+ ```
448
+
449
+ 1. **Content Upload** (JavaScript): Quick file handling
450
+ 2. **AI Processing** (Python): Image recognition, text analysis
451
+ 3. **Template Generation** (Ruby): Dynamic content templates
452
+ 4. **Real-time Updates** (TypeScript): WebSocket notifications
453
+
454
+ ## Common Tasks
455
+
456
+ - **Adding API endpoints**: Create API step in TypeScript/JavaScript with validation
457
+ - **Processing background jobs**: Create event steps in the most suitable language
458
+ - **AI/ML tasks**: Use Python steps with appropriate libraries
459
+ - **Data processing**: Use Python for analytics, Ruby for reports
460
+ - **Scheduled maintenance**: Use cron steps for periodic cleanup and auditing
461
+ - **Real-time features**: Use TypeScript/JavaScript for WebSocket handling
462
+
463
+ ## Resources
464
+
465
+ - Local development: `npm run dev` → http://localhost:5173
466
+ - Motia documentation: https://motia.dev/docs
467
+ - Workbench tutorials: Available in development mode