zigrix 0.1.0-alpha.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 (58) hide show
  1. package/LICENSE +184 -0
  2. package/README.md +128 -0
  3. package/dist/agents/registry.d.ts +28 -0
  4. package/dist/agents/registry.js +98 -0
  5. package/dist/config/defaults.d.ts +66 -0
  6. package/dist/config/defaults.js +58 -0
  7. package/dist/config/load.d.ts +13 -0
  8. package/dist/config/load.js +96 -0
  9. package/dist/config/mutate.d.ts +10 -0
  10. package/dist/config/mutate.js +61 -0
  11. package/dist/config/schema.d.ts +132 -0
  12. package/dist/config/schema.js +123 -0
  13. package/dist/configure.d.ts +24 -0
  14. package/dist/configure.js +164 -0
  15. package/dist/doctor.d.ts +4 -0
  16. package/dist/doctor.js +99 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +791 -0
  19. package/dist/onboard.d.ts +99 -0
  20. package/dist/onboard.js +490 -0
  21. package/dist/orchestration/dispatch.d.ts +9 -0
  22. package/dist/orchestration/dispatch.js +146 -0
  23. package/dist/orchestration/evidence.d.ts +19 -0
  24. package/dist/orchestration/evidence.js +97 -0
  25. package/dist/orchestration/finalize.d.ts +7 -0
  26. package/dist/orchestration/finalize.js +136 -0
  27. package/dist/orchestration/pipeline.d.ts +11 -0
  28. package/dist/orchestration/pipeline.js +26 -0
  29. package/dist/orchestration/report.d.ts +5 -0
  30. package/dist/orchestration/report.js +92 -0
  31. package/dist/orchestration/worker.d.ts +34 -0
  32. package/dist/orchestration/worker.js +132 -0
  33. package/dist/rules/templates.d.ts +24 -0
  34. package/dist/rules/templates.js +73 -0
  35. package/dist/runner/run.d.ts +10 -0
  36. package/dist/runner/run.js +91 -0
  37. package/dist/runner/schema.d.ts +33 -0
  38. package/dist/runner/schema.js +10 -0
  39. package/dist/runner/store.d.ts +5 -0
  40. package/dist/runner/store.js +19 -0
  41. package/dist/state/events.d.ts +3 -0
  42. package/dist/state/events.js +53 -0
  43. package/dist/state/paths.d.ts +15 -0
  44. package/dist/state/paths.js +23 -0
  45. package/dist/state/tasks.d.ts +61 -0
  46. package/dist/state/tasks.js +247 -0
  47. package/dist/state/verify.d.ts +2 -0
  48. package/dist/state/verify.js +65 -0
  49. package/examples/hello-workflow.json +13 -0
  50. package/package.json +44 -0
  51. package/skills/zigrix-doctor/SKILL.md +20 -0
  52. package/skills/zigrix-evidence/SKILL.md +21 -0
  53. package/skills/zigrix-init/SKILL.md +23 -0
  54. package/skills/zigrix-report/SKILL.md +20 -0
  55. package/skills/zigrix-shared/SKILL.md +31 -0
  56. package/skills/zigrix-task-create/SKILL.md +34 -0
  57. package/skills/zigrix-task-status/SKILL.md +27 -0
  58. package/skills/zigrix-worker/SKILL.md +22 -0
@@ -0,0 +1,247 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { appendEvent, loadEvents, nowIso } from './events.js';
4
+ import { ensureBaseState } from './paths.js';
5
+ // ─── Paths ──────────────────────────────────────────────────────────────────
6
+ const TASK_ID_RE = /^(DEV|TEST|TASK)-(\d{8})-(\d{3})$/;
7
+ function metaPath(paths, taskId) {
8
+ return path.join(paths.tasksDir, `${taskId}.meta.json`);
9
+ }
10
+ function specPath(paths, taskId) {
11
+ return path.join(paths.tasksDir, `${taskId}.md`);
12
+ }
13
+ /** Legacy flat JSON path (backward compat read) */
14
+ function legacyPath(paths, taskId) {
15
+ return path.join(paths.tasksDir, `${taskId}.json`);
16
+ }
17
+ // ─── Read helpers ───────────────────────────────────────────────────────────
18
+ function readJson(filePath) {
19
+ try {
20
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ // ─── Task ID generation ─────────────────────────────────────────────────────
27
+ export function nextTaskId(paths, prefix = 'DEV') {
28
+ ensureBaseState(paths);
29
+ const today = nowIso().slice(0, 10).replaceAll('-', '');
30
+ const idPrefix = `${prefix}-${today}-`;
31
+ let maxN = 0;
32
+ for (const name of fs.readdirSync(paths.tasksDir)) {
33
+ const base = name.replace(/\.(meta\.json|json|md)$/, '');
34
+ const match = TASK_ID_RE.exec(base);
35
+ if (match && base.startsWith(idPrefix)) {
36
+ maxN = Math.max(maxN, Number(match[3]));
37
+ }
38
+ }
39
+ return `${idPrefix}${String(maxN + 1).padStart(3, '0')}`;
40
+ }
41
+ // ─── Spec template ──────────────────────────────────────────────────────────
42
+ function renderSpecMd(task) {
43
+ return [
44
+ '# Task Spec',
45
+ '',
46
+ '## 0) Task Metadata',
47
+ `- Task ID: \`${task.taskId}\``,
48
+ `- Title: ${task.title}`,
49
+ `- Scale: \`${task.scale}\``,
50
+ `- Status: \`${task.status}\``,
51
+ `- Created: ${task.createdAt}`,
52
+ task.requestedBy ? `- Requested by: ${task.requestedBy}` : null,
53
+ task.projectDir ? `- Project dir: ${task.projectDir}` : null,
54
+ `- Meta: \`${task.taskId}.meta.json\``,
55
+ '',
56
+ '## Spec Rule',
57
+ '- `normal|risky|large`: 이 문서 작성/갱신 완료 전 작업 진행 금지',
58
+ '- `simple`: 요약형 허용, 문서 파일은 반드시 생성',
59
+ '- 사람용 문서. 기계용 정보는 `.meta.json` 우선.',
60
+ '',
61
+ '## 1) Scope',
62
+ '### In-Scope',
63
+ task.description,
64
+ '',
65
+ '### Out-of-Scope',
66
+ '- (TBD)',
67
+ '',
68
+ '## 2) Orchestration Plan',
69
+ `- Required agents: ${task.requiredAgents.join(', ') || '(none)'}`,
70
+ task.selectedAgents?.length ? `- Selected agents: ${task.selectedAgents.join(', ')}` : null,
71
+ '',
72
+ '## 3) Notes',
73
+ '- (TBD)',
74
+ '',
75
+ ].filter((line) => line !== null).join('\n');
76
+ }
77
+ // ─── Save / Load ────────────────────────────────────────────────────────────
78
+ export function saveTask(paths, task) {
79
+ ensureBaseState(paths);
80
+ task.updatedAt = nowIso();
81
+ // Write meta.json (machine data)
82
+ fs.writeFileSync(metaPath(paths, task.taskId), `${JSON.stringify(task, null, 2)}\n`, 'utf8');
83
+ // Write .md spec if it doesn't exist yet (don't overwrite human edits)
84
+ const mdPath = specPath(paths, task.taskId);
85
+ if (!fs.existsSync(mdPath)) {
86
+ fs.writeFileSync(mdPath, renderSpecMd(task), 'utf8');
87
+ }
88
+ rebuildIndex(paths);
89
+ return task;
90
+ }
91
+ export function loadTask(paths, taskId) {
92
+ // Prefer .meta.json, fall back to legacy .json
93
+ const meta = readJson(metaPath(paths, taskId));
94
+ if (meta)
95
+ return meta;
96
+ const legacy = readJson(legacyPath(paths, taskId));
97
+ return legacy;
98
+ }
99
+ export function listTasks(paths) {
100
+ ensureBaseState(paths);
101
+ const seen = new Set();
102
+ const tasks = [];
103
+ for (const name of fs.readdirSync(paths.tasksDir).sort()) {
104
+ let taskId = null;
105
+ if (name.endsWith('.meta.json')) {
106
+ taskId = name.replace(/\.meta\.json$/, '');
107
+ }
108
+ else if (name.endsWith('.json') && !name.endsWith('.meta.json')) {
109
+ taskId = name.replace(/\.json$/, '');
110
+ }
111
+ if (!taskId || seen.has(taskId))
112
+ continue;
113
+ if (!TASK_ID_RE.test(taskId))
114
+ continue;
115
+ const data = loadTask(paths, taskId);
116
+ if (data) {
117
+ seen.add(taskId);
118
+ tasks.push(data);
119
+ }
120
+ }
121
+ return tasks;
122
+ }
123
+ // ─── Events ─────────────────────────────────────────────────────────────────
124
+ export function listTaskEvents(paths, taskId) {
125
+ const rows = loadEvents(paths.eventsFile);
126
+ return taskId ? rows.filter((row) => String(row.taskId ?? '') === taskId) : rows;
127
+ }
128
+ // ─── Create ─────────────────────────────────────────────────────────────────
129
+ export function createTask(paths, params) {
130
+ const task = {
131
+ taskId: nextTaskId(paths, params.prefix ?? 'DEV'),
132
+ title: params.title,
133
+ description: params.description,
134
+ scale: params.scale ?? 'normal',
135
+ status: 'OPEN',
136
+ createdAt: nowIso(),
137
+ updatedAt: nowIso(),
138
+ requiredAgents: [...(params.requiredAgents ?? [])],
139
+ workerSessions: {},
140
+ ...(params.projectDir ? { projectDir: params.projectDir } : {}),
141
+ ...(params.requestedBy ? { requestedBy: params.requestedBy } : {}),
142
+ };
143
+ saveTask(paths, task);
144
+ appendEvent(paths.eventsFile, {
145
+ event: 'task_created',
146
+ taskId: task.taskId,
147
+ status: 'OPEN',
148
+ title: task.title,
149
+ scale: task.scale,
150
+ payload: { requiredAgents: task.requiredAgents, projectDir: params.projectDir ?? null },
151
+ });
152
+ rebuildIndex(paths);
153
+ return task;
154
+ }
155
+ // ─── Status transitions ─────────────────────────────────────────────────────
156
+ export function updateTaskStatus(paths, taskId, status) {
157
+ const task = loadTask(paths, taskId);
158
+ if (!task)
159
+ return null;
160
+ task.status = status;
161
+ saveTask(paths, task);
162
+ appendEvent(paths.eventsFile, { event: 'task_status_changed', taskId, status });
163
+ rebuildIndex(paths);
164
+ return task;
165
+ }
166
+ export function recordTaskProgress(paths, params) {
167
+ const task = loadTask(paths, params.taskId);
168
+ if (!task)
169
+ return null;
170
+ saveTask(paths, task);
171
+ const event = appendEvent(paths.eventsFile, {
172
+ event: 'progress_report',
173
+ taskId: params.taskId,
174
+ phase: 'execution',
175
+ actor: params.actor,
176
+ payload: {
177
+ message: params.message,
178
+ unitId: params.unitId,
179
+ workPackage: params.workPackage,
180
+ },
181
+ });
182
+ rebuildIndex(paths);
183
+ return event;
184
+ }
185
+ // ─── Stale policy ───────────────────────────────────────────────────────────
186
+ export function findStaleTasks(paths, hours = 24) {
187
+ const cutoff = Date.now() - hours * 3600 * 1000;
188
+ return listTasks(paths).filter((task) => task.status === 'IN_PROGRESS' && Date.parse(task.updatedAt) < cutoff);
189
+ }
190
+ export function applyStalePolicy(paths, hours = 24, reason = 'stale_timeout') {
191
+ const staleTasks = findStaleTasks(paths, hours);
192
+ const changed = staleTasks.map((task) => {
193
+ task.status = 'BLOCKED';
194
+ saveTask(paths, task);
195
+ const event = appendEvent(paths.eventsFile, {
196
+ event: 'task_blocked',
197
+ taskId: task.taskId,
198
+ phase: 'recovery',
199
+ actor: 'zigrix',
200
+ status: 'BLOCKED',
201
+ payload: { reason, previousStatus: 'IN_PROGRESS', hoursThreshold: hours },
202
+ });
203
+ return { taskId: task.taskId, event };
204
+ });
205
+ rebuildIndex(paths);
206
+ return { ok: true, hours, reason, count: changed.length, changed };
207
+ }
208
+ // ─── Index ──────────────────────────────────────────────────────────────────
209
+ export function rebuildIndex(paths) {
210
+ ensureBaseState(paths);
211
+ const tasks = listTasks(paths);
212
+ const events = loadEvents(paths.eventsFile);
213
+ const activeStatuses = new Set(['OPEN', 'IN_PROGRESS', 'BLOCKED', 'DONE_PENDING_REPORT']);
214
+ const statusBuckets = {};
215
+ const taskSummaries = {};
216
+ const activeTasks = {};
217
+ for (const task of tasks) {
218
+ statusBuckets[task.status] ??= [];
219
+ statusBuckets[task.status].push(task.taskId);
220
+ const summary = {
221
+ title: task.title,
222
+ status: task.status,
223
+ scale: task.scale,
224
+ requiredAgents: task.requiredAgents,
225
+ projectDir: task.projectDir ?? null,
226
+ updatedAt: task.updatedAt,
227
+ };
228
+ taskSummaries[task.taskId] = summary;
229
+ if (activeStatuses.has(task.status))
230
+ activeTasks[task.taskId] = summary;
231
+ }
232
+ const index = {
233
+ version: '2.0',
234
+ updatedAt: nowIso(),
235
+ policy: {
236
+ sourceOfTruth: 'tasks.jsonl',
237
+ projection: 'index.json',
238
+ qaRequiredForAllScales: true,
239
+ },
240
+ counts: { tasks: tasks.length, events: events.length },
241
+ statusBuckets,
242
+ activeTasks,
243
+ taskSummaries,
244
+ };
245
+ fs.writeFileSync(paths.indexFile, `${JSON.stringify(index, null, 2)}\n`, 'utf8');
246
+ return index;
247
+ }
@@ -0,0 +1,2 @@
1
+ import { type ZigrixPaths } from './paths.js';
2
+ export declare function verifyState(paths: ZigrixPaths): Record<string, unknown>;
@@ -0,0 +1,65 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { listTasks } from './tasks.js';
4
+ function safeReadJson(filePath) {
5
+ try {
6
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ }
12
+ function verifyTask(paths, task) {
13
+ const issues = [];
14
+ const evidenceDir = path.join(paths.evidenceDir, task.taskId);
15
+ const mergedPath = path.join(evidenceDir, '_merged.json');
16
+ const merged = safeReadJson(mergedPath);
17
+ const presentEvidenceAgents = fs.existsSync(evidenceDir)
18
+ ? fs.readdirSync(evidenceDir).filter((name) => name.endsWith('.json') && name !== '_merged.json').map((name) => path.basename(name, '.json')).sort()
19
+ : [];
20
+ const requiredAgents = Array.isArray(task.requiredAgents) ? task.requiredAgents.map(String) : [];
21
+ const workerAgents = Object.keys(task.workerSessions ?? {}).sort();
22
+ for (const agentId of requiredAgents) {
23
+ if (!workerAgents.includes(agentId) && !presentEvidenceAgents.includes(agentId)) {
24
+ issues.push(`required agent '${agentId}' has neither worker session nor evidence`);
25
+ }
26
+ }
27
+ if (merged) {
28
+ const mergedPresent = Array.isArray(merged.presentAgents) ? merged.presentAgents.map(String).sort() : [];
29
+ const mergedMissing = Array.isArray(merged.missingAgents) ? merged.missingAgents.map(String).sort() : [];
30
+ const computedMissing = requiredAgents.filter((agentId) => !presentEvidenceAgents.includes(agentId)).sort();
31
+ if (JSON.stringify(mergedPresent) !== JSON.stringify(presentEvidenceAgents)) {
32
+ issues.push('merged presentAgents does not match evidence files');
33
+ }
34
+ if (JSON.stringify(mergedMissing) !== JSON.stringify(computedMissing)) {
35
+ issues.push('merged missingAgents does not match requiredAgents/evidence files');
36
+ }
37
+ if (task.status === 'REPORTED' && merged.complete !== true) {
38
+ issues.push('task is REPORTED but merged evidence is incomplete');
39
+ }
40
+ }
41
+ else if (task.status === 'REPORTED') {
42
+ issues.push('task is REPORTED but merged evidence is missing');
43
+ }
44
+ return {
45
+ taskId: task.taskId,
46
+ status: task.status,
47
+ requiredAgents,
48
+ workerAgents,
49
+ presentEvidenceAgents,
50
+ mergedExists: Boolean(merged),
51
+ ok: issues.length === 0,
52
+ issues,
53
+ };
54
+ }
55
+ export function verifyState(paths) {
56
+ const tasks = listTasks(paths);
57
+ const checks = tasks.map((task) => verifyTask(paths, task));
58
+ const failures = checks.filter((item) => item.ok === false);
59
+ return {
60
+ ok: failures.length === 0,
61
+ taskCount: tasks.length,
62
+ failedCount: failures.length,
63
+ checks,
64
+ };
65
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "hello-workflow",
3
+ "steps": [
4
+ {
5
+ "id": "say-hello",
6
+ "run": "echo hello from zigrix"
7
+ },
8
+ {
9
+ "id": "print-state-dir",
10
+ "run": "pwd"
11
+ }
12
+ ]
13
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "zigrix",
3
+ "version": "0.1.0-alpha.0",
4
+ "type": "module",
5
+ "description": "Multi-project parallel task orchestration CLI for agent-assisted development",
6
+ "license": "Apache-2.0",
7
+ "bin": {
8
+ "zigrix": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "skills",
13
+ "examples",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "clean": "rm -rf dist .zigrix",
20
+ "dev": "tsx src/index.ts",
21
+ "prebuild": "npm run clean",
22
+ "prepack": "npm run build",
23
+ "publish:check": "npm run build && npm run test && npm run smoke && bash scripts/release-smoke.sh && npm pack --dry-run && node dist/index.js state check --json",
24
+ "smoke": "node dist/index.js --version && node dist/index.js config validate --json",
25
+ "pretest": "npm run build",
26
+ "test": "vitest run",
27
+ "typecheck": "tsc -p tsconfig.json --noEmit"
28
+ },
29
+ "engines": {
30
+ "node": ">=22"
31
+ },
32
+ "dependencies": {
33
+ "@inquirer/prompts": "^8.3.2",
34
+ "commander": "^14.0.0",
35
+ "yaml": "^2.8.1",
36
+ "zod": "^4.1.5"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^24.3.0",
40
+ "tsx": "^4.20.5",
41
+ "typescript": "^5.9.2",
42
+ "vitest": "^3.2.4"
43
+ }
44
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: zigrix-doctor
3
+ version: 0.1.0
4
+ description: Inspect Zigrix environment readiness and OpenClaw integration prerequisites.
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ cliHelp: "zigrix doctor --help"
10
+ ---
11
+
12
+ # zigrix doctor
13
+
14
+ Run this before debugging install or integration issues.
15
+
16
+ ```bash
17
+ zigrix doctor --json
18
+ ```
19
+
20
+ Returns Python, path, binary, and OpenClaw-home readiness details.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: zigrix-evidence
3
+ version: 0.2.0
4
+ description: Collect and merge task evidence in Zigrix.
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ cliHelp: "zigrix evidence --help"
10
+ ---
11
+
12
+ # zigrix evidence
13
+
14
+ Use evidence commands to persist verification outputs and merge completion state.
15
+
16
+ ```bash
17
+ zigrix evidence collect --task-id DEV-20260316-001 --agent-id qa-zig --summary "QA passed" --json
18
+ zigrix evidence merge --task-id DEV-20260316-001 --require-qa --json
19
+ ```
20
+
21
+ Evidence files are stored under `~/.zigrix/evidence/<taskId>/`.
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: zigrix-init
3
+ version: 0.2.0
4
+ description: "[DEPRECATED] Use zigrix onboard instead."
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ ---
10
+
11
+ # Zigrix Init (Deprecated)
12
+
13
+ **Use `zigrix onboard` instead.**
14
+
15
+ `zigrix init` is a deprecated compatibility command. It creates a config file but does not perform PATH stabilization, skill registration, or agent import.
16
+
17
+ ```bash
18
+ # Preferred
19
+ zigrix onboard --yes --json
20
+
21
+ # Legacy (deprecated)
22
+ zigrix init --yes --json
23
+ ```
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: zigrix-report
3
+ version: 0.1.0
4
+ description: Render a user-facing Zigrix completion report from merged evidence.
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ cliHelp: "zigrix report --help"
10
+ ---
11
+
12
+ # zigrix report
13
+
14
+ Render a user-facing completion summary after evidence merge.
15
+
16
+ ```bash
17
+ zigrix report render --task-id TASK-20260313-001 --record-events --json
18
+ ```
19
+
20
+ When `--record-events` is enabled, Zigrix appends `user_report_prepared` and `feedback_requested` events.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: zigrix-shared
3
+ version: 0.2.0
4
+ description: Shared guidance for Zigrix CLI usage, output modes, and safety.
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ ---
10
+
11
+ # Zigrix Shared Reference
12
+
13
+ Use Zigrix for multi-project parallel task orchestration with file-backed, inspectable state.
14
+
15
+ ## Rules
16
+ - Prefer `--json` for automation-heavy flows.
17
+ - Global state lives in `~/.zigrix/` (override: `ZIGRIX_HOME` env).
18
+ - Tasks are NOT project-bound — one Zigrix instance manages tasks across projects.
19
+ - Do not assume OpenClaw internals are required unless the task explicitly needs them.
20
+
21
+ ## Common commands
22
+ ```bash
23
+ zigrix doctor --json
24
+ zigrix task list --json
25
+ zigrix task dispatch --title "..." --description "..." --scale normal --json
26
+ zigrix task finalize <taskId> --auto-report --json
27
+ ```
28
+
29
+ ## Safety
30
+ - Confirm before destructive actions.
31
+ - Treat runtime state and source code as separate concerns.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: zigrix-task-create
3
+ version: 0.2.0
4
+ description: Create a new Zigrix task with title, description, and scale.
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ cliHelp: "zigrix task create --help"
10
+ ---
11
+
12
+ # zigrix task create
13
+
14
+ Create a task in `~/.zigrix/tasks/`.
15
+
16
+ For full orchestration metadata (work packages, execution units, boot prompt), use `zigrix task dispatch` instead.
17
+
18
+ ```bash
19
+ # Low-level task creation
20
+ zigrix task create \
21
+ --title "Implement installer" \
22
+ --description "Create a safe app-owned venv installer" \
23
+ --scale normal \
24
+ --json
25
+
26
+ # Full orchestration dispatch (preferred for agent workflows)
27
+ zigrix task dispatch \
28
+ --title "Implement installer" \
29
+ --description "Create a safe app-owned venv installer" \
30
+ --scale normal \
31
+ --json
32
+ ```
33
+
34
+ Prefer `--json` when another agent or script will consume the result.
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: zigrix-task-status
3
+ version: 0.1.0
4
+ description: Inspect Zigrix task records and state transitions.
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ cliHelp: "zigrix task status --help"
10
+ ---
11
+
12
+ # zigrix task status
13
+
14
+ Use this to inspect one task or list tasks.
15
+
16
+ ```bash
17
+ zigrix task list --json
18
+ zigrix task status TASK-20260313-001 --json
19
+ zigrix task events TASK-20260313-001 --json
20
+ zigrix task progress --task-id TASK-20260313-001 --actor pro-zig --message "진행 상황 요약" --json
21
+ zigrix task stale --hours 24 --json
22
+ zigrix task start TASK-20260313-001
23
+ zigrix task finalize TASK-20260313-001
24
+ zigrix task report TASK-20260313-001
25
+ ```
26
+
27
+ Treat status transitions as explicit lifecycle events.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: zigrix-worker
3
+ version: 0.2.0
4
+ description: Prepare, register, and complete Zigrix worker runs.
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ bins: ["zigrix"]
9
+ cliHelp: "zigrix worker --help"
10
+ ---
11
+
12
+ # zigrix worker
13
+
14
+ Use worker lifecycle commands to bridge agent execution and global orchestration state.
15
+
16
+ ```bash
17
+ zigrix worker prepare --task-id DEV-20260316-001 --agent-id qa-zig --description "Run QA checks" --json
18
+ zigrix worker register --task-id DEV-20260316-001 --agent-id qa-zig --session-key agent:test:qa --run-id run-001 --json
19
+ zigrix worker complete --task-id DEV-20260316-001 --agent-id qa-zig --session-key agent:test:qa --run-id run-001 --json
20
+ ```
21
+
22
+ These commands intentionally avoid hard-coding OpenClaw internals into the Zigrix core.