crewly 1.11.2 → 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.
- package/config/skills/agent/core/accept-task/SKILL.md +35 -7
- package/config/skills/agent/core/poll-tasks/execute.sh +44 -9
- package/config/skills/agent/core/poll-tasks/execute.test.sh +98 -0
- package/config/skills/agent/core/record-learning/execute.sh +92 -3
- package/config/skills/agent/core/register-self/SKILL.md +51 -8
- package/config/skills/agent/transcribe-audio/SKILL.md +110 -0
- package/config/skills/agent/transcribe-audio/execute.sh +223 -0
- package/config/skills/agent/transcribe-audio/instructions.md +92 -0
- package/config/skills/agent/transcribe-audio/skill.json +22 -0
- package/config/skills/orchestrator/assign-task/SKILL.md +40 -6
- package/config/skills/orchestrator/broadcast/SKILL.md +45 -8
- package/dist/backend/backend/src/constants.d.ts +0 -16
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +0 -16
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.js +3 -10
- package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/system.controller.js +24 -5
- package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +57 -2
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +2 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +124 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +0 -3
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +56 -20
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +2 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
- package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts +88 -0
- package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/boot/boot-announce.service.js +119 -0
- package/dist/backend/backend/src/services/boot/boot-announce.service.js.map +1 -0
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +14 -0
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
- package/dist/backend/backend/src/services/mcp-server.js +0 -6
- package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
- package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +97 -0
- package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/learning-format.validator.js +209 -0
- package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +1 -0
- package/dist/backend/backend/src/services/memory/memory.service.d.ts +78 -41
- package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.js +209 -127
- package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/project-memory.service.js +37 -9
- package/dist/backend/backend/src/services/memory/project-memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.d.ts +46 -0
- package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.js +51 -0
- package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +29 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +9 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts +86 -0
- package/dist/backend/backend/src/services/session/runtime-pid-registry.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js +214 -0
- package/dist/backend/backend/src/services/session/runtime-pid-registry.service.js.map +1 -0
- package/dist/backend/backend/src/services/sop/sop.service.d.ts +70 -2
- package/dist/backend/backend/src/services/sop/sop.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/sop/sop.service.js +93 -3
- package/dist/backend/backend/src/services/sop/sop.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/claim.service.d.ts +41 -0
- package/dist/backend/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/claim.service.js +72 -0
- package/dist/backend/backend/src/services/task-pool/claim.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +20 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js +11 -0
- package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/telegram/telegram.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/telegram/telegram.service.js +24 -2
- package/dist/backend/backend/src/services/telegram/telegram.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-reminder.service.js +18 -18
- package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +10 -0
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +20 -12
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +12 -3
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +15 -5
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js +31 -50
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +16 -0
- package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-search.service.js +20 -0
- package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -1
- package/dist/backend/backend/src/types/settings.types.d.ts +8 -0
- package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/settings.types.js +2 -0
- package/dist/backend/backend/src/types/settings.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +23 -0
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js +29 -0
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +0 -16
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +0 -16
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
- package/dist/cli/backend/src/services/mcp-server.js +0 -6
- package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.d.ts +78 -41
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.js +209 -127
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/project-memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/project-memory.service.js +37 -9
- package/dist/cli/backend/src/services/memory/project-memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/claim.service.d.ts +41 -0
- package/dist/cli/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/claim.service.js +72 -0
- package/dist/cli/backend/src/services/task-pool/claim.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +16 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +20 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
- package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/schema-loader.service.js +183 -0
- package/dist/cli/backend/src/services/wiki/schema-loader.service.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js +212 -0
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts +43 -0
- package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js +67 -0
- package/dist/cli/backend/src/services/wiki/wiki-overlay.resolver.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts +166 -0
- package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-search.service.js +379 -0
- package/dist/cli/backend/src/services/wiki/wiki-search.service.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki.types.d.ts +84 -0
- package/dist/cli/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki.types.js +10 -0
- package/dist/cli/backend/src/services/wiki/wiki.types.js.map +1 -0
- package/dist/cli/backend/src/types/settings.types.d.ts +8 -0
- package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/settings.types.js +2 -0
- package/dist/cli/backend/src/types/settings.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +23 -0
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js +29 -0
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/frontend/dist/assets/{index-44266b5d.css → index-8205ea5e.css} +1 -1
- package/frontend/dist/assets/{index-4099a91c.js → index-890d3f9d.js} +289 -289
- package/frontend/dist/index.html +2 -2
- 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
|
|
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 |
|
|
47
|
-
| `
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
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
|
-
|
|
96
|
-
|
|
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.
|
|
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
|
|
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
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `teamMemberId` | No |
|
|
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
|
-
|
|
68
|
+
### Register using legacy JSON argument
|
|
51
69
|
|
|
52
70
|
```bash
|
|
53
|
-
bash config/skills/agent/core/register-self/execute.sh '{"
|
|
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.
|