claude-mpm 4.15.6__py3-none-any.whl → 4.21.0__py3-none-any.whl

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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (194) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  3. claude_mpm/agents/BASE_PM.md +272 -23
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +49 -0
  5. claude_mpm/agents/agent_loader.py +4 -4
  6. claude_mpm/agents/templates/engineer.json +5 -1
  7. claude_mpm/agents/templates/php-engineer.json +10 -4
  8. claude_mpm/agents/templates/python_engineer.json +8 -3
  9. claude_mpm/agents/templates/rust_engineer.json +12 -7
  10. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  11. claude_mpm/cli/commands/__init__.py +2 -0
  12. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  13. claude_mpm/cli/commands/mpm_init/core.py +525 -0
  14. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  15. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  16. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  17. claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
  18. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  19. claude_mpm/cli/commands/mpm_init_handler.py +67 -1
  20. claude_mpm/cli/commands/skills.py +488 -0
  21. claude_mpm/cli/executor.py +2 -0
  22. claude_mpm/cli/parsers/base_parser.py +7 -0
  23. claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
  24. claude_mpm/cli/parsers/skills_parser.py +137 -0
  25. claude_mpm/cli/startup.py +57 -0
  26. claude_mpm/commands/mpm-auto-configure.md +52 -0
  27. claude_mpm/commands/mpm-help.md +3 -0
  28. claude_mpm/commands/mpm-init.md +112 -6
  29. claude_mpm/commands/mpm-version.md +113 -0
  30. claude_mpm/commands/mpm.md +1 -0
  31. claude_mpm/config/agent_config.py +2 -2
  32. claude_mpm/constants.py +12 -0
  33. claude_mpm/core/config.py +42 -0
  34. claude_mpm/core/factories.py +1 -1
  35. claude_mpm/core/interfaces.py +56 -1
  36. claude_mpm/core/optimized_agent_loader.py +3 -3
  37. claude_mpm/hooks/__init__.py +8 -0
  38. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  39. claude_mpm/hooks/session_resume_hook.py +121 -0
  40. claude_mpm/models/resume_log.py +340 -0
  41. claude_mpm/services/agents/auto_config_manager.py +1 -1
  42. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  43. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  44. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  45. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  46. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  47. claude_mpm/services/agents/local_template_manager.py +1 -1
  48. claude_mpm/services/agents/recommender.py +47 -0
  49. claude_mpm/services/cli/resume_service.py +617 -0
  50. claude_mpm/services/cli/session_manager.py +87 -0
  51. claude_mpm/services/cli/session_pause_manager.py +504 -0
  52. claude_mpm/services/cli/session_resume_helper.py +372 -0
  53. claude_mpm/services/core/interfaces.py +56 -1
  54. claude_mpm/services/core/models/agent_config.py +3 -0
  55. claude_mpm/services/core/models/process.py +4 -0
  56. claude_mpm/services/core/path_resolver.py +1 -1
  57. claude_mpm/services/diagnostics/models.py +21 -0
  58. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  59. claude_mpm/services/local_ops/__init__.py +2 -0
  60. claude_mpm/services/mcp_config_manager.py +7 -131
  61. claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
  62. claude_mpm/services/mcp_gateway/core/process_pool.py +19 -10
  63. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +26 -21
  64. claude_mpm/services/session_manager.py +205 -1
  65. claude_mpm/services/unified/deployment_strategies/local.py +1 -1
  66. claude_mpm/services/version_service.py +104 -1
  67. claude_mpm/skills/__init__.py +21 -0
  68. claude_mpm/skills/agent_skills_injector.py +324 -0
  69. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  70. claude_mpm/skills/bundled/api-documentation.md +393 -0
  71. claude_mpm/skills/bundled/async-testing.md +571 -0
  72. claude_mpm/skills/bundled/code-review.md +143 -0
  73. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  74. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  75. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  76. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  77. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  78. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  79. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  80. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  81. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  82. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  83. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  84. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  85. claude_mpm/skills/bundled/database-migration.md +199 -0
  86. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  87. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  88. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  89. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  90. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  91. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  92. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  93. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  94. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  95. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  96. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  97. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  98. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  99. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  100. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  101. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  102. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  103. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  104. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  105. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  106. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  107. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  108. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  109. claude_mpm/skills/bundled/git-workflow.md +414 -0
  110. claude_mpm/skills/bundled/imagemagick.md +204 -0
  111. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  112. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  113. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  114. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  115. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  116. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  117. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  118. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  119. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  120. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  121. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  122. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  123. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  124. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  125. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  126. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  127. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  128. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  129. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  130. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  131. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  132. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  133. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  134. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  135. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  136. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  137. claude_mpm/skills/bundled/pdf.md +141 -0
  138. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  139. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  140. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  141. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  142. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  143. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  144. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  145. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  146. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  147. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  148. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  149. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  150. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  151. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  152. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  153. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  154. claude_mpm/skills/bundled/security-scanning.md +327 -0
  155. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  156. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  157. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  158. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  159. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  160. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  161. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  162. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  163. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  164. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  165. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  166. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  167. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  168. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  169. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  170. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  171. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  172. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  173. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  174. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  175. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  176. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  177. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  178. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  179. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  180. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  181. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  182. claude_mpm/skills/bundled/xlsx.md +157 -0
  183. claude_mpm/skills/registry.py +97 -9
  184. claude_mpm/skills/skills_registry.py +348 -0
  185. claude_mpm/skills/skills_service.py +739 -0
  186. claude_mpm/utils/agent_dependency_loader.py +2 -2
  187. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/METADATA +211 -33
  188. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/RECORD +192 -60
  189. claude_mpm/agents/INSTRUCTIONS_OLD_DEPRECATED.md +0 -602
  190. claude_mpm/cli/commands/mpm_init.py +0 -2008
  191. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/WHEEL +0 -0
  192. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/entry_points.txt +0 -0
  193. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/licenses/LICENSE +0 -0
  194. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,742 @@
1
+ # Development Workflow Reference
2
+
3
+ ## Extension Development Setup
4
+
5
+ ### Using ext-template
6
+
7
+ The official ext-template provides the recommended structure for EspoCRM extensions.
8
+
9
+ ```bash
10
+ # Clone the template
11
+ git clone https://github.com/espocrm/ext-template.git my-extension
12
+ cd my-extension
13
+
14
+ # Install dependencies
15
+ composer install
16
+ npm install
17
+ ```
18
+
19
+ ### Extension Directory Structure (EspoCRM 7.4+)
20
+
21
+ ```
22
+ my-extension/
23
+ ├── src/
24
+ │ ├── files/
25
+ │ │ └── custom/Espo/Modules/MyModule/
26
+ │ │ ├── Resources/
27
+ │ │ │ ├── metadata/
28
+ │ │ │ │ ├── entityDefs/
29
+ │ │ │ │ ├── clientDefs/
30
+ │ │ │ │ └── scopes/
31
+ │ │ │ └── layouts/
32
+ │ │ ├── Services/
33
+ │ │ ├── Controllers/
34
+ │ │ ├── Repositories/
35
+ │ │ ├── Hooks/
36
+ │ │ └── Entities/
37
+ │ └── scripts/
38
+ ├── tests/
39
+ ├── package.json
40
+ └── manifest.json
41
+ ```
42
+
43
+ ### Manifest File
44
+
45
+ ```json
46
+ {
47
+ "name": "My Extension",
48
+ "version": "1.0.0",
49
+ "acceptableVersions": [">=7.4.0"],
50
+ "author": "Your Name",
51
+ "description": "Extension description",
52
+ "license": "MIT",
53
+ "releaseDate": "2024-01-01",
54
+ "skipBackup": true
55
+ }
56
+ ```
57
+
58
+ ### Building Extension
59
+
60
+ ```bash
61
+ # Build installable package
62
+ npm run build
63
+
64
+ # Output: build/MyExtension-1.0.0.zip
65
+ ```
66
+
67
+ ## Creating Custom Entities
68
+
69
+ ### Step 1: Entity Definition
70
+
71
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/MyEntity.json`:
72
+
73
+ ```json
74
+ {
75
+ "fields": {
76
+ "name": {
77
+ "type": "varchar",
78
+ "required": true,
79
+ "maxLength": 255,
80
+ "trim": true,
81
+ "view": "views/fields/varchar"
82
+ },
83
+ "description": {
84
+ "type": "text",
85
+ "rows": 4
86
+ },
87
+ "status": {
88
+ "type": "enum",
89
+ "options": ["New", "In Progress", "Complete", "Cancelled"],
90
+ "default": "New",
91
+ "required": true,
92
+ "audited": true,
93
+ "isSorted": true
94
+ },
95
+ "priority": {
96
+ "type": "enum",
97
+ "options": ["Low", "Normal", "High", "Urgent"],
98
+ "default": "Normal",
99
+ "audited": true
100
+ },
101
+ "dueDate": {
102
+ "type": "date",
103
+ "audited": true
104
+ },
105
+ "assignedUser": {
106
+ "type": "link"
107
+ },
108
+ "account": {
109
+ "type": "link"
110
+ },
111
+ "contacts": {
112
+ "type": "linkMultiple"
113
+ }
114
+ },
115
+ "links": {
116
+ "assignedUser": {
117
+ "type": "belongsTo",
118
+ "entity": "User",
119
+ "foreign": "myEntities"
120
+ },
121
+ "account": {
122
+ "type": "belongsTo",
123
+ "entity": "Account",
124
+ "foreign": "myEntities"
125
+ },
126
+ "contacts": {
127
+ "type": "hasMany",
128
+ "entity": "Contact",
129
+ "foreign": "myEntities",
130
+ "layoutRelationshipsDisabled": true
131
+ },
132
+ "teams": {
133
+ "type": "hasMany",
134
+ "entity": "Team",
135
+ "relationName": "EntityTeam",
136
+ "layoutRelationshipsDisabled": true
137
+ }
138
+ },
139
+ "collection": {
140
+ "orderBy": "createdAt",
141
+ "order": "desc"
142
+ },
143
+ "indexes": {
144
+ "name": {
145
+ "columns": ["name", "deleted"]
146
+ },
147
+ "assignedUser": {
148
+ "columns": ["assignedUserId", "deleted"]
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ ### Step 2: Scope Definition
155
+
156
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/metadata/scopes/MyEntity.json`:
157
+
158
+ ```json
159
+ {
160
+ "entity": true,
161
+ "object": true,
162
+ "layouts": true,
163
+ "tab": true,
164
+ "acl": true,
165
+ "aclActionList": [
166
+ "create",
167
+ "read",
168
+ "edit",
169
+ "delete",
170
+ "stream"
171
+ ],
172
+ "aclLevelList": [
173
+ "all",
174
+ "team",
175
+ "own",
176
+ "no"
177
+ ],
178
+ "aclPortal": true,
179
+ "aclPortalLevelList": [
180
+ "all",
181
+ "account",
182
+ "contact",
183
+ "own",
184
+ "no"
185
+ ],
186
+ "customizable": true,
187
+ "type": "Base",
188
+ "module": "MyModule",
189
+ "stream": true,
190
+ "activities": true,
191
+ "historyDisabled": false,
192
+ "importable": true,
193
+ "notifications": true,
194
+ "activityStatusList": ["Planned", "Held", "Not Held"]
195
+ }
196
+ ```
197
+
198
+ ### Step 3: Client Definitions
199
+
200
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/metadata/clientDefs/MyEntity.json`:
201
+
202
+ ```json
203
+ {
204
+ "controller": "controllers/record",
205
+ "iconClass": "fas fa-tasks",
206
+ "color": "#6FA8D6",
207
+ "createDisabled": false,
208
+ "dynamicLogic": {
209
+ "fields": {
210
+ "dueDate": {
211
+ "required": {
212
+ "conditionGroup": [
213
+ {
214
+ "type": "equals",
215
+ "attribute": "status",
216
+ "value": "In Progress"
217
+ }
218
+ ]
219
+ }
220
+ }
221
+ }
222
+ },
223
+ "filterList": [
224
+ "active",
225
+ "completed"
226
+ ],
227
+ "boolFilterList": [
228
+ "onlyMy"
229
+ ],
230
+ "defaultFilterData": {
231
+ "primary": "active"
232
+ },
233
+ "sidePanels": {
234
+ "detail": [
235
+ {
236
+ "name": "activities",
237
+ "label": "Activities",
238
+ "view": "crm:views/record/panels/activities",
239
+ "aclScope": "Activities"
240
+ }
241
+ ]
242
+ }
243
+ }
244
+ ```
245
+
246
+ ### Step 4: Language Translations
247
+
248
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/i18n/en_US/MyEntity.json`:
249
+
250
+ ```json
251
+ {
252
+ "fields": {
253
+ "name": "Name",
254
+ "description": "Description",
255
+ "status": "Status",
256
+ "priority": "Priority",
257
+ "dueDate": "Due Date",
258
+ "assignedUser": "Assigned To",
259
+ "account": "Account",
260
+ "contacts": "Contacts"
261
+ },
262
+ "links": {
263
+ "assignedUser": "Assigned To",
264
+ "account": "Account",
265
+ "contacts": "Contacts"
266
+ },
267
+ "options": {
268
+ "status": {
269
+ "New": "New",
270
+ "In Progress": "In Progress",
271
+ "Complete": "Complete",
272
+ "Cancelled": "Cancelled"
273
+ },
274
+ "priority": {
275
+ "Low": "Low",
276
+ "Normal": "Normal",
277
+ "High": "High",
278
+ "Urgent": "Urgent"
279
+ }
280
+ },
281
+ "labels": {
282
+ "Create MyEntity": "Create MyEntity"
283
+ },
284
+ "presetFilters": {
285
+ "active": "Active",
286
+ "completed": "Completed"
287
+ },
288
+ "boolFilters": {
289
+ "onlyMy": "Only My"
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Step 5: Service Layer
295
+
296
+ Create `src/files/custom/Espo/Modules/MyModule/Services/MyEntity.php`:
297
+
298
+ ```php
299
+ <?php
300
+ namespace Espo\Modules\MyModule\Services;
301
+
302
+ use Espo\Services\Record;
303
+ use Espo\ORM\Entity;
304
+
305
+ class MyEntity extends Record
306
+ {
307
+ protected function beforeCreateEntity(Entity $entity, array $data): void
308
+ {
309
+ parent::beforeCreateEntity($entity, $data);
310
+
311
+ // Set default assigned user to creator if not specified
312
+ if (!$entity->get('assignedUserId')) {
313
+ $entity->set('assignedUserId', $this->user->getId());
314
+ }
315
+ }
316
+
317
+ protected function beforeUpdateEntity(Entity $entity, array $data): void
318
+ {
319
+ parent::beforeUpdateEntity($entity, $data);
320
+
321
+ // Auto-complete when status set to Complete
322
+ if ($entity->isAttributeChanged('status') && $entity->get('status') === 'Complete') {
323
+ $entity->set('completedAt', date('Y-m-d H:i:s'));
324
+ }
325
+ }
326
+ }
327
+ ```
328
+
329
+ ### Step 6: Rebuild Cache
330
+
331
+ ```bash
332
+ bin/command rebuild
333
+ ```
334
+
335
+ ## Creating Custom Fields
336
+
337
+ ### Custom Field Type Definition
338
+
339
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/metadata/fields/myFieldType.json`:
340
+
341
+ ```json
342
+ {
343
+ "params": [
344
+ {
345
+ "name": "required",
346
+ "type": "bool",
347
+ "default": false
348
+ },
349
+ {
350
+ "name": "maxLength",
351
+ "type": "int"
352
+ },
353
+ {
354
+ "name": "customParam",
355
+ "type": "varchar"
356
+ }
357
+ ],
358
+ "view": "custom:views/fields/my-field-type",
359
+ "personalData": false
360
+ }
361
+ ```
362
+
363
+ ### Custom Field Backend
364
+
365
+ Create `src/files/custom/Espo/Modules/MyModule/Classes/FieldType/MyFieldTypeType.php`:
366
+
367
+ ```php
368
+ <?php
369
+ namespace Espo\Modules\MyModule\Classes\FieldType;
370
+
371
+ use Espo\ORM\Entity;
372
+ use Espo\ORM\Type\AttributeType;
373
+ use Espo\Core\Field\FieldType;
374
+
375
+ class MyFieldTypeType implements FieldType
376
+ {
377
+ public function getAttributeParamList(): array
378
+ {
379
+ return [
380
+ AttributeType::VARCHAR,
381
+ ];
382
+ }
383
+
384
+ public function getActualAttributeParamList(Entity $entity, string $field): array
385
+ {
386
+ return [
387
+ AttributeType::VARCHAR,
388
+ ];
389
+ }
390
+ }
391
+ ```
392
+
393
+ ### Custom Field Frontend
394
+
395
+ Create `client/custom/src/views/fields/my-field-type.js`:
396
+
397
+ ```javascript
398
+ define('custom:views/fields/my-field-type', ['views/fields/varchar'], function (Dep) {
399
+
400
+ return Dep.extend({
401
+
402
+ setup: function () {
403
+ Dep.prototype.setup.call(this);
404
+
405
+ // Custom setup logic
406
+ this.customParam = this.params.customParam || '';
407
+ },
408
+
409
+ afterRender: function () {
410
+ Dep.prototype.afterRender.call(this);
411
+
412
+ // Custom rendering logic
413
+ },
414
+
415
+ validateRequired: function () {
416
+ if (this.params.required) {
417
+ if (!this.model.get(this.name)) {
418
+ var msg = this.translate('fieldIsRequired', 'messages')
419
+ .replace('{field}', this.getLabelText());
420
+ this.showValidationMessage(msg);
421
+ return true;
422
+ }
423
+ }
424
+ },
425
+
426
+ fetch: function () {
427
+ var data = {};
428
+ data[this.name] = this.$element.val() || null;
429
+ return data;
430
+ }
431
+ });
432
+ });
433
+ ```
434
+
435
+ ## Custom API Endpoints
436
+
437
+ ### Step 1: Define Route
438
+
439
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/metadata/api.json`:
440
+
441
+ ```json
442
+ {
443
+ "routes": [
444
+ {
445
+ "route": "/MyEntity/:id/customAction",
446
+ "method": "post",
447
+ "controller": "MyModule:MyEntity",
448
+ "action": "customAction"
449
+ }
450
+ ]
451
+ }
452
+ ```
453
+
454
+ ### Step 2: Create Controller
455
+
456
+ Create `src/files/custom/Espo/Modules/MyModule/Controllers/MyEntity.php`:
457
+
458
+ ```php
459
+ <?php
460
+ namespace Espo\Modules\MyModule\Controllers;
461
+
462
+ use Espo\Core\Controllers\Record;
463
+ use Espo\Core\Api\Request;
464
+ use Espo\Core\Api\Response;
465
+ use Espo\Core\Exceptions\BadRequest;
466
+ use Espo\Core\Exceptions\Forbidden;
467
+ use stdClass;
468
+
469
+ class MyEntity extends Record
470
+ {
471
+ public function postActionCustomAction(Request $request, Response $response): stdClass
472
+ {
473
+ $id = $request->getRouteParam('id');
474
+
475
+ if (!$id) {
476
+ throw new BadRequest();
477
+ }
478
+
479
+ $data = $request->getParsedBody();
480
+
481
+ if (!$this->acl->check($this->name, 'edit')) {
482
+ throw new Forbidden();
483
+ }
484
+
485
+ // Delegate to service layer
486
+ $service = $this->getRecordService();
487
+ $result = $service->customAction($id, $data);
488
+
489
+ return $result->getValueMap();
490
+ }
491
+ }
492
+ ```
493
+
494
+ ### Step 3: Implement Service Method
495
+
496
+ ```php
497
+ <?php
498
+ namespace Espo\Modules\MyModule\Services;
499
+
500
+ use Espo\Services\Record;
501
+ use Espo\Core\Exceptions\NotFound;
502
+ use stdClass;
503
+
504
+ class MyEntity extends Record
505
+ {
506
+ public function customAction(string $id, stdClass $data): object
507
+ {
508
+ $entity = $this->getEntity($id);
509
+
510
+ if (!$entity) {
511
+ throw new NotFound();
512
+ }
513
+
514
+ // Business logic
515
+ $entity->set('status', $data->status ?? 'In Progress');
516
+ $entity->set('processedAt', date('Y-m-d H:i:s'));
517
+
518
+ $this->entityManager->saveEntity($entity);
519
+
520
+ return $entity;
521
+ }
522
+ }
523
+ ```
524
+
525
+ ### Step 4: Call from Frontend
526
+
527
+ ```javascript
528
+ this.ajaxPostRequest('MyEntity/' + id + '/customAction', {
529
+ status: 'Complete'
530
+ }).then(response => {
531
+ console.log('Action completed', response);
532
+ this.model.set(response);
533
+ });
534
+ ```
535
+
536
+ ## Custom Repositories
537
+
538
+ ### Creating Custom Repository
539
+
540
+ Create `src/files/custom/Espo/Modules/MyModule/Repositories/MyEntity.php`:
541
+
542
+ ```php
543
+ <?php
544
+ namespace Espo\Modules\MyModule\Repositories;
545
+
546
+ use Espo\Core\Repositories\Database;
547
+ use Espo\ORM\Entity;
548
+
549
+ class MyEntity extends Database
550
+ {
551
+ protected function beforeSave(Entity $entity, array $options = []): void
552
+ {
553
+ parent::beforeSave($entity, $options);
554
+
555
+ // Repository-level validation or data transformation
556
+ if ($entity->isNew()) {
557
+ $entity->set('customIdentifier', $this->generateIdentifier());
558
+ }
559
+ }
560
+
561
+ private function generateIdentifier(): string
562
+ {
563
+ // Generate unique identifier
564
+ $prefix = 'ME-';
565
+ $number = $this->getNewNumber();
566
+ return $prefix . str_pad($number, 6, '0', STR_PAD_LEFT);
567
+ }
568
+
569
+ private function getNewNumber(): int
570
+ {
571
+ $query = $this->entityManager
572
+ ->getQueryBuilder()
573
+ ->select()
574
+ ->from('MyEntity')
575
+ ->select('COUNT(*) as count')
576
+ ->build();
577
+
578
+ $sth = $this->entityManager->getQueryExecutor()->execute($query);
579
+ $row = $sth->fetch();
580
+
581
+ return ($row['count'] ?? 0) + 1;
582
+ }
583
+
584
+ public function findActive(): \Espo\ORM\Collection
585
+ {
586
+ return $this->where([
587
+ 'status!=' => ['Complete', 'Cancelled']
588
+ ])->find();
589
+ }
590
+ }
591
+ ```
592
+
593
+ ## Layouts
594
+
595
+ ### List Layout
596
+
597
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/layouts/MyEntity/list.json`:
598
+
599
+ ```json
600
+ [
601
+ {
602
+ "name": "name",
603
+ "width": "30"
604
+ },
605
+ {
606
+ "name": "status",
607
+ "width": "15"
608
+ },
609
+ {
610
+ "name": "priority",
611
+ "width": "15"
612
+ },
613
+ {
614
+ "name": "assignedUser",
615
+ "width": "15"
616
+ },
617
+ {
618
+ "name": "dueDate",
619
+ "width": "15"
620
+ },
621
+ {
622
+ "name": "createdAt",
623
+ "width": "10"
624
+ }
625
+ ]
626
+ ```
627
+
628
+ ### Detail Layout
629
+
630
+ Create `src/files/custom/Espo/Modules/MyModule/Resources/layouts/MyEntity/detail.json`:
631
+
632
+ ```json
633
+ [
634
+ {
635
+ "label": "Overview",
636
+ "rows": [
637
+ [
638
+ {"name": "name"},
639
+ {"name": "status"}
640
+ ],
641
+ [
642
+ {"name": "assignedUser"},
643
+ {"name": "priority"}
644
+ ],
645
+ [
646
+ {"name": "account"},
647
+ {"name": "dueDate"}
648
+ ],
649
+ [
650
+ {"name": "description", "fullWidth": true}
651
+ ]
652
+ ]
653
+ },
654
+ {
655
+ "label": "Contacts",
656
+ "rows": [
657
+ [
658
+ {"name": "contacts", "fullWidth": true}
659
+ ]
660
+ ]
661
+ }
662
+ ]
663
+ ```
664
+
665
+ ## Development Best Practices
666
+
667
+ ### Cache Rebuild Workflow
668
+
669
+ ```bash
670
+ # After any metadata changes
671
+ bin/command rebuild
672
+
673
+ # Clear cache only (faster, but may miss some changes)
674
+ bin/command clear-cache
675
+
676
+ # Hard rebuild (if issues persist)
677
+ rm -rf data/cache/*
678
+ bin/command rebuild
679
+ ```
680
+
681
+ ### Testing Extension Installation
682
+
683
+ ```bash
684
+ # Build extension
685
+ npm run build
686
+
687
+ # Install in test EspoCRM instance
688
+ # Administration > Extensions > Upload
689
+ # Upload build/MyExtension-1.0.0.zip
690
+
691
+ # After changes, rebuild extension and reinstall
692
+ npm run build
693
+ # Uninstall old version via Administration > Extensions
694
+ # Install new version
695
+ ```
696
+
697
+ ### Version Compatibility
698
+
699
+ ```php
700
+ // Check EspoCRM version in code
701
+ $version = $this->config->get('version');
702
+
703
+ if (version_compare($version, '8.0.0', '>=')) {
704
+ // EspoCRM 8.0+ features
705
+ }
706
+
707
+ // Use version-specific metadata
708
+ // For EspoCRM 7.x
709
+ custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/MyEntity.json
710
+
711
+ // For EspoCRM 8.x+
712
+ custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/MyEntity/MyEntity.json
713
+ ```
714
+
715
+ ### Debugging Development Issues
716
+
717
+ ```bash
718
+ # Enable debug mode
719
+ # data/config.php
720
+ 'logger' => [
721
+ 'level' => 'DEBUG',
722
+ ],
723
+
724
+ # Check logs
725
+ tail -f data/logs/espo-$(date +%Y-%m-%d).log
726
+
727
+ # Check for PHP errors
728
+ tail -f /var/log/apache2/error.log # or nginx error log
729
+ ```
730
+
731
+ ### Module Dependencies
732
+
733
+ ```json
734
+ // In manifest.json
735
+ {
736
+ "dependencies": {
737
+ "Advanced Pack": {
738
+ "version": ">=2.14.0"
739
+ }
740
+ }
741
+ }
742
+ ```