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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +691 -0
  3. package/SKILL.md +191 -0
  4. package/VERSION +1 -0
  5. package/autonomy/.loki/dashboard/index.html +2634 -0
  6. package/autonomy/CONSTITUTION.md +508 -0
  7. package/autonomy/README.md +201 -0
  8. package/autonomy/config.example.yaml +152 -0
  9. package/autonomy/loki +526 -0
  10. package/autonomy/run.sh +3636 -0
  11. package/bin/loki-mode.js +26 -0
  12. package/bin/postinstall.js +60 -0
  13. package/docs/ACKNOWLEDGEMENTS.md +234 -0
  14. package/docs/COMPARISON.md +325 -0
  15. package/docs/COMPETITIVE-ANALYSIS.md +333 -0
  16. package/docs/INSTALLATION.md +547 -0
  17. package/docs/auto-claude-comparison.md +276 -0
  18. package/docs/cursor-comparison.md +225 -0
  19. package/docs/dashboard-guide.md +355 -0
  20. package/docs/screenshots/README.md +149 -0
  21. package/docs/screenshots/dashboard-agents.png +0 -0
  22. package/docs/screenshots/dashboard-tasks.png +0 -0
  23. package/docs/thick2thin.md +173 -0
  24. package/package.json +48 -0
  25. package/references/advanced-patterns.md +453 -0
  26. package/references/agent-types.md +243 -0
  27. package/references/agents.md +1043 -0
  28. package/references/business-ops.md +550 -0
  29. package/references/competitive-analysis.md +216 -0
  30. package/references/confidence-routing.md +371 -0
  31. package/references/core-workflow.md +275 -0
  32. package/references/cursor-learnings.md +207 -0
  33. package/references/deployment.md +604 -0
  34. package/references/lab-research-patterns.md +534 -0
  35. package/references/mcp-integration.md +186 -0
  36. package/references/memory-system.md +467 -0
  37. package/references/openai-patterns.md +647 -0
  38. package/references/production-patterns.md +568 -0
  39. package/references/prompt-repetition.md +192 -0
  40. package/references/quality-control.md +437 -0
  41. package/references/sdlc-phases.md +410 -0
  42. package/references/task-queue.md +361 -0
  43. package/references/tool-orchestration.md +691 -0
  44. package/skills/00-index.md +120 -0
  45. package/skills/agents.md +249 -0
  46. package/skills/artifacts.md +174 -0
  47. package/skills/github-integration.md +218 -0
  48. package/skills/model-selection.md +125 -0
  49. package/skills/parallel-workflows.md +526 -0
  50. package/skills/patterns-advanced.md +188 -0
  51. package/skills/production.md +292 -0
  52. package/skills/quality-gates.md +180 -0
  53. package/skills/testing.md +149 -0
  54. 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.