@jiggai/recipes 0.4.23 → 0.4.25

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.
@@ -2,7 +2,7 @@
2
2
  "id": "recipes",
3
3
  "name": "Recipes",
4
4
  "description": "Markdown recipes that scaffold agents and teams (workspace-local).",
5
- "version": "0.4.23",
5
+ "version": "0.4.25",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "@jiggai/recipes",
3
- "version": "0.4.23",
3
+ "version": "0.4.25",
4
4
  "description": "ClawRecipes plugin for OpenClaw (markdown recipes -> scaffold agents/teams)",
5
5
  "main": "index.ts",
6
6
  "type": "commonjs",
7
7
  "openclaw": {
8
8
  "extensions": [
9
9
  "./index.ts"
10
- ]
10
+ ],
11
+ "compat": {
12
+ "pluginApi": "2026.3"
13
+ }
11
14
  },
12
15
  "publishConfig": {
13
16
  "access": "public"
@@ -34,7 +37,7 @@
34
37
  "lint:fix": "eslint src/ index.ts --fix",
35
38
  "smell-check": "node scripts/smell-check.mjs",
36
39
  "jscpd": "jscpd src/ index.ts --min-lines 8 --min-tokens 50",
37
- "prepare": "husky",
40
+ "prepare": "husky || true",
38
41
  "check:plugin-version": "node scripts/check-openclaw-plugin-version.mjs",
39
42
  "prepack": "npm run -s sync:plugin-version && npm run -s check:plugin-version",
40
43
  "prepublishOnly": "npm run -s sync:plugin-version && npm run -s check:plugin-version",
@@ -9,13 +9,58 @@ cronJobs:
9
9
  name: "Lead triage loop"
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
- message: "Automated lead triage loop (Business Team): triage inbox/tickets, assign work, and update notes/status.md."
12
+ agentId: "{{teamId}}-lead"
13
+ timeoutSeconds: 1800
14
+ message: "Lead triage loop (Business Team): triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing."
15
+ enabledByDefault: false
16
+
17
+ - id: ops-work-loop
18
+ name: "Operations work loop (safe-idle)"
19
+ schedule: "*/30 7-23 * * 1-5"
20
+ timezone: "America/New_York"
21
+ agentId: "{{teamId}}-ops"
22
+ timeoutSeconds: 1800
23
+ message: "Work loop: check for operations-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/ops/agent-outputs/."
24
+ enabledByDefault: false
25
+ - id: sales-work-loop
26
+ name: "Sales work loop (safe-idle)"
27
+ schedule: "*/30 7-23 * * 1-5"
28
+ timezone: "America/New_York"
29
+ agentId: "{{teamId}}-sales"
30
+ timeoutSeconds: 1800
31
+ message: "Work loop: check for sales-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/sales/agent-outputs/."
32
+ enabledByDefault: false
33
+ - id: marketing-work-loop
34
+ name: "Marketing work loop (safe-idle)"
35
+ schedule: "*/30 7-23 * * 1-5"
36
+ timezone: "America/New_York"
37
+ agentId: "{{teamId}}-marketing"
38
+ timeoutSeconds: 1800
39
+ message: "Work loop: check for marketing-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/marketing/agent-outputs/."
40
+ enabledByDefault: false
41
+ - id: finance-work-loop
42
+ name: "Finance work loop (safe-idle)"
43
+ schedule: "*/30 7-23 * * 1-5"
44
+ timezone: "America/New_York"
45
+ agentId: "{{teamId}}-finance"
46
+ timeoutSeconds: 1800
47
+ message: "Work loop: check for finance-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/finance/agent-outputs/."
48
+ enabledByDefault: false
49
+ - id: analyst-work-loop
50
+ name: "Analyst work loop (safe-idle)"
51
+ schedule: "*/30 7-23 * * 1-5"
52
+ timezone: "America/New_York"
53
+ agentId: "{{teamId}}-analyst"
54
+ timeoutSeconds: 1800
55
+ message: "Work loop: check for analytics-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/analyst/agent-outputs/."
13
56
  enabledByDefault: false
14
57
  - id: execution-loop
15
58
  name: "Execution loop"
16
59
  schedule: "*/30 7-23 * * 1-5"
17
60
  timezone: "America/New_York"
18
- message: "Automated execution loop (Business Team): make progress on in-progress tickets and update notes/status.md."
61
+ agentId: "{{teamId}}-lead"
62
+ timeoutSeconds: 1800
63
+ message: "Execution loop (Business Team): complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on."
19
64
  enabledByDefault: false
20
65
  requiredSkills: []
21
66
  team:
@@ -117,9 +162,10 @@ templates:
117
162
  - `roles/<role>/agent-outputs/` (append-only)
118
163
  - `../shared-context/agent-outputs/` (team-level, read/write from role via `../`)
119
164
 
120
- ## Role work loop contract (safe-idle)
165
+ ## Role work loop contract
121
166
  - No-op unless explicit queued work exists for the role.
122
- - If work happens, write back in order: ticket `../notes/status.md` `roles/<role>/agent-outputs/`.
167
+ - If work exists, complete it fully. If too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
168
+ - Write back in order: ticket → `../notes/status.md` → `roles/<role>/agent-outputs/`.
123
169
 
124
170
  sharedContext.priorities: |
125
171
  # Priorities (lead-curated)
@@ -9,13 +9,42 @@ cronJobs:
9
9
  name: "Lead triage loop"
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
- message: "Automated lead triage loop: triage inbox/tickets, assign work, and update notes/status.md."
12
+ agentId: "{{teamId}}-lead"
13
+ timeoutSeconds: 1800
14
+ message: "Lead triage loop (Customer Support Team): triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing."
15
+ enabledByDefault: false
16
+
17
+ - id: triage-work-loop
18
+ name: "Triage work loop (safe-idle)"
19
+ schedule: "*/30 7-23 * * 1-5"
20
+ timezone: "America/New_York"
21
+ agentId: "{{teamId}}-triage"
22
+ timeoutSeconds: 1800
23
+ message: "Work loop: check for triage-assigned tickets (categorize, route, escalate). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/triage/agent-outputs/."
24
+ enabledByDefault: false
25
+ - id: resolver-work-loop
26
+ name: "Resolver work loop (safe-idle)"
27
+ schedule: "*/30 7-23 * * 1-5"
28
+ timezone: "America/New_York"
29
+ agentId: "{{teamId}}-resolver"
30
+ timeoutSeconds: 1800
31
+ message: "Work loop: check for resolver-assigned tickets (investigate, resolve, follow up). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/resolver/agent-outputs/."
32
+ enabledByDefault: false
33
+ - id: kb-writer-work-loop
34
+ name: "KB Writer work loop (safe-idle)"
35
+ schedule: "*/30 7-23 * * 1-5"
36
+ timezone: "America/New_York"
37
+ agentId: "{{teamId}}-kb-writer"
38
+ timeoutSeconds: 1800
39
+ message: "Work loop: check for knowledge-base work (document solutions, update FAQs, maintain docs). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/kb-writer/agent-outputs/."
13
40
  enabledByDefault: false
14
41
  - id: execution-loop
15
42
  name: "Execution loop"
16
43
  schedule: "*/30 7-23 * * 1-5"
17
44
  timezone: "America/New_York"
18
- message: "Automated execution loop: make progress on in-progress tickets, keep changes small/safe, and update notes/status.md."
45
+ agentId: "{{teamId}}-lead"
46
+ timeoutSeconds: 1800
47
+ message: "Execution loop (Customer Support Team): complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on."
19
48
  enabledByDefault: false
20
49
  # pr-watcher omitted (enable only when a real PR integration exists)
21
50
  requiredSkills: []
@@ -106,9 +135,10 @@ templates:
106
135
  - `roles/<role>/agent-outputs/` (append-only)
107
136
  - `../shared-context/agent-outputs/` (team-level, read/write from role via `../`)
108
137
 
109
- ## Role work loop contract (safe-idle)
138
+ ## Role work loop contract
110
139
  - No-op unless explicit queued work exists for the role.
111
- - If work happens, write back in order: ticket `../notes/status.md` `roles/<role>/agent-outputs/`.
140
+ - If work exists, complete it fully. If too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
141
+ - Write back in order: ticket → `../notes/status.md` → `roles/<role>/agent-outputs/`.
112
142
 
113
143
  sharedContext.priorities: |
114
144
  # Priorities (lead-curated)
@@ -10,8 +10,9 @@ cronJobs:
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
12
  agentId: "{{teamId}}-lead"
13
+ timeoutSeconds: 1800
13
14
  message: |
14
- Automated lead triage loop: triage inbox/tickets, assign work, and update notes/status.md.
15
+ Lead triage loop: triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing.
15
16
 
16
17
  QA-gated PR rule:
17
18
  - Dev/DevOps must NOT open PRs.
@@ -35,8 +36,9 @@ cronJobs:
35
36
  schedule: "*/30 7-23 * * 1-5"
36
37
  timezone: "America/New_York"
37
38
  agentId: "{{teamId}}-dev"
39
+ timeoutSeconds: 1800
38
40
  message: |
39
- Safe-idle loop: work dev-assigned tickets.
41
+ Work loop: check for dev-assigned tickets. If you have one, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece (not a fragment) and update the ticket with what's done and what remains. Always leave work in a clean, consistent state.
40
42
 
41
43
  Constraints:
42
44
  - Do NOT open PRs. Dev hands off to QA by moving ticket to work/testing and setting Owner=test.
@@ -49,7 +51,8 @@ cronJobs:
49
51
  schedule: "*/30 7-23 * * 1-5"
50
52
  timezone: "America/New_York"
51
53
  agentId: "{{teamId}}-devops"
52
- message: "Safe-idle loop: check for devops-assigned tickets/runs, make small progress, and write outputs under roles/devops/agent-outputs/."
54
+ timeoutSeconds: 1800
55
+ message: "Work loop: check for devops-assigned tickets/runs. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/devops/agent-outputs/."
53
56
  enabledByDefault: true
54
57
 
55
58
  - id: test-work-loop
@@ -57,8 +60,9 @@ cronJobs:
57
60
  schedule: "*/30 7-23 * * 1-5"
58
61
  timezone: "America/New_York"
59
62
  agentId: "{{teamId}}-test"
63
+ timeoutSeconds: 1800
60
64
  message: |
61
- Safe-idle loop: drain work/testing tickets assigned to test.
65
+ Work loop: drain work/testing tickets assigned to test. Complete each ticket's QA fully before moving on.
62
66
 
63
67
  Workflow:
64
68
  - On PASS: keep ticket in work/testing but set Owner=lead (ready-for-pr) and add a `QA: PASS` comment + evidence.
@@ -75,8 +79,9 @@ cronJobs:
75
79
  schedule: "*/30 7-23 * * 1-5"
76
80
  timezone: "America/New_York"
77
81
  agentId: "{{teamId}}-lead"
82
+ timeoutSeconds: 1800
78
83
  message: |
79
- Automated execution loop: make progress on in-progress tickets, keep changes small/safe, and update notes/status.md.
84
+ Execution loop: complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on. If a task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
80
85
 
81
86
  CWD guardrail (team root): run:
82
87
  cd "$(bash ../../scripts/team-root.sh 2>/dev/null || bash ./scripts/team-root.sh)"
@@ -85,7 +90,7 @@ cronJobs:
85
90
  Guardrail: run ./scripts/ticket-hygiene-dev.sh each loop; if it fails, fix lane/status/owner mismatches before proceeding (assignment stubs are deprecated).
86
91
 
87
92
  LEAD-OWNED TICKETS RULE (must follow)
88
- - Do NOT automatically move a ticket just because Owner=lead expects backlog”.
93
+ - Do NOT automatically move a ticket just because Owner=lead "expects backlog".
89
94
  - If you encounter a lead-owned ticket in work/in-progress or work/testing that seems misassigned:
90
95
  - LEAVE IT IN PLACE.
91
96
  - Add a dated comment to the ticket explaining what you observed and what should change.
@@ -158,7 +163,7 @@ cronJobs:
158
163
 
159
164
  - id: backup-devteam-work
160
165
  name: "Backup dev-team work (every 3h, off-hours avoided)"
161
- # Every 3h during 07:0022:00 America/New_York (avoids 02:0007:00 blackout)
166
+ # Every 3h during 07:00-22:00 America/New_York (avoids 02:00-07:00 blackout)
162
167
  schedule: "0 7,10,13,16,19,22 * * *"
163
168
  timezone: "America/New_York"
164
169
  agentId: "{{teamId}}-lead"
@@ -220,29 +225,29 @@ templates:
220
225
  sharedContext.memoryPolicy: |
221
226
  # Team Memory Policy (File-first)
222
227
 
223
- Quick link: see `shared-context/MEMORY_PLAN.md` for the canonical what goes where map.
228
+ Quick link: see `shared-context/MEMORY_PLAN.md` for the canonical "what goes where" map.
224
229
 
225
230
  This team is run **file-first**. Chat is not the system of record.
226
231
 
227
- ## Where memory lives (and what its for)
232
+ ## Where memory lives (and what it's for)
228
233
 
229
234
  ### 1) Team knowledge memory (Kitchen UI)
230
235
  - `shared-context/memory/team.jsonl` (append-only)
231
236
  - `shared-context/memory/pinned.jsonl` (append-only)
232
237
 
233
- Kitchens Team Editor → Memory tab reads/writes these JSONL streams.
238
+ Kitchen's Team Editor → Memory tab reads/writes these JSONL streams.
234
239
 
235
240
  ### 2) Per-role continuity memory (agents)
236
241
  Each role keeps its own continuity memory:
237
242
  - `roles/<role>/memory/YYYY-MM-DD.md` (daily log)
238
243
  - `roles/<role>/MEMORY.md` (curated long-term memory)
239
244
 
240
- These files are what the role agent uses to remember decisions and context across sessions.
245
+ These files are what the role agent uses to "remember" decisions and context across sessions.
241
246
 
242
247
  ## Where to write things
243
248
  - Ticket = source of truth for a unit of work.
244
249
  - `../notes/plan.md` + `../shared-context/priorities.md` are **lead-curated**.
245
- - `../notes/status.md` is **append-only** and updated after each work session (35 bullets).
250
+ - `../notes/status.md` is **append-only** and updated after each work session (3-5 bullets).
246
251
 
247
252
  ## Outputs / artifacts
248
253
  - Role-level raw output (append-only): `roles/<role>/agent-outputs/`
@@ -250,10 +255,11 @@ templates:
250
255
 
251
256
  Guardrail: do **not** create or rely on `roles/<role>/shared-context/**`.
252
257
 
253
- ## Role work loop contract (safe-idle)
254
- When a roles cron/heartbeat runs:
258
+ ## Role work loop contract
259
+ When a role's cron/heartbeat runs:
255
260
  - **No-op unless explicit queued work exists** for that role (ticket assigned/owned by role, or workflow run nodes assigned to the role agentId).
256
- - If work happens, write back in this order:
261
+ - If work exists, **complete the ticket fully**. If the task is too large for one session, complete a meaningful self-contained piece (not a fragment) and update the ticket with what's done and what remains. Always leave work in a clean, consistent state.
262
+ - Write back in this order:
257
263
  1) Update the relevant ticket(s) (source of truth).
258
264
  2) Append 1–3 bullets to `../notes/status.md` (team roll-up).
259
265
  3) Write raw logs/artifacts under `roles/<role>/agent-outputs/` and reference them from the ticket.
@@ -266,11 +272,11 @@ templates:
266
272
  After meaningful work:
267
273
  1) Update the ticket with what changed + how to verify + rollback.
268
274
  2) Add a dated note in the ticket `## Comments`.
269
- 3) Append 35 bullets to `../notes/status.md`.
275
+ 3) Append 3-5 bullets to `../notes/status.md`.
270
276
  4) Append logs/output to `roles/<role>/agent-outputs/`.
271
277
 
272
278
  tickets: |
273
- # Tickets {{teamId}}
279
+ # Tickets - {{teamId}}
274
280
 
275
281
  ## Workflow stages
276
282
  - backlog → in-progress → testing → done
@@ -280,7 +286,7 @@ templates:
280
286
  - test: verify + record PASS/FAIL
281
287
  - lead: creates PR **only after QA PASS**
282
288
 
283
- ## Ready for PR (no extra lane)
289
+ ## "Ready for PR" (no extra lane)
284
290
  This team does **not** add a separate lane.
285
291
 
286
292
  Instead, a ticket is considered **ready for PR** when:
@@ -295,7 +301,7 @@ templates:
295
301
  - Move ticket to `work/testing/`
296
302
  - Set `Owner: test`
297
303
  - Ensure the ticket contains:
298
- - verification steps (How to test)
304
+ - verification steps ("How to test")
299
305
  - links to branch/commit under `## PR-ready`
300
306
 
301
307
  ### Test → Lead (QA PASS)
@@ -324,7 +330,7 @@ templates:
324
330
 
325
331
 
326
332
  sharedContext.qaAccess: |
327
- # QA Access {{teamId}}
333
+ # QA Access - {{teamId}}
328
334
 
329
335
  This file exists to prevent QA tickets being bounced due to missing environment access.
330
336
 
@@ -381,9 +387,10 @@ templates:
381
387
  - `roles/<role>/agent-outputs/` (append-only)
382
388
  - `../shared-context/agent-outputs/` (team-level, read/write from role via `../`)
383
389
 
384
- ## Role work loop contract (safe-idle)
390
+ ## Role work loop contract
385
391
  - No-op unless explicit queued work exists for the role.
386
- - If work happens, write back in order: ticket `../notes/status.md` `roles/<role>/agent-outputs/`.
392
+ - If work exists, complete it fully. If too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
393
+ - Write back in order: ticket → `../notes/status.md` → `roles/<role>/agent-outputs/`.
387
394
 
388
395
  sharedContext.priorities: |
389
396
  # Priorities (lead-curated)
@@ -1013,7 +1020,7 @@ templates:
1013
1020
  After you act:
1014
1021
  1) Write back:
1015
1022
  - Update tickets with decisions/assignments.
1016
- - Keep `../notes/status.md` current (35 bullets per active ticket).
1023
+ - Keep `../notes/status.md` current (3-5 bullets per active ticket).
1017
1024
 
1018
1025
  ## Curator model
1019
1026
 
@@ -1032,14 +1039,14 @@ templates:
1032
1039
  Source of truth is the shared team workspace.
1033
1040
 
1034
1041
  Folders:
1035
- - `inbox/` raw incoming requests (append-only)
1036
- - `work/backlog/` normalized tickets, filename-ordered (`0001-...md`)
1037
- - `work/in-progress/` tickets currently being executed
1038
- - `work/testing/` tickets awaiting QA verification
1039
- - `work/done/` completed tickets + completion notes
1040
- - `../notes/plan.md` current plan / priorities (curated)
1041
- - `../notes/status.md` current status snapshot
1042
- - `shared-context/` shared context + append-only outputs
1042
+ - `inbox/` - raw incoming requests (append-only)
1043
+ - `work/backlog/` - normalized tickets, filename-ordered (`0001-...md`)
1044
+ - `work/in-progress/` - tickets currently being executed
1045
+ - `work/testing/` - tickets awaiting QA verification
1046
+ - `work/done/` - completed tickets + completion notes
1047
+ - `../notes/plan.md` - current plan / priorities (curated)
1048
+ - `../notes/status.md` - current status snapshot
1049
+ - `shared-context/` - shared context + append-only outputs
1043
1050
 
1044
1051
  ### Ticket numbering (critical)
1045
1052
  - Backlog tickets MUST be named `0001-...md`, `0002-...md`, etc.
@@ -1092,7 +1099,7 @@ templates:
1092
1099
  - `../notes/plan.md`
1093
1100
  - `../notes/status.md`
1094
1101
  - `../shared-context/priorities.md`
1095
- - the current ticket youre working on
1102
+ - the current ticket you're working on
1096
1103
 
1097
1104
  Optional (team knowledge memory, Kitchen UI):
1098
1105
  - `shared-context/memory/pinned.jsonl`
@@ -1104,8 +1111,8 @@ templates:
1104
1111
 
1105
1112
  After you finish a work session (even if not done):
1106
1113
  1) Write back:
1107
- - Update the ticket with what you did and whats next.
1108
- - Add **35 bullets** to `../notes/status.md` (what changed / whats blocked).
1114
+ - Update the ticket with what you did and what's next.
1115
+ - Add **3-5 bullets** to `../notes/status.md` (what changed / what's blocked).
1109
1116
  - Append detailed output to `../shared-context/agent-outputs/` (append-only).
1110
1117
 
1111
1118
  Curator model:
@@ -1125,7 +1132,7 @@ templates:
1125
1132
  4) Do the work.
1126
1133
 
1127
1134
  5) Handoff to QA (required):
1128
- - Ensure the ticket has verification steps (How to test).
1135
+ - Ensure the ticket has verification steps ("How to test").
1129
1136
  - Add a `## PR-ready` section with repo + branch + commit SHA (if known).
1130
1137
  - Move the ticket to `work/testing/`.
1131
1138
  - Set `Owner: test`.
@@ -1159,7 +1166,7 @@ templates:
1159
1166
  - `../notes/plan.md`
1160
1167
  - `../notes/status.md`
1161
1168
  - `../shared-context/priorities.md`
1162
- - the current ticket youre working on
1169
+ - the current ticket you're working on
1163
1170
 
1164
1171
  Optional (team knowledge memory, Kitchen UI):
1165
1172
  - `shared-context/memory/pinned.jsonl`
@@ -1168,7 +1175,7 @@ templates:
1168
1175
  After you finish a work session:
1169
1176
  1) Write back:
1170
1177
  - Update the ticket with what you did + verification steps.
1171
- - Add **35 bullets** to `../notes/status.md`.
1178
+ - Add **3-5 bullets** to `../notes/status.md`.
1172
1179
  - Append detailed output/logs to `../shared-context/agent-outputs/` (append-only).
1173
1180
 
1174
1181
  Curator model:
@@ -1300,7 +1307,7 @@ templates:
1300
1307
 
1301
1308
  ## Core workflow (QA gated)
1302
1309
  - You verify work before any PR is created.
1303
- - If the ticket passes: keep it in `work/testing/` but set `Owner: lead` (this is the ready for PR state).
1310
+ - If the ticket passes: keep it in `work/testing/` but set `Owner: lead` (this is the "ready for PR" state).
1304
1311
  - If it fails: move it back to `work/in-progress/` and set `Owner: dev`.
1305
1312
 
1306
1313
  ## Guardrails (read → act → write)
@@ -1323,7 +1330,7 @@ templates:
1323
1330
  After each verification pass:
1324
1331
  1) Write back:
1325
1332
  - Add a short verification note to the ticket (pass/fail + evidence).
1326
- - Add **35 bullets** to `../notes/status.md` (whats verified / whats blocked).
1333
+ - Add **3-5 bullets** to `../notes/status.md` (what's verified / what's blocked).
1327
1334
  - Append detailed findings to `../shared-context/feedback/` or `../shared-context/agent-outputs/`.
1328
1335
 
1329
1336
  Curator model:
@@ -1342,7 +1349,7 @@ templates:
1342
1349
  3) If it passes:
1343
1350
  - Add a dated ticket comment: `QA: PASS` + evidence (links, logs, screenshots as applicable).
1344
1351
  - Keep the ticket in `work/testing/`.
1345
- - Set `Owner: lead` (this is the ready for PR state).
1352
+ - Set `Owner: lead` (this is the "ready for PR" state).
1346
1353
 
1347
1354
  4) If it fails:
1348
1355
  - Add a dated ticket comment: `QA: FAIL` + repro + what to fix.
@@ -10,86 +10,98 @@ cronJobs:
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
12
  agentId: "{{teamId}}-lead"
13
- message: "Automated lead triage loop (Marketing Team): triage inbox/tickets, assign work, and update notes/status.md."
13
+ timeoutSeconds: 1800
14
+ message: "Lead triage loop (Marketing Team): triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing."
14
15
  enabledByDefault: false
15
16
 
16
- # Safe-idle role loops (enabled by default): roles do not "wake up" unless they have their own heartbeat schedule or cron.
17
+ # Safe-idle role loops: roles do not "wake up" unless they have their own cron.
17
18
  - id: seo-work-loop
18
19
  name: "SEO work loop (safe-idle)"
19
20
  schedule: "*/30 7-23 * * 1-5"
20
21
  timezone: "America/New_York"
21
22
  agentId: "{{teamId}}-seo"
22
- message: "Safe-idle loop: check for SEO-assigned work (tickets/workflows), make small progress, and write outputs under roles/seo/agent-outputs/."
23
+ timeoutSeconds: 1800
24
+ message: "Work loop: check for SEO-assigned work (tickets/workflows). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/seo/agent-outputs/."
23
25
  enabledByDefault: false
24
26
  - id: copywriter-work-loop
25
27
  name: "Copywriter work loop (safe-idle)"
26
28
  schedule: "*/30 7-23 * * 1-5"
27
29
  timezone: "America/New_York"
28
30
  agentId: "{{teamId}}-copywriter"
29
- message: "Safe-idle loop: check for copywriting-assigned work, make progress, and write outputs under roles/copywriter/agent-outputs/."
31
+ timeoutSeconds: 1800
32
+ message: "Work loop: check for copywriting-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/copywriter/agent-outputs/."
30
33
  enabledByDefault: false
31
34
  - id: ads-work-loop
32
35
  name: "Ads work loop (safe-idle)"
33
36
  schedule: "*/30 7-23 * * 1-5"
34
37
  timezone: "America/New_York"
35
38
  agentId: "{{teamId}}-ads"
36
- message: "Safe-idle loop: check for ads-assigned work, make progress, and write outputs under roles/ads/agent-outputs/."
39
+ timeoutSeconds: 1800
40
+ message: "Work loop: check for ads-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/ads/agent-outputs/."
37
41
  enabledByDefault: false
38
42
  - id: social-work-loop
39
43
  name: "Social work loop (safe-idle)"
40
44
  schedule: "*/30 7-23 * * 1-5"
41
45
  timezone: "America/New_York"
42
46
  agentId: "{{teamId}}-social"
43
- message: "Safe-idle loop: check for social/community-assigned work, make progress, and write outputs under roles/social/agent-outputs/."
47
+ timeoutSeconds: 1800
48
+ message: "Work loop: check for social/community-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/social/agent-outputs/."
44
49
  enabledByDefault: false
45
50
  - id: designer-work-loop
46
51
  name: "Designer work loop (safe-idle)"
47
52
  schedule: "*/30 7-23 * * 1-5"
48
53
  timezone: "America/New_York"
49
54
  agentId: "{{teamId}}-designer"
50
- message: "Safe-idle loop: check for creative/design-assigned work, make progress, and write outputs under roles/designer/agent-outputs/."
55
+ timeoutSeconds: 1800
56
+ message: "Work loop: check for creative/design-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/designer/agent-outputs/."
51
57
  enabledByDefault: false
52
58
  - id: analyst-work-loop
53
59
  name: "Analyst work loop (safe-idle)"
54
60
  schedule: "*/30 7-23 * * 1-5"
55
61
  timezone: "America/New_York"
56
62
  agentId: "{{teamId}}-analyst"
57
- message: "Safe-idle loop: check for analytics-assigned work, make progress, and write outputs under roles/analyst/agent-outputs/."
63
+ timeoutSeconds: 1800
64
+ message: "Work loop: check for analytics-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/analyst/agent-outputs/."
58
65
  enabledByDefault: false
59
66
  - id: video-work-loop
60
67
  name: "Video work loop (safe-idle)"
61
68
  schedule: "*/30 7-23 * * 1-5"
62
69
  timezone: "America/New_York"
63
70
  agentId: "{{teamId}}-video"
64
- message: "Safe-idle loop: check for video-assigned work, make progress, and write outputs under roles/video/agent-outputs/."
71
+ timeoutSeconds: 1800
72
+ message: "Work loop: check for video-assigned work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/video/agent-outputs/."
65
73
  enabledByDefault: false
66
74
  - id: compliance-work-loop
67
75
  name: "Compliance work loop (safe-idle)"
68
76
  schedule: "*/30 7-23 * * 1-5"
69
77
  timezone: "America/New_York"
70
78
  agentId: "{{teamId}}-compliance"
71
- message: "Safe-idle loop: check for compliance/brand-review work, make progress, and write outputs under roles/compliance/agent-outputs/."
79
+ timeoutSeconds: 1800
80
+ message: "Work loop: check for compliance/brand-review work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/compliance/agent-outputs/."
72
81
  enabledByDefault: false
73
82
  - id: offer-work-loop
74
83
  name: "Offer work loop (safe-idle)"
75
84
  schedule: "*/30 7-23 * * 1-5"
76
85
  timezone: "America/New_York"
77
86
  agentId: "{{teamId}}-offer"
78
- message: "Safe-idle loop: check for offer/positioning work, make progress, and write outputs under roles/offer/agent-outputs/."
87
+ timeoutSeconds: 1800
88
+ message: "Work loop: check for offer/positioning work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/offer/agent-outputs/."
79
89
  enabledByDefault: false
80
90
  - id: funnel-work-loop
81
91
  name: "Funnel work loop (safe-idle)"
82
92
  schedule: "*/30 7-23 * * 1-5"
83
93
  timezone: "America/New_York"
84
94
  agentId: "{{teamId}}-funnel"
85
- message: "Safe-idle loop: check for funnel/landing-page work, make progress, and write outputs under roles/funnel/agent-outputs/."
95
+ timeoutSeconds: 1800
96
+ message: "Work loop: check for funnel/landing-page work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/funnel/agent-outputs/."
86
97
  enabledByDefault: false
87
98
  - id: lifecycle-work-loop
88
99
  name: "Lifecycle work loop (safe-idle)"
89
100
  schedule: "*/30 7-23 * * 1-5"
90
101
  timezone: "America/New_York"
91
102
  agentId: "{{teamId}}-lifecycle"
92
- message: "Safe-idle loop: check for lifecycle/email work, make progress, and write outputs under roles/lifecycle/agent-outputs/."
103
+ timeoutSeconds: 1800
104
+ message: "Work loop: check for lifecycle/email work. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/lifecycle/agent-outputs/."
93
105
  enabledByDefault: false
94
106
 
95
107
  # NOTE: Workflow worker crons are NOT defined here.
@@ -104,7 +116,8 @@ cronJobs:
104
116
  schedule: "*/30 7-23 * * 1-5"
105
117
  timezone: "America/New_York"
106
118
  agentId: "{{teamId}}-lead"
107
- message: "Automated execution loop (Marketing Team): make progress on in-progress tickets and update notes/status.md."
119
+ timeoutSeconds: 1800
120
+ message: "Execution loop (Marketing Team): complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on."
108
121
  enabledByDefault: false
109
122
  requiredSkills: []
110
123
  team:
@@ -9,13 +9,50 @@ cronJobs:
9
9
  name: "Lead triage loop"
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
- message: "Automated lead triage loop: triage inbox/tickets, assign work, and update notes/status.md."
12
+ agentId: "{{teamId}}-lead"
13
+ timeoutSeconds: 1800
14
+ message: "Lead triage loop (Product Team): triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing."
15
+ enabledByDefault: false
16
+
17
+ - id: pm-work-loop
18
+ name: "Product Manager work loop (safe-idle)"
19
+ schedule: "*/30 7-23 * * 1-5"
20
+ timezone: "America/New_York"
21
+ agentId: "{{teamId}}-pm"
22
+ timeoutSeconds: 1800
23
+ message: "Work loop: check for product-management work (specs, user stories, requirements). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/pm/agent-outputs/."
24
+ enabledByDefault: false
25
+ - id: designer-work-loop
26
+ name: "Designer work loop (safe-idle)"
27
+ schedule: "*/30 7-23 * * 1-5"
28
+ timezone: "America/New_York"
29
+ agentId: "{{teamId}}-designer"
30
+ timeoutSeconds: 1800
31
+ message: "Work loop: check for design-assigned work (mockups, prototypes, design reviews). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/designer/agent-outputs/."
32
+ enabledByDefault: false
33
+ - id: engineer-work-loop
34
+ name: "Engineer work loop (safe-idle)"
35
+ schedule: "*/30 7-23 * * 1-5"
36
+ timezone: "America/New_York"
37
+ agentId: "{{teamId}}-engineer"
38
+ timeoutSeconds: 1800
39
+ message: "Work loop: check for engineering-assigned tickets. If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/engineer/agent-outputs/."
40
+ enabledByDefault: false
41
+ - id: test-work-loop
42
+ name: "Test/QA work loop (safe-idle)"
43
+ schedule: "*/30 7-23 * * 1-5"
44
+ timezone: "America/New_York"
45
+ agentId: "{{teamId}}-test"
46
+ timeoutSeconds: 1800
47
+ message: "Work loop: check for testing-assigned tickets (QA, verification, bug reports). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/test/agent-outputs/."
13
48
  enabledByDefault: false
14
49
  - id: execution-loop
15
50
  name: "Execution loop"
16
51
  schedule: "*/30 7-23 * * 1-5"
17
52
  timezone: "America/New_York"
18
- message: "Automated execution loop: make progress on in-progress tickets, keep changes small/safe, and update notes/status.md."
53
+ agentId: "{{teamId}}-lead"
54
+ timeoutSeconds: 1800
55
+ message: "Execution loop (Product Team): complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on."
19
56
  enabledByDefault: false
20
57
  # pr-watcher omitted (enable only when a real PR integration exists)
21
58
  requiredSkills: []
@@ -112,9 +149,10 @@ templates:
112
149
  - `roles/<role>/agent-outputs/` (append-only)
113
150
  - `../shared-context/agent-outputs/` (team-level, read/write from role via `../`)
114
151
 
115
- ## Role work loop contract (safe-idle)
152
+ ## Role work loop contract
116
153
  - No-op unless explicit queued work exists for the role.
117
- - If work happens, write back in order: ticket `../notes/status.md` `roles/<role>/agent-outputs/`.
154
+ - If work exists, complete it fully. If too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
155
+ - Write back in order: ticket → `../notes/status.md` → `roles/<role>/agent-outputs/`.
118
156
 
119
157
  sharedContext.priorities: |
120
158
  # Priorities (lead-curated)
@@ -9,13 +9,42 @@ cronJobs:
9
9
  name: "Lead triage loop"
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
- message: "Automated lead triage loop: triage inbox/tickets, assign work, and update notes/status.md."
12
+ agentId: "{{teamId}}-lead"
13
+ timeoutSeconds: 1800
14
+ message: "Lead triage loop (Research Team): triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing."
15
+ enabledByDefault: false
16
+
17
+ - id: researcher-work-loop
18
+ name: "Researcher work loop (safe-idle)"
19
+ schedule: "*/30 7-23 * * 1-5"
20
+ timezone: "America/New_York"
21
+ agentId: "{{teamId}}-researcher"
22
+ timeoutSeconds: 1800
23
+ message: "Work loop: check for research-assigned work (investigate, gather data, analyze). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/researcher/agent-outputs/."
24
+ enabledByDefault: false
25
+ - id: fact-checker-work-loop
26
+ name: "Fact Checker work loop (safe-idle)"
27
+ schedule: "*/30 7-23 * * 1-5"
28
+ timezone: "America/New_York"
29
+ agentId: "{{teamId}}-fact-checker"
30
+ timeoutSeconds: 1800
31
+ message: "Work loop: check for fact-checking work (verify claims, check sources, flag issues). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/fact-checker/agent-outputs/."
32
+ enabledByDefault: false
33
+ - id: summarizer-work-loop
34
+ name: "Summarizer work loop (safe-idle)"
35
+ schedule: "*/30 7-23 * * 1-5"
36
+ timezone: "America/New_York"
37
+ agentId: "{{teamId}}-summarizer"
38
+ timeoutSeconds: 1800
39
+ message: "Work loop: check for summarization work (distill findings, create briefs, write reports). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/summarizer/agent-outputs/."
13
40
  enabledByDefault: false
14
41
  - id: execution-loop
15
42
  name: "Execution loop"
16
43
  schedule: "*/30 7-23 * * 1-5"
17
44
  timezone: "America/New_York"
18
- message: "Automated execution loop: make progress on in-progress tickets, keep changes small/safe, and update notes/status.md."
45
+ agentId: "{{teamId}}-lead"
46
+ timeoutSeconds: 1800
47
+ message: "Execution loop (Research Team): complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on."
19
48
  enabledByDefault: false
20
49
  # pr-watcher omitted (enable only when a real PR integration exists)
21
50
  requiredSkills: []
@@ -106,9 +135,10 @@ templates:
106
135
  - `roles/<role>/agent-outputs/` (append-only)
107
136
  - `../shared-context/agent-outputs/` (team-level, read/write from role via `../`)
108
137
 
109
- ## Role work loop contract (safe-idle)
138
+ ## Role work loop contract
110
139
  - No-op unless explicit queued work exists for the role.
111
- - If work happens, write back in order: ticket `../notes/status.md` `roles/<role>/agent-outputs/`.
140
+ - If work exists, complete it fully. If too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
141
+ - Write back in order: ticket → `../notes/status.md` → `roles/<role>/agent-outputs/`.
112
142
 
113
143
  sharedContext.priorities: |
114
144
  # Priorities (lead-curated)
@@ -9,13 +9,114 @@ cronJobs:
9
9
  name: "Lead triage loop"
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
- message: "Automated lead triage loop: triage inbox/tickets, assign work, and update notes/status.md."
12
+ agentId: "{{teamId}}-lead"
13
+ timeoutSeconds: 1800
14
+ message: "Lead triage loop (Social Media Team): triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing."
15
+ enabledByDefault: false
16
+
17
+ - id: research-work-loop
18
+ name: "Research work loop (safe-idle)"
19
+ schedule: "*/30 7-23 * * 1-5"
20
+ timezone: "America/New_York"
21
+ agentId: "{{teamId}}-research"
22
+ timeoutSeconds: 1800
23
+ message: "Work loop: check for research-assigned work (trends, competitor analysis, audience insights). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/research/agent-outputs/."
24
+ enabledByDefault: false
25
+ - id: listening-work-loop
26
+ name: "Social Listening work loop (safe-idle)"
27
+ schedule: "*/30 7-23 * * 1-5"
28
+ timezone: "America/New_York"
29
+ agentId: "{{teamId}}-listening"
30
+ timeoutSeconds: 1800
31
+ message: "Work loop: check for social-listening work (monitor mentions, sentiment, conversations). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/listening/agent-outputs/."
32
+ enabledByDefault: false
33
+ - id: social-seo-work-loop
34
+ name: "Social SEO work loop (safe-idle)"
35
+ schedule: "*/30 7-23 * * 1-5"
36
+ timezone: "America/New_York"
37
+ agentId: "{{teamId}}-social-seo"
38
+ timeoutSeconds: 1800
39
+ message: "Work loop: check for social-SEO work (hashtag research, keyword optimization, discoverability). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/social-seo/agent-outputs/."
40
+ enabledByDefault: false
41
+ - id: editorial-work-loop
42
+ name: "Editorial work loop (safe-idle)"
43
+ schedule: "*/30 7-23 * * 1-5"
44
+ timezone: "America/New_York"
45
+ agentId: "{{teamId}}-editorial"
46
+ timeoutSeconds: 1800
47
+ message: "Work loop: check for editorial work (content calendar, copy review, brand voice). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/editorial/agent-outputs/."
48
+ enabledByDefault: false
49
+ - id: community-work-loop
50
+ name: "Community work loop (safe-idle)"
51
+ schedule: "*/30 7-23 * * 1-5"
52
+ timezone: "America/New_York"
53
+ agentId: "{{teamId}}-community"
54
+ timeoutSeconds: 1800
55
+ message: "Work loop: check for community work (engage, moderate, build relationships). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/community/agent-outputs/."
56
+ enabledByDefault: false
57
+ - id: distributor-work-loop
58
+ name: "Distributor work loop (safe-idle)"
59
+ schedule: "*/30 7-23 * * 1-5"
60
+ timezone: "America/New_York"
61
+ agentId: "{{teamId}}-distributor"
62
+ timeoutSeconds: 1800
63
+ message: "Work loop: check for distribution work (schedule posts, cross-post, syndicate content). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/distributor/agent-outputs/."
64
+ enabledByDefault: false
65
+ - id: tiktok-work-loop
66
+ name: "TikTok work loop (safe-idle)"
67
+ schedule: "*/30 7-23 * * 1-5"
68
+ timezone: "America/New_York"
69
+ agentId: "{{teamId}}-tiktok"
70
+ timeoutSeconds: 1800
71
+ message: "Work loop: check for TikTok-assigned work (create, post, optimize short-form video). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/tiktok/agent-outputs/."
72
+ enabledByDefault: false
73
+ - id: instagram-work-loop
74
+ name: "Instagram work loop (safe-idle)"
75
+ schedule: "*/30 7-23 * * 1-5"
76
+ timezone: "America/New_York"
77
+ agentId: "{{teamId}}-instagram"
78
+ timeoutSeconds: 1800
79
+ message: "Work loop: check for Instagram-assigned work (stories, reels, posts, engagement). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/instagram/agent-outputs/."
80
+ enabledByDefault: false
81
+ - id: youtube-work-loop
82
+ name: "YouTube work loop (safe-idle)"
83
+ schedule: "*/30 7-23 * * 1-5"
84
+ timezone: "America/New_York"
85
+ agentId: "{{teamId}}-youtube"
86
+ timeoutSeconds: 1800
87
+ message: "Work loop: check for YouTube-assigned work (video content, descriptions, community). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/youtube/agent-outputs/."
88
+ enabledByDefault: false
89
+ - id: facebook-work-loop
90
+ name: "Facebook work loop (safe-idle)"
91
+ schedule: "*/30 7-23 * * 1-5"
92
+ timezone: "America/New_York"
93
+ agentId: "{{teamId}}-facebook"
94
+ timeoutSeconds: 1800
95
+ message: "Work loop: check for Facebook-assigned work (posts, groups, ads, engagement). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/facebook/agent-outputs/."
96
+ enabledByDefault: false
97
+ - id: x-work-loop
98
+ name: "X/Twitter work loop (safe-idle)"
99
+ schedule: "*/30 7-23 * * 1-5"
100
+ timezone: "America/New_York"
101
+ agentId: "{{teamId}}-x"
102
+ timeoutSeconds: 1800
103
+ message: "Work loop: check for X/Twitter-assigned work (tweets, threads, engagement, spaces). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/x/agent-outputs/."
104
+ enabledByDefault: false
105
+ - id: linkedin-work-loop
106
+ name: "LinkedIn work loop (safe-idle)"
107
+ schedule: "*/30 7-23 * * 1-5"
108
+ timezone: "America/New_York"
109
+ agentId: "{{teamId}}-linkedin"
110
+ timeoutSeconds: 1800
111
+ message: "Work loop: check for LinkedIn-assigned work (posts, articles, professional engagement). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/linkedin/agent-outputs/."
13
112
  enabledByDefault: false
14
113
  - id: execution-loop
15
114
  name: "Execution loop"
16
115
  schedule: "*/30 7-23 * * 1-5"
17
116
  timezone: "America/New_York"
18
- message: "Automated execution loop: make progress on in-progress tickets, keep changes small/safe, and update notes/status.md."
117
+ agentId: "{{teamId}}-lead"
118
+ timeoutSeconds: 1800
119
+ message: "Execution loop (Social Media Team): complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on."
19
120
  enabledByDefault: false
20
121
  # pr-watcher omitted (enable only when a real PR integration exists)
21
122
  requiredSkills: []
@@ -119,9 +220,10 @@ templates:
119
220
  - `roles/<role>/agent-outputs/` (append-only)
120
221
  - `../shared-context/agent-outputs/` (team-level, read/write from role via `../`)
121
222
 
122
- ## Role work loop contract (safe-idle)
223
+ ## Role work loop contract
123
224
  - No-op unless explicit queued work exists for the role.
124
- - If work happens, write back in order: ticket `../notes/status.md` `roles/<role>/agent-outputs/`.
225
+ - If work exists, complete it fully. If too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
226
+ - Write back in order: ticket → `../notes/status.md` → `roles/<role>/agent-outputs/`.
125
227
 
126
228
  sharedContext.priorities: |
127
229
  # Priorities (lead-curated)
@@ -9,13 +9,42 @@ cronJobs:
9
9
  name: "Lead triage loop"
10
10
  schedule: "*/30 7-23 * * 1-5"
11
11
  timezone: "America/New_York"
12
- message: "Automated lead triage loop: triage inbox/tickets, assign work, and update notes/status.md."
12
+ agentId: "{{teamId}}-lead"
13
+ timeoutSeconds: 1800
14
+ message: "Lead triage loop (Writing Team): triage inbox/tickets, assign work, and update notes/status.md. Complete all pending triage before finishing."
15
+ enabledByDefault: false
16
+
17
+ - id: outliner-work-loop
18
+ name: "Outliner work loop (safe-idle)"
19
+ schedule: "*/30 7-23 * * 1-5"
20
+ timezone: "America/New_York"
21
+ agentId: "{{teamId}}-outliner"
22
+ timeoutSeconds: 1800
23
+ message: "Work loop: check for outlining work (research, structure, create outlines). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/outliner/agent-outputs/."
24
+ enabledByDefault: false
25
+ - id: writer-work-loop
26
+ name: "Writer work loop (safe-idle)"
27
+ schedule: "*/30 7-23 * * 1-5"
28
+ timezone: "America/New_York"
29
+ agentId: "{{teamId}}-writer"
30
+ timeoutSeconds: 1800
31
+ message: "Work loop: check for writing-assigned work (draft, revise, polish content). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/writer/agent-outputs/."
32
+ enabledByDefault: false
33
+ - id: editor-work-loop
34
+ name: "Editor work loop (safe-idle)"
35
+ schedule: "*/30 7-23 * * 1-5"
36
+ timezone: "America/New_York"
37
+ agentId: "{{teamId}}-editor"
38
+ timeoutSeconds: 1800
39
+ message: "Work loop: check for editing work (review, proofread, fact-check, ensure quality). If you have work, complete it fully. If the task is too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains. Write outputs under roles/editor/agent-outputs/."
13
40
  enabledByDefault: false
14
41
  - id: execution-loop
15
42
  name: "Execution loop"
16
43
  schedule: "*/30 7-23 * * 1-5"
17
44
  timezone: "America/New_York"
18
- message: "Automated execution loop: make progress on in-progress tickets, keep changes small/safe, and update notes/status.md."
45
+ agentId: "{{teamId}}-lead"
46
+ timeoutSeconds: 1800
47
+ message: "Execution loop (Writing Team): complete in-progress tickets and update notes/status.md. Finish each ticket fully before moving on."
19
48
  enabledByDefault: false
20
49
  # pr-watcher omitted (enable only when a real PR integration exists)
21
50
  requiredSkills: []
@@ -106,9 +135,10 @@ templates:
106
135
  - `roles/<role>/agent-outputs/` (append-only)
107
136
  - `../shared-context/agent-outputs/` (team-level, read/write from role via `../`)
108
137
 
109
- ## Role work loop contract (safe-idle)
138
+ ## Role work loop contract
110
139
  - No-op unless explicit queued work exists for the role.
111
- - If work happens, write back in order: ticket `../notes/status.md` `roles/<role>/agent-outputs/`.
140
+ - If work exists, complete it fully. If too large for one session, complete a meaningful self-contained piece and update the ticket with what's done and what remains.
141
+ - Write back in order: ticket → `../notes/status.md` → `roles/<role>/agent-outputs/`.
112
142
 
113
143
  sharedContext.priorities: |
114
144
  # Priorities (lead-curated)
@@ -64,7 +64,7 @@ type CronReconcileScope =
64
64
 
65
65
  function buildCronJobForCreate(
66
66
  scope: CronReconcileScope,
67
- j: { id: string; name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; enabledByDefault?: boolean; delivery?: 'none' | 'announce' },
67
+ j: { id: string; name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; enabledByDefault?: boolean; delivery?: 'none' | 'announce'; timeoutSeconds?: number },
68
68
  wantEnabled: boolean
69
69
  ): Record<string, unknown> {
70
70
  const name =
@@ -90,10 +90,12 @@ function buildCronJobForCreate(
90
90
  wakeMode: "next-heartbeat",
91
91
  sessionTarget,
92
92
  schedule: { kind: "cron", expr: j.schedule, ...(j.timezone ? { tz: j.timezone } : {}) },
93
- payload: effectiveAgentId ? { kind: "agentTurn", message: j.message } : { kind: "systemEvent", text: j.message },
93
+ payload: effectiveAgentId
94
+ ? { kind: "agentTurn", message: j.message, ...(j.timeoutSeconds ? { timeoutSeconds: j.timeoutSeconds } : {}) }
95
+ : { kind: "systemEvent", text: j.message },
94
96
  ...(j.delivery === 'none'
95
97
  ? { delivery: { mode: "none" } }
96
- : j.channel || j.to
98
+ : j.delivery === 'announce' || j.channel || j.to
97
99
  ? {
98
100
  delivery: {
99
101
  mode: "announce",
@@ -102,12 +104,14 @@ function buildCronJobForCreate(
102
104
  bestEffort: true,
103
105
  },
104
106
  }
105
- : {}),
107
+ : // Default to none — OpenClaw defaults isolated agentTurn crons to
108
+ // "announce" which errors when no channel target is available.
109
+ { delivery: { mode: "none" } }),
106
110
  };
107
111
  }
108
112
 
109
113
  function buildCronJobPatch(
110
- j: { name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; delivery?: 'none' | 'announce' },
114
+ j: { name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; delivery?: 'none' | 'announce'; timeoutSeconds?: number },
111
115
  name: string
112
116
  ): CronJobPatch {
113
117
  const effectiveAgentId = typeof j.agentId === "string" && j.agentId.trim() ? j.agentId.trim() : undefined;
@@ -119,17 +123,23 @@ function buildCronJobPatch(
119
123
  sessionTarget: effectiveAgentId ? "isolated" : "main",
120
124
  wakeMode: "next-heartbeat",
121
125
  schedule: { kind: "cron", expr: j.schedule, ...(j.timezone ? { tz: j.timezone } : {}) },
122
- payload: effectiveAgentId ? { kind: "agentTurn", message: j.message } : { kind: "systemEvent", text: j.message },
126
+ payload: effectiveAgentId
127
+ ? { kind: "agentTurn", message: j.message, ...(j.timeoutSeconds ? { timeoutSeconds: j.timeoutSeconds } : {}) }
128
+ : { kind: "systemEvent", text: j.message },
123
129
  };
124
130
  if (j.delivery === 'none') {
125
131
  patch.delivery = { mode: "none" };
126
- } else if (j.channel || j.to) {
132
+ } else if (j.delivery === 'announce' || j.channel || j.to) {
127
133
  patch.delivery = {
128
134
  mode: "announce",
129
135
  ...(j.channel ? { channel: j.channel } : {}),
130
136
  ...(j.to ? { to: j.to } : {}),
131
137
  bestEffort: true,
132
138
  };
139
+ } else {
140
+ // Default to none — OpenClaw defaults isolated agentTurn crons to
141
+ // "announce" which errors when no channel target is available.
142
+ patch.delivery = { mode: "none" };
133
143
  }
134
144
  return patch;
135
145
  }
@@ -13,6 +13,8 @@ export type CronJobSpec = {
13
13
  enabledByDefault?: boolean;
14
14
  /** Delivery mode: "none" suppresses announce; "announce" delivers to chat. Omit to use gateway default. */
15
15
  delivery?: 'none' | 'announce';
16
+ /** Agent turn timeout in seconds. Sets how long the agent can run before being killed. */
17
+ timeoutSeconds?: number;
16
18
  };
17
19
 
18
20
  /** Raw input for a cron job from YAML (supports message/task/prompt for backward compat). */
@@ -30,6 +32,7 @@ type CronJobInput = {
30
32
  agentId?: unknown;
31
33
  enabledByDefault?: unknown;
32
34
  delivery?: unknown;
35
+ timeoutSeconds?: unknown;
33
36
  };
34
37
 
35
38
  export type RecipeFrontmatter = {
@@ -87,6 +90,7 @@ function buildCronJobSpec(j: CronJobInput, id: string): CronJobSpec {
87
90
  agentId: j.agentId != null ? String(j.agentId) : undefined,
88
91
  enabledByDefault: Boolean(j.enabledByDefault ?? false),
89
92
  delivery: j.delivery === 'none' || j.delivery === 'announce' ? j.delivery : undefined,
93
+ timeoutSeconds: typeof j.timeoutSeconds === 'number' && j.timeoutSeconds > 0 ? j.timeoutSeconds : undefined,
90
94
  };
91
95
  }
92
96
 
@@ -515,8 +515,17 @@ export async function runWorkflowWorkerTick(api: OpenClawPluginApi, opts: {
515
515
  // by the runner/worker loop itself (they send a message + set awaiting state).
516
516
  const nextKind = String(nextNode.kind ?? '');
517
517
  if (nextKind === 'human_approval' || nextKind === 'start' || nextKind === 'end') {
518
- // Re-enqueue onto the same agent so it can execute the next node deterministically.
519
- await enqueueTask(teamDir, agentId, {
518
+ // Route approval nodes to the correct agent:
519
+ // 1. Explicit agentId on the node config (workflow author override)
520
+ // 2. Team lead (${teamId}-lead) — the natural orchestrator role
521
+ // 3. Fallback to the current agent (backwards compat)
522
+ const nextConfig = (nextNode as unknown as Record<string, unknown>)['config'];
523
+ const nextConfigObj = nextConfig && typeof nextConfig === 'object' && !Array.isArray(nextConfig)
524
+ ? (nextConfig as Record<string, unknown>) : {};
525
+ const explicitAgentId = String(nextConfigObj['agentId'] ?? '').trim();
526
+ const approvalAgentId = explicitAgentId || `${teamId}-lead` || agentId;
527
+
528
+ await enqueueTask(teamDir, approvalAgentId, {
520
529
  teamId,
521
530
  runId: task.runId,
522
531
  nodeId: nextNode.id,
@@ -528,7 +537,7 @@ export async function runWorkflowWorkerTick(api: OpenClawPluginApi, opts: {
528
537
  updatedAt: new Date().toISOString(),
529
538
  status: 'waiting_workers',
530
539
  nextNodeIndex: enqueueIdx,
531
- events: [...cur.events, { ts: new Date().toISOString(), type: 'node.enqueued', nodeId: nextNode.id, agentId }],
540
+ events: [...cur.events, { ts: new Date().toISOString(), type: 'node.enqueued', nodeId: nextNode.id, agentId: approvalAgentId }],
532
541
  }));
533
542
 
534
543
  results.push({ taskId: task.id, runId: task.runId, nodeId: task.nodeId, status: 'ok' });