crewly 1.11.3 → 1.11.4

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 (171) hide show
  1. package/config/skills/agent/core/accept-task/SKILL.md +35 -7
  2. package/config/skills/agent/core/poll-tasks/execute.sh +44 -9
  3. package/config/skills/agent/core/poll-tasks/execute.test.sh +98 -0
  4. package/config/skills/agent/core/record-learning/execute.sh +92 -3
  5. package/config/skills/agent/core/register-self/SKILL.md +51 -8
  6. package/config/skills/agent/transcribe-audio/SKILL.md +110 -0
  7. package/config/skills/agent/transcribe-audio/execute.sh +223 -0
  8. package/config/skills/agent/transcribe-audio/instructions.md +92 -0
  9. package/config/skills/agent/transcribe-audio/skill.json +22 -0
  10. package/config/skills/orchestrator/assign-task/SKILL.md +40 -6
  11. package/config/skills/orchestrator/broadcast/SKILL.md +45 -8
  12. package/dist/backend/backend/src/constants.d.ts +0 -16
  13. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  14. package/dist/backend/backend/src/constants.js +0 -16
  15. package/dist/backend/backend/src/constants.js.map +1 -1
  16. package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
  17. package/dist/backend/backend/src/controllers/memory/memory.controller.js +3 -10
  18. package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
  19. package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
  20. package/dist/backend/backend/src/controllers/system/system.controller.js +24 -5
  21. package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
  22. package/dist/backend/backend/src/index.d.ts +2 -0
  23. package/dist/backend/backend/src/index.d.ts.map +1 -1
  24. package/dist/backend/backend/src/index.js +124 -1
  25. package/dist/backend/backend/src/index.js.map +1 -1
  26. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  27. package/dist/backend/backend/src/routes/api.routes.js +0 -3
  28. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  29. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  30. package/dist/backend/backend/src/services/agent/agent-registration.service.js +56 -20
  31. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  32. package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +1 -0
  33. package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts.map +1 -1
  34. package/dist/backend/backend/src/services/ai/prompt-modules/index.js +1 -0
  35. package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
  36. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
  37. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +2 -0
  38. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
  39. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
  40. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
  41. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
  42. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
  43. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts +88 -0
  44. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts.map +1 -0
  45. package/dist/backend/backend/src/services/boot/boot-announce.service.js +119 -0
  46. package/dist/backend/backend/src/services/boot/boot-announce.service.js.map +1 -0
  47. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
  48. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +14 -0
  49. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
  50. package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/mcp-server.js +0 -6
  52. package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
  53. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +97 -0
  54. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +1 -0
  55. package/dist/backend/backend/src/services/memory/learning-format.validator.js +209 -0
  56. package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +1 -0
  57. package/dist/backend/backend/src/services/memory/memory.service.d.ts +78 -41
  58. package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
  59. package/dist/backend/backend/src/services/memory/memory.service.js +209 -127
  60. package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
  61. package/dist/backend/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/memory/project-memory.service.js +37 -9
  63. package/dist/backend/backend/src/services/memory/project-memory.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
  65. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +29 -0
  66. package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
  67. package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
  68. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +9 -0
  69. package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
  70. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts +86 -0
  71. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts.map +1 -0
  72. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js +214 -0
  73. package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js.map +1 -0
  74. package/dist/backend/backend/src/services/sop/sop.service.d.ts +70 -2
  75. package/dist/backend/backend/src/services/sop/sop.service.d.ts.map +1 -1
  76. package/dist/backend/backend/src/services/sop/sop.service.js +93 -3
  77. package/dist/backend/backend/src/services/sop/sop.service.js.map +1 -1
  78. package/dist/backend/backend/src/services/task-pool/claim.service.d.ts +41 -0
  79. package/dist/backend/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
  80. package/dist/backend/backend/src/services/task-pool/claim.service.js +72 -0
  81. package/dist/backend/backend/src/services/task-pool/claim.service.js.map +1 -1
  82. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
  83. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  84. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +20 -0
  85. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  86. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts.map +1 -1
  87. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js +11 -0
  88. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js.map +1 -1
  89. package/dist/backend/backend/src/services/telegram/telegram.service.d.ts.map +1 -1
  90. package/dist/backend/backend/src/services/telegram/telegram.service.js +24 -2
  91. package/dist/backend/backend/src/services/telegram/telegram.service.js.map +1 -1
  92. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -1
  93. package/dist/backend/backend/src/services/v3/mission-reminder.service.js +18 -18
  94. package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -1
  95. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +10 -0
  96. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
  97. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +20 -12
  98. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
  99. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -1
  100. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +12 -3
  101. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -1
  102. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +15 -5
  103. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -1
  104. package/dist/backend/backend/src/services/wiki/wiki-query.service.js +31 -50
  105. package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -1
  106. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +16 -0
  107. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
  108. package/dist/backend/backend/src/services/wiki/wiki-search.service.js +20 -0
  109. package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -1
  110. package/dist/backend/backend/src/types/settings.types.d.ts +8 -0
  111. package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
  112. package/dist/backend/backend/src/types/settings.types.js +2 -0
  113. package/dist/backend/backend/src/types/settings.types.js.map +1 -1
  114. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +23 -0
  115. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  116. package/dist/backend/backend/src/types/v2/work-item.types.js +29 -0
  117. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  118. package/dist/cli/backend/src/constants.d.ts +0 -16
  119. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  120. package/dist/cli/backend/src/constants.js +0 -16
  121. package/dist/cli/backend/src/constants.js.map +1 -1
  122. package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
  123. package/dist/cli/backend/src/services/mcp-server.js +0 -6
  124. package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
  125. package/dist/cli/backend/src/services/memory/memory.service.d.ts +78 -41
  126. package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
  127. package/dist/cli/backend/src/services/memory/memory.service.js +209 -127
  128. package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
  129. package/dist/cli/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
  130. package/dist/cli/backend/src/services/memory/project-memory.service.js +37 -9
  131. package/dist/cli/backend/src/services/memory/project-memory.service.js.map +1 -1
  132. package/dist/cli/backend/src/services/task-pool/claim.service.d.ts +41 -0
  133. package/dist/cli/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
  134. package/dist/cli/backend/src/services/task-pool/claim.service.js +72 -0
  135. package/dist/cli/backend/src/services/task-pool/claim.service.js.map +1 -1
  136. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
  137. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  138. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +20 -0
  139. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  140. package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
  141. package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
  142. package/dist/cli/backend/src/services/wiki/schema-loader.service.js +183 -0
  143. package/dist/cli/backend/src/services/wiki/schema-loader.service.js.map +1 -0
  144. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
  145. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
  146. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js +212 -0
  147. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
  148. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts +43 -0
  149. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts.map +1 -0
  150. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js +67 -0
  151. package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js.map +1 -0
  152. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts +166 -0
  153. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -0
  154. package/dist/cli/backend/src/services/wiki/wiki-search.service.js +379 -0
  155. package/dist/cli/backend/src/services/wiki/wiki-search.service.js.map +1 -0
  156. package/dist/cli/backend/src/services/wiki/wiki.types.d.ts +84 -0
  157. package/dist/cli/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
  158. package/dist/cli/backend/src/services/wiki/wiki.types.js +10 -0
  159. package/dist/cli/backend/src/services/wiki/wiki.types.js.map +1 -0
  160. package/dist/cli/backend/src/types/settings.types.d.ts +8 -0
  161. package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
  162. package/dist/cli/backend/src/types/settings.types.js +2 -0
  163. package/dist/cli/backend/src/types/settings.types.js.map +1 -1
  164. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +23 -0
  165. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  166. package/dist/cli/backend/src/types/v2/work-item.types.js +29 -0
  167. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  168. package/frontend/dist/assets/{index-44266b5d.css → index-8205ea5e.css} +1 -1
  169. package/frontend/dist/assets/{index-4099a91c.js → index-890d3f9d.js} +289 -289
  170. package/frontend/dist/index.html +2 -2
  171. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Accept Task
3
- description: Accept and take the next available task from the task queue.
3
+ description: "Accept and take the next available task from the task queue. Use when an agent is idle and ready to pick up the highest-priority unassigned task. For assigning tasks to specific agents, use assign-task instead."
4
4
  version: 1.0.0
5
5
  category: task-management
6
6
  skillType: claude-skill
@@ -37,21 +37,49 @@ execution:
37
37
 
38
38
  # Accept Task
39
39
 
40
- Accept and take the next available task from the task queue. The backend assigns the highest-priority unassigned task to your session.
40
+ Accept and take the next available task from the task queue. The backend selects the highest-priority unassigned task and assigns it to the requesting agent's session.
41
+
42
+ ## When to Use
43
+
44
+ Run this skill when the agent is idle and ready to pick up new work. The backend automatically selects the highest-priority unassigned task; assignment is keyed by the agent's session.
41
45
 
42
46
  ## Parameters
43
47
 
44
48
  | Parameter | Required | Description |
45
49
  |-----------|----------|-------------|
46
- | `sessionName` | Yes | Your agent session name |
47
- | `teamMemberId` | No | Your team member ID for targeted assignment |
50
+ | `sessionName` | Yes | The agent's session name (e.g., `dev-1`) |
51
+ | `projectPath` | No | Project path to scope task selection |
52
+ | `taskGroup` | No | Task group to filter available tasks |
53
+
54
+ ## Examples
48
55
 
49
- ## Example
56
+ ### Accept the next available task
50
57
 
51
58
  ```bash
52
- bash config/skills/agent/accept-task/execute.sh '{"sessionName":"dev-1"}'
59
+ bash config/skills/agent/core/accept-task/execute.sh '{"sessionName":"dev-1"}'
60
+ ```
61
+
62
+ ### Accept within a specific project and task group
63
+
64
+ ```bash
65
+ bash config/skills/agent/core/accept-task/execute.sh '{"sessionName":"dev-1","projectPath":"/path/to/project","taskGroup":"frontend"}'
53
66
  ```
54
67
 
55
68
  ## Output
56
69
 
57
- JSON with the assigned task details including path, description, and priority. Returns an empty result if no tasks are available.
70
+ JSON object with the assigned task details including task ID, description, priority, and status. Returns an empty result if no tasks are available.
71
+
72
+ ## Error Handling
73
+
74
+ | Error | Cause | Solution |
75
+ |-------|-------|----------|
76
+ | `Missing required parameter: sessionName` | `sessionName` not provided | Include `sessionName` in the JSON input |
77
+ | `curl failed with exit code N` | Backend not running | Start the Crewly backend |
78
+ | Empty result | No unassigned tasks in queue | Wait and retry, or create new tasks |
79
+
80
+ ## Related Skills
81
+
82
+ - `read-task` — view details of a specific task without accepting it
83
+ - `complete-task` — mark an accepted task as done
84
+ - `report-progress` — update progress on the current task
85
+ - `get-my-tasks` — list all tasks assigned to the agent
@@ -64,6 +64,15 @@ fi
64
64
 
65
65
  # ---------------------------------------------------------------------------
66
66
  # Step 1: Query available WorkItems from Task Pool
67
+ #
68
+ # Primary query: owner=agent (normal task-pool queue).
69
+ # Fallback query: target=$SESSION_NAME — picks up orchestrator/TL-owned
70
+ # WorkItems delegated directly to this agent. Without the fallback,
71
+ # direct delegations would never be seen by poll-tasks because they
72
+ # do not match owner=agent. (D8 defect: previously the target= query
73
+ # only fired on HTTP error from the primary, not on count=0, so direct
74
+ # delegations sat in the pool indefinitely while the agent reported
75
+ # "no work".)
67
76
  # ---------------------------------------------------------------------------
68
77
 
69
78
  QUERY_PARAMS="?types=${TYPES}&owner=agent"
@@ -77,6 +86,22 @@ AVAILABLE_RESPONSE=$(api_call GET "/task-pool${QUERY_PARAMS}" 2>&1) || {
77
86
 
78
87
  AVAILABLE_COUNT=$(printf '%s' "$AVAILABLE_RESPONSE" | jq -r '.count // 0')
79
88
 
89
+ # When the primary owner=agent query yields no items, also probe the
90
+ # target= namespace before declaring no work. If the fallback returns
91
+ # items, they are by definition pinned to this agent — record the first
92
+ # item's id so Step 3 can claim it explicitly (the server-side FIFO
93
+ # picker filters owner=agent and would otherwise ignore these items).
94
+ TARGET_PINNED_ID=""
95
+ if [ "$AVAILABLE_COUNT" -eq 0 ]; then
96
+ TARGET_RESPONSE=$(api_call GET "/task-pool?types=${TYPES}&target=${SESSION_NAME}" 2>&1) || TARGET_RESPONSE=""
97
+ TARGET_COUNT=$(printf '%s' "$TARGET_RESPONSE" | jq -r '.count // 0' 2>/dev/null || echo 0)
98
+ if [ "$TARGET_COUNT" -gt 0 ]; then
99
+ AVAILABLE_RESPONSE="$TARGET_RESPONSE"
100
+ AVAILABLE_COUNT="$TARGET_COUNT"
101
+ TARGET_PINNED_ID=$(printf '%s' "$TARGET_RESPONSE" | jq -r '(.data // [])[0].id // empty')
102
+ fi
103
+ fi
104
+
80
105
  if [ "$AVAILABLE_COUNT" -eq 0 ]; then
81
106
  # No available work — return early
82
107
  jq -n \
@@ -123,15 +148,25 @@ fi
123
148
  # We pass our agentId and filters so the server picks the best match.
124
149
  # ---------------------------------------------------------------------------
125
150
 
126
- CLAIM_BODY=$(jq -n \
127
- --arg agentId "$SESSION_NAME" \
128
- --arg types "$TYPES" \
129
- '{
130
- agentId: $agentId,
131
- filters: {
132
- types: ($types | split(","))
133
- }
134
- }')
151
+ # When a target-pinned item was found via the fallback query, claim it
152
+ # by explicit workItemId — the server-side FIFO picker filters owner=agent
153
+ # and would not return orchestrator-owned items via the unfiltered claim.
154
+ if [ -n "$TARGET_PINNED_ID" ]; then
155
+ CLAIM_BODY=$(jq -n \
156
+ --arg agentId "$SESSION_NAME" \
157
+ --arg workItemId "$TARGET_PINNED_ID" \
158
+ '{agentId: $agentId, workItemId: $workItemId}')
159
+ else
160
+ CLAIM_BODY=$(jq -n \
161
+ --arg agentId "$SESSION_NAME" \
162
+ --arg types "$TYPES" \
163
+ '{
164
+ agentId: $agentId,
165
+ filters: {
166
+ types: ($types | split(","))
167
+ }
168
+ }')
169
+ fi
135
170
 
136
171
  CLAIM_RESPONSE=$(api_call POST "/task-pool/claim" "$CLAIM_BODY" 2>&1) || {
137
172
  CLAIM_ERROR="$CLAIM_RESPONSE"
@@ -199,6 +199,104 @@ else
199
199
  fi
200
200
  assert_eq "empty types uses role default" "delegate,project_task,review" "$FINAL_TYPES2"
201
201
 
202
+ # ---------------------------------------------------------------------------
203
+ # Test 7: D8 fallback — target= query when owner=agent yields zero
204
+ #
205
+ # Mirrors the production logic: when the primary owner=agent response has
206
+ # count=0, we should adopt the target= response if it contains any items,
207
+ # and record the first item's id as TARGET_PINNED_ID so the claim step
208
+ # can claim by workItemId rather than by FIFO filters.
209
+ # ---------------------------------------------------------------------------
210
+ echo "Test 7: D8 fallback for orchestrator-owned target items"
211
+
212
+ OWNER_AGENT_EMPTY='{"success":true,"data":[],"count":0}'
213
+ TARGET_RESPONSE_HIT='{"success":true,"data":[
214
+ {"id":"wi-orc-1","type":"delegate","owner":"orchestrator","target":"agent-1","status":"queued"},
215
+ {"id":"wi-orc-2","type":"delegate","owner":"orchestrator","target":"agent-1","status":"queued"}
216
+ ],"count":2}'
217
+
218
+ # Simulate the merge step
219
+ AVAILABLE_RESPONSE_SIM="$OWNER_AGENT_EMPTY"
220
+ AVAILABLE_COUNT_SIM=$(printf '%s' "$AVAILABLE_RESPONSE_SIM" | jq -r '.count // 0')
221
+ TARGET_PINNED_ID_SIM=""
222
+ if [ "$AVAILABLE_COUNT_SIM" -eq 0 ]; then
223
+ TARGET_RESPONSE_SIM="$TARGET_RESPONSE_HIT"
224
+ TARGET_COUNT_SIM=$(printf '%s' "$TARGET_RESPONSE_SIM" | jq -r '.count // 0')
225
+ if [ "$TARGET_COUNT_SIM" -gt 0 ]; then
226
+ AVAILABLE_RESPONSE_SIM="$TARGET_RESPONSE_SIM"
227
+ AVAILABLE_COUNT_SIM="$TARGET_COUNT_SIM"
228
+ TARGET_PINNED_ID_SIM=$(printf '%s' "$TARGET_RESPONSE_SIM" | jq -r '(.data // [])[0].id // empty')
229
+ fi
230
+ fi
231
+
232
+ assert_eq "fallback adopts target response count" "2" "$AVAILABLE_COUNT_SIM"
233
+ assert_eq "fallback pins first target item id" "wi-orc-1" "$TARGET_PINNED_ID_SIM"
234
+
235
+ # When BOTH queries are empty, AVAILABLE_COUNT stays 0 and no pin is set
236
+ AVAILABLE_RESPONSE_EMPTY="$OWNER_AGENT_EMPTY"
237
+ AVAILABLE_COUNT_EMPTY=$(printf '%s' "$AVAILABLE_RESPONSE_EMPTY" | jq -r '.count // 0')
238
+ TARGET_PINNED_ID_EMPTY=""
239
+ if [ "$AVAILABLE_COUNT_EMPTY" -eq 0 ]; then
240
+ TARGET_RESPONSE_EMPTY='{"success":true,"data":[],"count":0}'
241
+ TARGET_COUNT_EMPTY=$(printf '%s' "$TARGET_RESPONSE_EMPTY" | jq -r '.count // 0')
242
+ if [ "$TARGET_COUNT_EMPTY" -gt 0 ]; then
243
+ AVAILABLE_RESPONSE_EMPTY="$TARGET_RESPONSE_EMPTY"
244
+ AVAILABLE_COUNT_EMPTY="$TARGET_COUNT_EMPTY"
245
+ TARGET_PINNED_ID_EMPTY=$(printf '%s' "$TARGET_RESPONSE_EMPTY" | jq -r '(.data // [])[0].id // empty')
246
+ fi
247
+ fi
248
+ assert_eq "both-empty leaves count at 0" "0" "$AVAILABLE_COUNT_EMPTY"
249
+ assert_eq "both-empty leaves pin empty" "" "$TARGET_PINNED_ID_EMPTY"
250
+
251
+ # When owner=agent has items already, fallback must NOT fire
252
+ OWNER_AGENT_HIT='{"success":true,"data":[
253
+ {"id":"wi-agent-1","type":"project_task","owner":"agent","status":"queued"}
254
+ ],"count":1}'
255
+ AVAILABLE_RESPONSE_PRI="$OWNER_AGENT_HIT"
256
+ AVAILABLE_COUNT_PRI=$(printf '%s' "$AVAILABLE_RESPONSE_PRI" | jq -r '.count // 0')
257
+ TARGET_PINNED_ID_PRI=""
258
+ if [ "$AVAILABLE_COUNT_PRI" -eq 0 ]; then
259
+ TARGET_PINNED_ID_PRI="should-not-be-set"
260
+ fi
261
+ assert_eq "primary-hit keeps count=1" "1" "$AVAILABLE_COUNT_PRI"
262
+ assert_eq "primary-hit leaves pin empty (no fallback)" "" "$TARGET_PINNED_ID_PRI"
263
+
264
+ # ---------------------------------------------------------------------------
265
+ # Test 8: Claim body shape — workItemId vs filters
266
+ #
267
+ # When TARGET_PINNED_ID is set, the claim body must include workItemId.
268
+ # Otherwise it uses the FIFO filters shape. Both are accepted by the
269
+ # /task-pool/claim endpoint, but only the workItemId form will claim
270
+ # orchestrator-owned items.
271
+ # ---------------------------------------------------------------------------
272
+ echo "Test 8: Claim body shape"
273
+
274
+ build_claim_body() {
275
+ local pinned="$1" session="$2" types="$3"
276
+ if [ -n "$pinned" ]; then
277
+ jq -nc \
278
+ --arg agentId "$session" \
279
+ --arg workItemId "$pinned" \
280
+ '{agentId: $agentId, workItemId: $workItemId}'
281
+ else
282
+ jq -nc \
283
+ --arg agentId "$session" \
284
+ --arg types "$types" \
285
+ '{agentId: $agentId, filters: {types: ($types | split(","))}}'
286
+ fi
287
+ }
288
+
289
+ PINNED_BODY=$(build_claim_body "wi-orc-1" "agent-1" "delegate,project_task")
290
+ assert_json_field "pinned body has workItemId" "$PINNED_BODY" ".workItemId" "wi-orc-1"
291
+ assert_json_field "pinned body has agentId" "$PINNED_BODY" ".agentId" "agent-1"
292
+ assert_json_field "pinned body has no filters" "$PINNED_BODY" ".filters" "null"
293
+
294
+ FIFO_BODY=$(build_claim_body "" "agent-1" "delegate,project_task")
295
+ assert_json_field "fifo body has agentId" "$FIFO_BODY" ".agentId" "agent-1"
296
+ assert_json_field "fifo body has no workItemId" "$FIFO_BODY" ".workItemId" "null"
297
+ assert_json_field "fifo body types[0]" "$FIFO_BODY" ".filters.types[0]" "delegate"
298
+ assert_json_field "fifo body types[1]" "$FIFO_BODY" ".filters.types[1]" "project_task"
299
+
202
300
  # ---------------------------------------------------------------------------
203
301
  # Summary
204
302
  # ---------------------------------------------------------------------------
@@ -1,6 +1,18 @@
1
1
  #!/bin/bash
2
2
  # Record a learning or insight for team knowledge sharing.
3
3
  # Supports CLI flags (preferred) and legacy JSON.
4
+ #
5
+ # Karpathy-lite preflight (ARCHIVIST-V2.f1):
6
+ # Before persisting, the learning text is checked against the 4 rules of
7
+ # the Karpathy-lite Entity-Centric format defined in SKILL.md:
8
+ # 1. [[Entity]] opener — HARD reject (always).
9
+ # 2. Sentence count 1..3 — soft warn (HARD with --strict).
10
+ # 3. Linked or sourced — soft warn (HARD with --strict).
11
+ # 4. No log-style "I/We …" opener — soft warn (HARD with --strict).
12
+ #
13
+ # Flags:
14
+ # --strict Escalate rules 2..4 to hard rejects (CI / Archivist v2).
15
+ # --no-preflight Skip the local preflight (escape hatch).
4
16
  set -euo pipefail
5
17
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
18
  source "${SCRIPT_DIR}/../../_common/lib.sh"
@@ -10,6 +22,8 @@ AGENT_ID=""
10
22
  AGENT_ROLE=""
11
23
  PROJECT_PATH=""
12
24
  LEARNING=""
25
+ STRICT=0
26
+ SKIP_PREFLIGHT=0
13
27
 
14
28
  # Detect legacy JSON argument
15
29
  if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
@@ -39,12 +53,32 @@ while [[ $# -gt 0 ]]; do
39
53
  LEARNING="$(cat "$2")"
40
54
  shift 2
41
55
  ;;
56
+ --strict)
57
+ STRICT=1
58
+ shift
59
+ ;;
60
+ --no-preflight)
61
+ SKIP_PREFLIGHT=1
62
+ shift
63
+ ;;
42
64
  --json|-j)
43
65
  INPUT_JSON="$2"
44
66
  shift 2
45
67
  ;;
46
68
  --help|-h)
47
- echo "Usage: execute.sh --agent dev-1 --role developer --project /path --learning 'What I learned'"
69
+ cat <<'EOF'
70
+ Usage: execute.sh --agent <id> --role <role> --project <path> --learning '<text>' [--strict] [--no-preflight]
71
+
72
+ Karpathy-lite preflight rules (see SKILL.md):
73
+ 1. [[Entity]] opener (HARD)
74
+ 2. 1..3 sentences (soft, hard with --strict)
75
+ 3. Linked or sourced (soft, hard with --strict)
76
+ 4. No log-style "I/We" opener (soft, hard with --strict)
77
+
78
+ Flags:
79
+ --strict Escalate rules 2..4 to hard rejects.
80
+ --no-preflight Skip local preflight checks (escape hatch).
81
+ EOF
48
82
  exit 0
49
83
  ;;
50
84
  --)
@@ -79,6 +113,10 @@ if [ -n "$INPUT_JSON" ]; then
79
113
  [ -z "$AGENT_ROLE" ] && AGENT_ROLE=$(printf '%s' "$INPUT" | jq -r '.agentRole // empty')
80
114
  [ -z "$PROJECT_PATH" ] && PROJECT_PATH=$(printf '%s' "$INPUT" | jq -r '.projectPath // empty')
81
115
  [ -z "$LEARNING" ] && LEARNING=$(printf '%s' "$INPUT" | jq -r '.learning // empty')
116
+ if [ "$STRICT" -eq 0 ]; then
117
+ JSON_STRICT=$(printf '%s' "$INPUT" | jq -r '.strict // empty')
118
+ [ "$JSON_STRICT" = "true" ] && STRICT=1
119
+ fi
82
120
  fi
83
121
 
84
122
  require_param "agentId (--agent)" "$AGENT_ID"
@@ -86,13 +124,64 @@ require_param "agentRole (--role)" "$AGENT_ROLE"
86
124
  require_param "projectPath (--project)" "$PROJECT_PATH"
87
125
  require_param "learning (--learning)" "$LEARNING"
88
126
 
127
+ # ---------- Karpathy-lite preflight ----------
128
+ # Local checks for fast feedback. Canonical implementation lives in
129
+ # backend/src/services/memory/learning-format.validator.ts (full Jest tests).
130
+ # This bash mirror covers the most common rules (1 + 4) so agents get immediate
131
+ # stderr feedback without paying an HTTP round-trip.
132
+ if [ "$SKIP_PREFLIGHT" -eq 0 ]; then
133
+ PREFLIGHT_FAIL=0
134
+
135
+ # Rule 1 — [[Entity]] opener (HARD always).
136
+ TRIMMED_LEARNING="${LEARNING#"${LEARNING%%[![:space:]]*}"}" # left-trim whitespace
137
+ if ! [[ "$TRIMMED_LEARNING" =~ ^\[\[[^\]]+\]\] ]]; then
138
+ SNIPPET="${TRIMMED_LEARNING:0:80}"
139
+ [ "${#TRIMMED_LEARNING}" -gt 80 ] && SNIPPET="${SNIPPET}…"
140
+ {
141
+ echo "✗ record-learning rule 1 (entity_opener): missing leading [[Entity]] opener — required for Archivist v2 join key."
142
+ echo " Got: \"${SNIPPET}\""
143
+ echo " Fix: Lead with [[Entity Name]]. Example: \"[[Fts5IndexService]] FTS5 rank is negative; invert. PR #320\""
144
+ echo " See: config/skills/agent/core/record-learning/SKILL.md § Mandated Format: Karpathy-lite"
145
+ } >&2
146
+ PREFLIGHT_FAIL=1
147
+ fi
148
+
149
+ # Rule 4 — log-style "I/We" opener (soft warn; hard with --strict).
150
+ STRIPPED_LEARNING="${TRIMMED_LEARNING}"
151
+ if [[ "$STRIPPED_LEARNING" =~ ^\[\[[^\]]+\]\][[:space:]]* ]]; then
152
+ PREFIX_MATCH="${BASH_REMATCH[0]}"
153
+ STRIPPED_LEARNING="${STRIPPED_LEARNING#"$PREFIX_MATCH"}"
154
+ fi
155
+ if [[ "$STRIPPED_LEARNING" =~ ^[Ii][[:space:]\'] ]] || [[ "$STRIPPED_LEARNING" =~ ^[Ww]e[[:space:]\'] ]]; then
156
+ {
157
+ echo "⚠ record-learning rule 4 (no_log_style): log-style opener detected (\"I …\" / \"We …\")."
158
+ echo " Fix: Lead with [[Entity]] then state the insight. Avoid first-person narrative."
159
+ echo " See: config/skills/agent/core/record-learning/SKILL.md § Mandated Format: Karpathy-lite"
160
+ } >&2
161
+ if [ "$STRICT" -eq 1 ]; then
162
+ PREFLIGHT_FAIL=1
163
+ fi
164
+ fi
165
+
166
+ if [ "$PREFLIGHT_FAIL" -eq 1 ]; then
167
+ echo "record-learning preflight rejected. Re-run with corrected text, or use --no-preflight to bypass." >&2
168
+ exit 2
169
+ fi
170
+ fi
171
+ # ---------- end preflight ----------
172
+
89
173
  # Build body using env vars for safe escaping
90
174
  export _LRN_AGENT="$AGENT_ID"
91
175
  export _LRN_ROLE="$AGENT_ROLE"
92
176
  export _LRN_PROJECT="$PROJECT_PATH"
93
177
  export _LRN_CONTENT="$LEARNING"
178
+ export _LRN_STRICT="$STRICT"
94
179
 
95
- BODY=$(jq -n '{agentId: env._LRN_AGENT, agentRole: env._LRN_ROLE, projectPath: env._LRN_PROJECT, learning: env._LRN_CONTENT}')
96
- unset _LRN_AGENT _LRN_ROLE _LRN_PROJECT _LRN_CONTENT
180
+ if [ "$STRICT" -eq 1 ]; then
181
+ BODY=$(jq -n '{agentId: env._LRN_AGENT, agentRole: env._LRN_ROLE, projectPath: env._LRN_PROJECT, learning: env._LRN_CONTENT, strict: true}')
182
+ else
183
+ BODY=$(jq -n '{agentId: env._LRN_AGENT, agentRole: env._LRN_ROLE, projectPath: env._LRN_PROJECT, learning: env._LRN_CONTENT}')
184
+ fi
185
+ unset _LRN_AGENT _LRN_ROLE _LRN_PROJECT _LRN_CONTENT _LRN_STRICT
97
186
 
98
187
  api_call POST "/memory/record-learning" "$BODY"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Register Self
3
- description: Register the agent as active with the Crewly backend. Must be called on startup.
3
+ description: "Register the agent as active with the Crewly backend on startup. Use when an agent first launches and needs to join the team and become visible to the orchestrator. For confirming responsiveness after registration, use heartbeat instead."
4
4
  version: 1.0.0
5
5
  category: system
6
6
  skillType: claude-skill
@@ -36,19 +36,62 @@ execution:
36
36
 
37
37
  # Register Self
38
38
 
39
- Register this agent as active with the Crewly backend. This must be the first skill you run on startup.
39
+ Register the agent as active with the Crewly backend. This must be the first skill run on agent startup to join the team and become visible to the orchestrator.
40
+
41
+ ## When to Use
42
+
43
+ Run this skill immediately after the agent process starts. Registration makes the agent visible in the team dashboard and enables it to receive tasks, messages, and heartbeat checks. Without registration, the orchestrator cannot assign work to the agent.
40
44
 
41
45
  ## Parameters
42
46
 
43
47
  | Parameter | Required | Description |
44
48
  |-----------|----------|-------------|
45
- | `role` | Yes | Agent role (e.g., "developer", "qa", "tpm") |
46
- | `sessionName` | Yes | Your session name (from your identity) |
47
- | `teamMemberId` | No | Your team member ID |
48
- | `claudeSessionId` | No | Claude session ID for resume support |
49
+ | `sessionName` / `--session` | Yes | Agent session name (e.g., `dev-1`) |
50
+ | `role` / `--role` | Yes | Agent role: `developer`, `qa`, `tpm`, `designer`, `product-manager`, etc. |
51
+ | `teamMemberId` / `--team-member` | No | Team member UUID for identity linking |
52
+ | `claudeSessionId` / `--claude-session` | No | Claude session ID for resume support |
53
+
54
+ ## Examples
55
+
56
+ ### Register using CLI flags (preferred)
57
+
58
+ ```bash
59
+ bash config/skills/agent/core/register-self/execute.sh --session dev-1 --role developer
60
+ ```
61
+
62
+ ### Register with all options
63
+
64
+ ```bash
65
+ bash config/skills/agent/core/register-self/execute.sh --session dev-1 --role qa --team-member tm-abc123 --claude-session cs-xyz789
66
+ ```
49
67
 
50
- ## Example
68
+ ### Register using legacy JSON argument
51
69
 
52
70
  ```bash
53
- bash config/skills/agent/core/register-self/execute.sh '{"role":"developer","sessionName":"dev-1"}'
71
+ bash config/skills/agent/core/register-self/execute.sh '{"sessionName":"dev-1","role":"developer"}'
54
72
  ```
73
+
74
+ ### Register via stdin pipe
75
+
76
+ ```bash
77
+ echo '{"sessionName":"dev-1","role":"developer"}' | bash config/skills/agent/core/register-self/execute.sh
78
+ ```
79
+
80
+ ## Output
81
+
82
+ JSON confirmation from `POST /api/teams/members/register` containing the registered agent's details including session name, assigned role, and team membership status.
83
+
84
+ ## Error Handling
85
+
86
+ | Error | Cause | Solution |
87
+ |-------|-------|----------|
88
+ | `Missing required parameter: sessionName (--session)` | Session name not provided | Pass `--session <name>` or include `sessionName` in JSON |
89
+ | `Missing required parameter: role (--role)` | Role not provided | Pass `--role <role>` or include `role` in JSON |
90
+ | `Unknown argument: <arg>` | Unrecognized CLI flag | Check spelling; run with `--help` for usage |
91
+ | `curl failed with exit code N` | Backend not running | Start the Crewly backend |
92
+
93
+ ## Related Skills
94
+
95
+ - `heartbeat` — confirm the agent is still responsive after registration
96
+ - `get-my-context` — retrieve the agent's current role and team context
97
+ - `accept-task` — pick up the first available task after registering
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: transcribe-audio
3
+ description: Transcribe a local audio (or video) file to text with timestamps using Whisper. Defaults to local whisper.cpp (free, offline, word/segment-level timestamps) and automatically falls back to the OpenAI Whisper API (whisper-1) when the local engine is not installed. Any agent can call it for meetings, podcasts, voice notes, interviews, or video audio tracks.
4
+ category: content
5
+ assignableRoles:
6
+ - "*"
7
+ version: "1.0.0"
8
+ tags:
9
+ - audio
10
+ - transcribe
11
+ - transcription
12
+ - whisper
13
+ - whisper.cpp
14
+ - openai
15
+ - speech-to-text
16
+ - timestamps
17
+ ---
18
+
19
+ # Transcribe Audio (Whisper)
20
+
21
+ Transcribe a **local audio or video file** into text with timestamps. This is the
22
+ general-purpose Whisper-based speech-to-text skill — distinct from
23
+ `xiaoyuzhoufm-transcript` (which is the Gemini-based podcast/video research skill;
24
+ this skill does **not** replace it).
25
+
26
+ ## Engines
27
+
28
+ | Engine | When used | Cost | Network | Timestamps |
29
+ |--------|-----------|------|---------|------------|
30
+ | **whisper.cpp** (local, `large-v3-turbo`) | Default — used whenever the binary + model are present | Free | Offline | Segment + word-level |
31
+ | **OpenAI Whisper API** (`whisper-1`) | Fallback — used when local is unavailable, or forced via `engine:"openai"` | ~$0.006/min | Required | Segment + word-level |
32
+
33
+ **Default = `auto`:** prefer local whisper.cpp (free, private, offline, no per-use
34
+ cost — ideal for unattended agents), and transparently fall back to the OpenAI API
35
+ when the local engine is not installed. This gives zero-cost transcription where the
36
+ local model exists and zero-install reliability everywhere else. Force a specific
37
+ engine with `engine:"local"` or `engine:"openai"`.
38
+
39
+ ## Usage
40
+
41
+ ```bash
42
+ # Auto engine (local if available, else OpenAI). Prints JSON to stdout.
43
+ bash execute.sh '{"audioFile":"/path/to/recording.m4a"}'
44
+
45
+ # Save as Markdown (timestamped transcript)
46
+ bash execute.sh '{"audioFile":"/path/to/recording.mp3","outputFile":"./transcript.md"}'
47
+
48
+ # Save as JSON (full structured segments)
49
+ bash execute.sh '{"audioFile":"/path/to/recording.wav","outputFile":"./transcript.json"}'
50
+
51
+ # Language hint (ISO-639-1, e.g. en / zh / ja). Default: auto-detect
52
+ bash execute.sh '{"audioFile":"/path/to/recording.m4a","language":"zh"}'
53
+
54
+ # Force a specific engine
55
+ bash execute.sh '{"audioFile":"/path/to/x.wav","engine":"local"}'
56
+ bash execute.sh '{"audioFile":"/path/to/x.wav","engine":"openai"}'
57
+
58
+ # A video file works too — the audio track is extracted automatically
59
+ bash execute.sh '{"audioFile":"/path/to/clip.mp4"}'
60
+ ```
61
+
62
+ ## Parameters
63
+
64
+ | Parameter | Required | Description |
65
+ |-----------|----------|-------------|
66
+ | `audioFile` | Yes | Path to a local audio or video file (m4a, mp3, wav, aac, ogg, flac, mp4, mov…) |
67
+ | `outputFile` | No | Save the transcript to this path. `.json` → structured JSON; anything else → Markdown |
68
+ | `language` | No | Language hint (ISO-639-1). Default: auto-detect |
69
+ | `engine` | No | `auto` (default), `local`, or `openai` |
70
+
71
+ ## Output (stdout JSON)
72
+
73
+ ```json
74
+ {
75
+ "success": true,
76
+ "engine": "whisper.cpp",
77
+ "language": "en",
78
+ "durationSec": 11.0,
79
+ "text": "Full transcript as one block of text...",
80
+ "segments": [
81
+ { "start": 0.0, "end": 2.5, "text": "Hello everyone", "speaker": "Unknown" }
82
+ ],
83
+ "segmentCount": 1,
84
+ "outputFile": "/abs/path/transcript.md"
85
+ }
86
+ ```
87
+
88
+ `speaker` is `"Unknown"` unless the chosen engine returns diarization (neither
89
+ default engine performs speaker separation today; the field is reserved so
90
+ downstream consumers have a stable shape).
91
+
92
+ ## Dependencies & Setup
93
+
94
+ - **`ffmpeg`** — required for both engines (audio is normalized to 16 kHz mono WAV).
95
+ Install: `brew install ffmpeg`.
96
+ - **Local engine (`whisper.cpp`)** — needs the `whisper-cli` binary and a model file:
97
+ - Binary: `brew install whisper-cpp` (provides `whisper-cli`). Override with `FLOPOST_WHISPER_BIN`.
98
+ - Model: `ggml-large-v3-turbo-q5_0.bin` in `~/.flopost/whisper/` or `~/.cache/whisper-models/`. Override with `FLOPOST_WHISPER_MODEL`.
99
+ - If the binary or model is missing, the skill falls back to OpenAI (or reports a clear hint when `engine:"local"` is forced).
100
+ - **OpenAI engine** — needs an OpenAI API key. Resolution order:
101
+ 1. `OPENAI_API_KEY` environment variable (injected by Crewly secrets).
102
+ 2. Crewly Settings → API Keys (`GET http://localhost:8787/api/settings` → `data.apiKeys.global.openai`).
103
+ No key is ever hard-coded.
104
+
105
+ ## Notes
106
+
107
+ - Engine detection and key resolution lift the proven logic from Flopost
108
+ (`desktop/server/whisperModule.ts` and `service/lib/video/transcriptionService.ts`).
109
+ - Long files: whisper.cpp handles arbitrary length locally. The OpenAI API enforces a
110
+ 25 MB upload limit; for larger files prefer the local engine.