loki-mode 4.2.0
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/LICENSE +21 -0
- package/README.md +691 -0
- package/SKILL.md +191 -0
- package/VERSION +1 -0
- package/autonomy/.loki/dashboard/index.html +2634 -0
- package/autonomy/CONSTITUTION.md +508 -0
- package/autonomy/README.md +201 -0
- package/autonomy/config.example.yaml +152 -0
- package/autonomy/loki +526 -0
- package/autonomy/run.sh +3636 -0
- package/bin/loki-mode.js +26 -0
- package/bin/postinstall.js +60 -0
- package/docs/ACKNOWLEDGEMENTS.md +234 -0
- package/docs/COMPARISON.md +325 -0
- package/docs/COMPETITIVE-ANALYSIS.md +333 -0
- package/docs/INSTALLATION.md +547 -0
- package/docs/auto-claude-comparison.md +276 -0
- package/docs/cursor-comparison.md +225 -0
- package/docs/dashboard-guide.md +355 -0
- package/docs/screenshots/README.md +149 -0
- package/docs/screenshots/dashboard-agents.png +0 -0
- package/docs/screenshots/dashboard-tasks.png +0 -0
- package/docs/thick2thin.md +173 -0
- package/package.json +48 -0
- package/references/advanced-patterns.md +453 -0
- package/references/agent-types.md +243 -0
- package/references/agents.md +1043 -0
- package/references/business-ops.md +550 -0
- package/references/competitive-analysis.md +216 -0
- package/references/confidence-routing.md +371 -0
- package/references/core-workflow.md +275 -0
- package/references/cursor-learnings.md +207 -0
- package/references/deployment.md +604 -0
- package/references/lab-research-patterns.md +534 -0
- package/references/mcp-integration.md +186 -0
- package/references/memory-system.md +467 -0
- package/references/openai-patterns.md +647 -0
- package/references/production-patterns.md +568 -0
- package/references/prompt-repetition.md +192 -0
- package/references/quality-control.md +437 -0
- package/references/sdlc-phases.md +410 -0
- package/references/task-queue.md +361 -0
- package/references/tool-orchestration.md +691 -0
- package/skills/00-index.md +120 -0
- package/skills/agents.md +249 -0
- package/skills/artifacts.md +174 -0
- package/skills/github-integration.md +218 -0
- package/skills/model-selection.md +125 -0
- package/skills/parallel-workflows.md +526 -0
- package/skills/patterns-advanced.md +188 -0
- package/skills/production.md +292 -0
- package/skills/quality-gates.md +180 -0
- package/skills/testing.md +149 -0
- package/skills/troubleshooting.md +109 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# Task Queue Reference
|
|
2
|
+
|
|
3
|
+
Distributed task queue system, dead letter handling, and circuit breakers.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task Schema
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"id": "uuid",
|
|
12
|
+
"idempotencyKey": "hash-of-task-content",
|
|
13
|
+
"type": "eng-backend|eng-frontend|ops-devops|...",
|
|
14
|
+
"priority": 1-10,
|
|
15
|
+
"dependencies": ["task-id-1", "task-id-2"],
|
|
16
|
+
"payload": {
|
|
17
|
+
"action": "implement|test|deploy|...",
|
|
18
|
+
"target": "file/path or resource",
|
|
19
|
+
"params": {},
|
|
20
|
+
"goal": "What success looks like (high-level objective)",
|
|
21
|
+
"constraints": ["No third-party deps", "Maintain backwards compat"],
|
|
22
|
+
"context": {
|
|
23
|
+
"relatedFiles": ["file1.ts", "file2.ts"],
|
|
24
|
+
"architectureDecisions": ["ADR-001: Use JWT tokens"],
|
|
25
|
+
"previousAttempts": "What was tried before, why it failed"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"createdAt": "ISO",
|
|
29
|
+
"claimedBy": null,
|
|
30
|
+
"claimedAt": null,
|
|
31
|
+
"timeout": 3600,
|
|
32
|
+
"retries": 0,
|
|
33
|
+
"maxRetries": 3,
|
|
34
|
+
"backoffSeconds": 60,
|
|
35
|
+
"lastError": null,
|
|
36
|
+
"completedAt": null,
|
|
37
|
+
"result": {
|
|
38
|
+
"status": "success|failed",
|
|
39
|
+
"output": "What was produced",
|
|
40
|
+
"decisionReport": { ... }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Decision Report is REQUIRED for completed tasks.** Tasks without proper decision documentation will be marked as incomplete.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Queue Files
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
.loki/queue/
|
|
53
|
+
+-- pending.json # Tasks waiting to be claimed
|
|
54
|
+
+-- in-progress.json # Currently executing tasks
|
|
55
|
+
+-- completed.json # Finished tasks
|
|
56
|
+
+-- dead-letter.json # Failed tasks for review
|
|
57
|
+
+-- cancelled.json # Cancelled tasks
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Queue Operations
|
|
63
|
+
|
|
64
|
+
### Claim Task (with file locking)
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
def claim_task(agent_id, agent_capabilities):
|
|
68
|
+
with file_lock(".loki/state/locks/queue.lock", timeout=10):
|
|
69
|
+
pending = read_json(".loki/queue/pending.json")
|
|
70
|
+
|
|
71
|
+
# Find eligible task
|
|
72
|
+
for task in sorted(pending.tasks, key=lambda t: -t.priority):
|
|
73
|
+
if task.type not in agent_capabilities:
|
|
74
|
+
continue
|
|
75
|
+
if task.claimedBy and not claim_expired(task):
|
|
76
|
+
continue
|
|
77
|
+
if not all_dependencies_completed(task.dependencies):
|
|
78
|
+
continue
|
|
79
|
+
if circuit_breaker_open(task.type):
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
# Claim it
|
|
83
|
+
task.claimedBy = agent_id
|
|
84
|
+
task.claimedAt = now()
|
|
85
|
+
move_task(task, "pending", "in-progress")
|
|
86
|
+
return task
|
|
87
|
+
|
|
88
|
+
return None
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### File Locking (Bash)
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
#!/bin/bash
|
|
95
|
+
# Atomic task claim using flock
|
|
96
|
+
|
|
97
|
+
QUEUE_FILE=".loki/queue/pending.json"
|
|
98
|
+
LOCK_FILE=".loki/state/locks/queue.lock"
|
|
99
|
+
|
|
100
|
+
(
|
|
101
|
+
flock -x -w 10 200 || exit 1
|
|
102
|
+
|
|
103
|
+
# Read, claim, write atomically
|
|
104
|
+
TASK=$(jq -r '.tasks | map(select(.claimedBy == null)) | .[0]' "$QUEUE_FILE")
|
|
105
|
+
if [ "$TASK" != "null" ]; then
|
|
106
|
+
TASK_ID=$(echo "$TASK" | jq -r '.id')
|
|
107
|
+
jq --arg id "$TASK_ID" --arg agent "$AGENT_ID" \
|
|
108
|
+
'.tasks |= map(if .id == $id then .claimedBy = $agent | .claimedAt = now else . end)' \
|
|
109
|
+
"$QUEUE_FILE" > "${QUEUE_FILE}.tmp" && mv "${QUEUE_FILE}.tmp" "$QUEUE_FILE"
|
|
110
|
+
echo "$TASK_ID"
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
) 200>"$LOCK_FILE"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Complete Task
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
def complete_task(task_id, result, success=True):
|
|
120
|
+
with file_lock(".loki/state/locks/queue.lock"):
|
|
121
|
+
task = find_task(task_id, "in-progress")
|
|
122
|
+
task.completedAt = now()
|
|
123
|
+
task.result = result
|
|
124
|
+
|
|
125
|
+
if success:
|
|
126
|
+
move_task(task, "in-progress", "completed")
|
|
127
|
+
reset_circuit_breaker(task.type)
|
|
128
|
+
trigger_dependents(task_id)
|
|
129
|
+
else:
|
|
130
|
+
handle_failure(task)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Failure Handling
|
|
136
|
+
|
|
137
|
+
### Exponential Backoff
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
def handle_failure(task):
|
|
141
|
+
task.retries += 1
|
|
142
|
+
task.lastError = get_last_error()
|
|
143
|
+
|
|
144
|
+
if task.retries >= task.maxRetries:
|
|
145
|
+
# Move to dead letter queue
|
|
146
|
+
move_task(task, "in-progress", "dead-letter")
|
|
147
|
+
increment_circuit_breaker(task.type)
|
|
148
|
+
alert_orchestrator(f"Task {task.id} moved to dead letter queue")
|
|
149
|
+
else:
|
|
150
|
+
# Exponential backoff: 60s, 120s, 240s, ...
|
|
151
|
+
task.backoffSeconds = task.backoffSeconds * (2 ** (task.retries - 1))
|
|
152
|
+
task.availableAt = now() + task.backoffSeconds
|
|
153
|
+
move_task(task, "in-progress", "pending")
|
|
154
|
+
log(f"Task {task.id} retry {task.retries}, backoff {task.backoffSeconds}s")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Dead Letter Queue
|
|
160
|
+
|
|
161
|
+
Tasks in dead letter queue require manual review:
|
|
162
|
+
|
|
163
|
+
### Review Process
|
|
164
|
+
|
|
165
|
+
1. Read `.loki/queue/dead-letter.json`
|
|
166
|
+
2. For each task:
|
|
167
|
+
- Analyze `lastError` and failure pattern
|
|
168
|
+
- Determine if:
|
|
169
|
+
- Task is invalid -> delete
|
|
170
|
+
- Bug in agent -> fix agent, retry
|
|
171
|
+
- External dependency down -> wait, retry
|
|
172
|
+
- Requires human decision -> escalate
|
|
173
|
+
3. To retry: move task back to pending with reset retries
|
|
174
|
+
4. Log decision in `.loki/logs/decisions/dlq-review-{date}.md`
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Idempotency
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
def enqueue_task(task):
|
|
182
|
+
# Generate idempotency key from content
|
|
183
|
+
task.idempotencyKey = hash(json.dumps(task.payload, sort_keys=True))
|
|
184
|
+
|
|
185
|
+
# Check if already exists
|
|
186
|
+
for queue in ["pending", "in-progress", "completed"]:
|
|
187
|
+
existing = find_by_idempotency_key(task.idempotencyKey, queue)
|
|
188
|
+
if existing:
|
|
189
|
+
log(f"Duplicate task detected: {task.idempotencyKey}")
|
|
190
|
+
return existing.id # Return existing, don't create duplicate
|
|
191
|
+
|
|
192
|
+
# Safe to create
|
|
193
|
+
save_task(task, "pending")
|
|
194
|
+
return task.id
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Task Cancellation
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
def cancel_task(task_id, reason):
|
|
203
|
+
with file_lock(".loki/state/locks/queue.lock"):
|
|
204
|
+
for queue in ["pending", "in-progress"]:
|
|
205
|
+
task = find_task(task_id, queue)
|
|
206
|
+
if task:
|
|
207
|
+
task.cancelledAt = now()
|
|
208
|
+
task.cancelReason = reason
|
|
209
|
+
move_task(task, queue, "cancelled")
|
|
210
|
+
|
|
211
|
+
# Cancel dependent tasks too
|
|
212
|
+
for dep_task in find_tasks_depending_on(task_id):
|
|
213
|
+
cancel_task(dep_task.id, f"Parent {task_id} cancelled")
|
|
214
|
+
|
|
215
|
+
return True
|
|
216
|
+
return False
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Circuit Breakers
|
|
222
|
+
|
|
223
|
+
### State Schema
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"circuitBreakers": {
|
|
228
|
+
"eng-backend": {
|
|
229
|
+
"state": "closed",
|
|
230
|
+
"failures": 0,
|
|
231
|
+
"lastFailure": null,
|
|
232
|
+
"openedAt": null,
|
|
233
|
+
"halfOpenAt": null
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### States
|
|
240
|
+
|
|
241
|
+
| State | Description | Behavior |
|
|
242
|
+
|-------|-------------|----------|
|
|
243
|
+
| **closed** | Normal operation | Tasks flow normally |
|
|
244
|
+
| **open** | Too many failures | Block all tasks of this type |
|
|
245
|
+
| **half-open** | Testing recovery | Allow 1 test task |
|
|
246
|
+
|
|
247
|
+
### Configuration
|
|
248
|
+
|
|
249
|
+
```yaml
|
|
250
|
+
# .loki/config/circuit-breakers.yaml
|
|
251
|
+
defaults:
|
|
252
|
+
failureThreshold: 5
|
|
253
|
+
cooldownSeconds: 300
|
|
254
|
+
halfOpenAfter: 60
|
|
255
|
+
|
|
256
|
+
overrides:
|
|
257
|
+
ops-security:
|
|
258
|
+
failureThreshold: 3 # More sensitive for security
|
|
259
|
+
biz-marketing:
|
|
260
|
+
failureThreshold: 10 # More tolerant for non-critical
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Implementation
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
def check_circuit_breaker(agent_type):
|
|
267
|
+
cb = load_circuit_breaker(agent_type)
|
|
268
|
+
|
|
269
|
+
if cb.state == "closed":
|
|
270
|
+
return True # Proceed
|
|
271
|
+
|
|
272
|
+
if cb.state == "open":
|
|
273
|
+
if now() > cb.openedAt + config.halfOpenAfter:
|
|
274
|
+
cb.state = "half-open"
|
|
275
|
+
save_circuit_breaker(cb)
|
|
276
|
+
return True # Allow test task
|
|
277
|
+
return False # Still blocking
|
|
278
|
+
|
|
279
|
+
if cb.state == "half-open":
|
|
280
|
+
return False # Already testing, wait
|
|
281
|
+
|
|
282
|
+
def on_task_success(agent_type):
|
|
283
|
+
cb = load_circuit_breaker(agent_type)
|
|
284
|
+
if cb.state == "half-open":
|
|
285
|
+
cb.state = "closed"
|
|
286
|
+
cb.failures = 0
|
|
287
|
+
save_circuit_breaker(cb)
|
|
288
|
+
|
|
289
|
+
def on_task_failure(agent_type):
|
|
290
|
+
cb = load_circuit_breaker(agent_type)
|
|
291
|
+
cb.failures += 1
|
|
292
|
+
cb.lastFailure = now()
|
|
293
|
+
|
|
294
|
+
if cb.state == "half-open" or cb.failures >= config.failureThreshold:
|
|
295
|
+
cb.state = "open"
|
|
296
|
+
cb.openedAt = now()
|
|
297
|
+
alert_orchestrator(f"Circuit breaker OPEN for {agent_type}")
|
|
298
|
+
|
|
299
|
+
save_circuit_breaker(cb)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Rate Limit Handling
|
|
305
|
+
|
|
306
|
+
### Detection
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
def detect_rate_limit(error):
|
|
310
|
+
indicators = [
|
|
311
|
+
"rate limit",
|
|
312
|
+
"429",
|
|
313
|
+
"too many requests",
|
|
314
|
+
"quota exceeded",
|
|
315
|
+
"retry-after"
|
|
316
|
+
]
|
|
317
|
+
return any(ind in str(error).lower() for ind in indicators)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Response Protocol
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
def handle_rate_limit(agent_id, error):
|
|
324
|
+
# 1. Save state checkpoint
|
|
325
|
+
checkpoint_state(agent_id)
|
|
326
|
+
|
|
327
|
+
# 2. Calculate backoff
|
|
328
|
+
retry_after = parse_retry_after(error) or calculate_exponential_backoff()
|
|
329
|
+
|
|
330
|
+
# 3. Log and wait
|
|
331
|
+
log(f"Rate limit hit for {agent_id}, waiting {retry_after}s")
|
|
332
|
+
|
|
333
|
+
# 4. Signal other agents to slow down
|
|
334
|
+
broadcast_signal("SLOWDOWN", {"wait": retry_after / 2})
|
|
335
|
+
|
|
336
|
+
# 5. Resume after backoff
|
|
337
|
+
schedule_resume(agent_id, retry_after)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Exponential Backoff
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
def calculate_exponential_backoff(attempt=1, base=60, max_wait=3600):
|
|
344
|
+
wait = min(base * (2 ** (attempt - 1)), max_wait)
|
|
345
|
+
jitter = random.uniform(0, wait * 0.1)
|
|
346
|
+
return wait + jitter
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Priority System
|
|
352
|
+
|
|
353
|
+
| Priority | Use Case | Example |
|
|
354
|
+
|----------|----------|---------|
|
|
355
|
+
| 10 | Critical blockers | Security vulnerability fix |
|
|
356
|
+
| 8-9 | High priority | Core feature implementation |
|
|
357
|
+
| 5-7 | Normal | Standard tasks |
|
|
358
|
+
| 3-4 | Low priority | Documentation, cleanup |
|
|
359
|
+
| 1-2 | Background | Nice-to-have improvements |
|
|
360
|
+
|
|
361
|
+
Tasks are always processed in priority order within their type.
|