arkaos 4.43.0 → 4.44.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/THE-ARKAOS-GUIDE.md +1 -1
- package/VERSION +1 -1
- package/config/hooks/agent-provision.sh +35 -14
- package/core/governance/aggregate_guard.py +32 -6
- package/core/governance/quality_api.py +13 -17
- package/core/governance/review_workflow.py +26 -12
- package/core/hooks/stop.py +67 -21
- package/harness/codex/AGENTS.md +1 -1
- package/harness/copilot/copilot-instructions.md +1 -1
- package/harness/cursor/rules/arkaos.mdc +2 -2
- package/harness/gemini/GEMINI.md +1 -1
- package/harness/opencode/AGENTS.md +1 -1
- package/harness/opencode/agents/arka-architect-gabriel.md +1 -1
- package/harness/opencode/agents/arka-brand-director-valentina.md +1 -1
- package/harness/opencode/agents/arka-cfo-helena.md +1 -1
- package/harness/opencode/agents/arka-chief-of-staff-afonso.md +1 -1
- package/harness/opencode/agents/arka-community-strategist-beatriz.md +1 -1
- package/harness/opencode/agents/arka-content-strategist-rafael.md +1 -1
- package/harness/opencode/agents/arka-conversion-strategist-ines.md +1 -1
- package/harness/opencode/agents/arka-coo-sofia.md +1 -1
- package/harness/opencode/agents/arka-copy-director-eduardo.md +1 -1
- package/harness/opencode/agents/arka-cqo-marta.md +1 -1
- package/harness/opencode/agents/arka-cto-marco.md +1 -1
- package/harness/opencode/agents/arka-design-ops-lead-iris.md +1 -1
- package/harness/opencode/agents/arka-ecom-director-ricardo.md +1 -1
- package/harness/opencode/agents/arka-knowledge-director-clara.md +1 -1
- package/harness/opencode/agents/arka-leadership-director-rodrigo.md +1 -1
- package/harness/opencode/agents/arka-marketing-director-luna.md +1 -1
- package/harness/opencode/agents/arka-ops-lead-daniel.md +1 -1
- package/harness/opencode/agents/arka-pm-director-carolina.md +1 -1
- package/harness/opencode/agents/arka-revops-lead-vicente.md +1 -1
- package/harness/opencode/agents/arka-saas-strategist-tiago.md +1 -1
- package/harness/opencode/agents/arka-sales-director-miguel.md +1 -1
- package/harness/opencode/agents/arka-strategy-director-tomas.md +1 -1
- package/harness/opencode/agents/arka-tech-director-francisca.md +1 -1
- package/harness/opencode/agents/arka-tech-lead-paulo.md +1 -1
- package/harness/opencode/agents/arka-video-producer-simao.md +1 -1
- package/harness/zed/.rules +1 -1
- package/installer/adapters/claude-code.js +88 -3
- package/installer/doctor.js +121 -3
- package/installer/index.js +17 -0
- package/installer/skill-deploy.js +43 -2
- package/installer/update.js +12 -0
- package/knowledge/skills-manifest.json +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/THE-ARKAOS-GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The ArkaOS Guide
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.44.0 — 89 agents, 17 departments, 332 skills, 297 commands, 18 ADRs.
|
|
4
4
|
> One file, everything you need to start. Generated by `scripts/guide_gen.py` — never hand-edited.
|
|
5
5
|
|
|
6
6
|
## What it is
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.44.0
|
|
@@ -2,11 +2,23 @@
|
|
|
2
2
|
# ArkaOS PreToolUse hook for dynamic agent provisioning.
|
|
3
3
|
# Intercepts Task tool calls: if subagent_type is not present in the
|
|
4
4
|
# project's .claude/agents/, copies it from ArkaOS core when available,
|
|
5
|
-
# or
|
|
6
|
-
#
|
|
5
|
+
# or surfaces an approval-request message WITHOUT blocking when the
|
|
6
|
+
# agent is unknown. The set of valid subagent_types is not enumerable
|
|
7
|
+
# here — runtime built-ins (general-purpose, statusline-setup, …)
|
|
8
|
+
# change with Claude Code versions and plugins add their own — so any
|
|
9
|
+
# blocking arm on "unknown" breaks legitimate dispatches (QG PR-B5 r1
|
|
10
|
+
# reproduced exit 2 on general-purpose). Provision when we know the
|
|
11
|
+
# name; stand aside when we don't.
|
|
7
12
|
|
|
8
13
|
set -euo pipefail
|
|
9
14
|
|
|
15
|
+
# No jq, no payload parse. .claude/rules/bash-hooks.md:11-12 prescribes
|
|
16
|
+
# a python3 fallback for jq; this gate is OPTIONAL by design, so it
|
|
17
|
+
# stands aside instead of paying a python spawn on every Task call —
|
|
18
|
+
# and per the same rules file ("exit code 2 = block action", last
|
|
19
|
+
# bullet), exiting 0 here can never break a dispatch.
|
|
20
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
21
|
+
|
|
10
22
|
# ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
|
|
11
23
|
# The resolver guards its own ARKA_PY assignment with `|| true`, so sourcing
|
|
12
24
|
# is set -e-safe even on the last-resort fallback. The trailing `|| true`
|
|
@@ -49,7 +61,6 @@ if [ -z "$core_root" ]; then
|
|
|
49
61
|
fi
|
|
50
62
|
|
|
51
63
|
if [ -d "$core_root/departments" ]; then
|
|
52
|
-
mkdir -p "$project_agents_dir"
|
|
53
64
|
set +e
|
|
54
65
|
"$ARKA_PY" - "$core_root" "$subagent_type" "$target" <<'PY'
|
|
55
66
|
import os, re, sys
|
|
@@ -105,7 +116,10 @@ if md_path is not None:
|
|
|
105
116
|
|
|
106
117
|
content = "\n".join(parts) + "\n"
|
|
107
118
|
|
|
108
|
-
#
|
|
119
|
+
# Create the parent only on the arm that actually writes (a dispatch
|
|
120
|
+
# of an unknown name must not scatter empty .claude/agents/ dirs), then
|
|
121
|
+
# atomic write: temp file in same dir, then os.replace.
|
|
122
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
109
123
|
tmp = target.with_suffix(".md.tmp")
|
|
110
124
|
tmp.write_text(content)
|
|
111
125
|
os.replace(tmp, target)
|
|
@@ -128,15 +142,22 @@ PY
|
|
|
128
142
|
esac
|
|
129
143
|
fi
|
|
130
144
|
|
|
131
|
-
# Agent not in project and
|
|
145
|
+
# Agent not in project, and the core lookup either found nothing or
|
|
146
|
+
# never ran. Say exactly which, and NEVER block: this name may be a
|
|
147
|
+
# runtime built-in or a plugin agent this script cannot know about —
|
|
148
|
+
# if it truly doesn't exist, the Task dispatch itself fails with the
|
|
149
|
+
# runtime's own error.
|
|
150
|
+
if [ -d "$core_root/departments" ]; then
|
|
151
|
+
core_note="no ArkaOS core agent of that name was found (core searched at: $core_root)"
|
|
152
|
+
else
|
|
153
|
+
core_note="the ArkaOS core lookup did not run (no departments/ under: ${core_root:-<unset>})"
|
|
154
|
+
fi
|
|
132
155
|
cat >&2 <<MSG
|
|
133
|
-
[arka:provision-needed] Agent '$subagent_type' is not
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
4-framework DNA, goes through Quality Gate, and commits to core before
|
|
140
|
-
propagating to the project. Blocking dispatch until the agent exists.
|
|
156
|
+
[arka:provision-needed] Agent '$subagent_type' is not in this project's
|
|
157
|
+
.claude/agents/, and $core_note.
|
|
158
|
+
If ArkaOS should provide this agent, create it at
|
|
159
|
+
.claude/agents/$subagent_type.md, or run 'npx arkaos update' so ArkaOS
|
|
160
|
+
core ships a definition this gate can copy.
|
|
161
|
+
Runtime built-ins and plugin agents are unaffected — dispatch proceeds.
|
|
141
162
|
MSG
|
|
142
|
-
exit
|
|
163
|
+
exit 0
|
|
@@ -391,12 +391,33 @@ def _digest_issues(
|
|
|
391
391
|
return issues, notes
|
|
392
392
|
|
|
393
393
|
|
|
394
|
-
def _ended_issues(session_id: str) -> list[str]:
|
|
395
|
-
"""A stamped session is not a live quorum (PR-B4 session binding).
|
|
394
|
+
def _ended_issues(session_id: str, artifact_names: list[str]) -> list[str]:
|
|
395
|
+
"""A stamped session is not a live quorum (PR-B4 session binding).
|
|
396
|
+
|
|
397
|
+
M4 hardening (PR-B5): the stamp only outlaws records that PREDATE
|
|
398
|
+
it. A counted record captured strictly after the stamp's mtime
|
|
399
|
+
proves the hook boundary came back to life under this session id —
|
|
400
|
+
never observed on the dev machine, where the stamp shipped one
|
|
401
|
+
release earlier and the ledger held a single stamped session when
|
|
402
|
+
this was written; the refusal must not outlive its own evidence.
|
|
403
|
+
Ties and unreadable mtimes keep the refusal: equality cannot
|
|
404
|
+
distinguish before from after, and fail-closed is the guard's
|
|
405
|
+
resting state.
|
|
406
|
+
"""
|
|
396
407
|
from core.governance.reviewer_ledger import ENDED_NAME
|
|
397
408
|
|
|
398
|
-
|
|
409
|
+
session_dir = ledger_root() / session_id
|
|
410
|
+
stamp = session_dir / ENDED_NAME
|
|
411
|
+
if not stamp.is_file():
|
|
399
412
|
return []
|
|
413
|
+
try:
|
|
414
|
+
newest = max(
|
|
415
|
+
(session_dir / name).stat().st_mtime for name in artifact_names
|
|
416
|
+
)
|
|
417
|
+
if newest > stamp.stat().st_mtime:
|
|
418
|
+
return []
|
|
419
|
+
except (OSError, ValueError):
|
|
420
|
+
pass # no readable counted record newer than the stamp
|
|
400
421
|
return [
|
|
401
422
|
f"session {session_id} is marked ended (SessionEnd stamped its "
|
|
402
423
|
"ledger) — a past session's reviewer records are not a reusable "
|
|
@@ -568,7 +589,9 @@ def check_aggregate(aggregate: dict, session_id: str) -> GuardResult:
|
|
|
568
589
|
reviewers, [name for name, _ in counted]
|
|
569
590
|
)
|
|
570
591
|
verdicts = [(str(r.get("reviewer_id")), r["verdict"]) for _, r in counted]
|
|
571
|
-
reasons, warnings = _reasons(
|
|
592
|
+
reasons, warnings = _reasons(
|
|
593
|
+
aggregate, verdicts, session_id, [name for name, _ in counted]
|
|
594
|
+
)
|
|
572
595
|
return GuardResult(
|
|
573
596
|
ok=not reasons,
|
|
574
597
|
reasons=reasons,
|
|
@@ -579,7 +602,10 @@ def check_aggregate(aggregate: dict, session_id: str) -> GuardResult:
|
|
|
579
602
|
|
|
580
603
|
|
|
581
604
|
def _reasons(
|
|
582
|
-
aggregate: dict,
|
|
605
|
+
aggregate: dict,
|
|
606
|
+
verdicts: list[tuple[str, dict]],
|
|
607
|
+
session_id: str,
|
|
608
|
+
artifact_names: list[str],
|
|
583
609
|
) -> tuple[list[str], list[str]]:
|
|
584
610
|
"""Every refusal reason and warning for one aggregate.
|
|
585
611
|
|
|
@@ -594,7 +620,7 @@ def _reasons(
|
|
|
594
620
|
"""
|
|
595
621
|
approved = _norm(aggregate.get("verdict")) == "approved"
|
|
596
622
|
issues, notes = _digest_issues(aggregate, verdicts)
|
|
597
|
-
issues += _ended_issues(session_id)
|
|
623
|
+
issues += _ended_issues(session_id, artifact_names)
|
|
598
624
|
reasons = (
|
|
599
625
|
_verdict_reasons(aggregate, verdicts)
|
|
600
626
|
+ _blocker_reasons(aggregate, verdicts, approved)
|
|
@@ -8,26 +8,15 @@ Provides a simple programmatic interface for the Quality Gate system:
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
from datetime import UTC
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
from typing import Any
|
|
13
14
|
|
|
14
15
|
from core.governance.quality_router import (
|
|
15
|
-
QualityRouter,
|
|
16
|
-
ReviewAssignment,
|
|
17
|
-
ReviewerType,
|
|
18
16
|
DeliverableType,
|
|
19
|
-
|
|
20
|
-
route_deliverable,
|
|
21
|
-
)
|
|
22
|
-
from core.governance.review_workflow import (
|
|
23
|
-
ReviewWorkflowEngine,
|
|
24
|
-
ReviewWorkflow,
|
|
25
|
-
ReviewPhase,
|
|
26
|
-
Verdict,
|
|
27
|
-
ReviewerOpinion,
|
|
17
|
+
QualityRouter,
|
|
28
18
|
)
|
|
29
19
|
|
|
30
|
-
|
|
31
20
|
_STATE_DIR = Path.home() / ".arkaos" / "quality-gate"
|
|
32
21
|
_QUEUE_FILE = _STATE_DIR / "queue.json"
|
|
33
22
|
_WORKFLOWS_FILE = _STATE_DIR / "workflows.json"
|
|
@@ -147,6 +136,14 @@ def record_verdict(
|
|
|
147
136
|
) -> bool:
|
|
148
137
|
"""Record a reviewer's verdict for a submission.
|
|
149
138
|
|
|
139
|
+
.. deprecated:: 4.44.0 (PR-B5)
|
|
140
|
+
Writes an unguarded label: no ledger artifact, no digest, no
|
|
141
|
+
aggregate guard. Use ``core.evals.record_cli``: ``--kind qg``
|
|
142
|
+
passes ``aggregate_guard.check_aggregate``, which requires at
|
|
143
|
+
least two hook-captured reviewer artifacts in the session
|
|
144
|
+
ledger; ``--kind reviewer`` remains an unguarded label path —
|
|
145
|
+
its ledger cross-reference is provenance, not admission.
|
|
146
|
+
|
|
150
147
|
Args:
|
|
151
148
|
submission_id: ID of the submission
|
|
152
149
|
reviewer: Agent ID of reviewer
|
|
@@ -157,8 +154,6 @@ def record_verdict(
|
|
|
157
154
|
Returns:
|
|
158
155
|
True if verdict recorded successfully
|
|
159
156
|
"""
|
|
160
|
-
reviewer_type = ReviewerType(reviewer) if reviewer in [r.value for r in ReviewerType] else None
|
|
161
|
-
|
|
162
157
|
queue = _load_queue()
|
|
163
158
|
for item in queue:
|
|
164
159
|
if item["id"] == submission_id:
|
|
@@ -217,9 +212,9 @@ def clear_resolved(older_than_days: int = 7) -> int:
|
|
|
217
212
|
Returns:
|
|
218
213
|
Number of items removed
|
|
219
214
|
"""
|
|
220
|
-
from datetime import datetime, timedelta
|
|
215
|
+
from datetime import datetime, timedelta
|
|
221
216
|
|
|
222
|
-
cutoff = datetime.now(
|
|
217
|
+
cutoff = datetime.now(UTC) - timedelta(days=older_than_days)
|
|
223
218
|
queue = _load_queue()
|
|
224
219
|
original_count = len(queue)
|
|
225
220
|
|
|
@@ -268,6 +263,7 @@ class QualityGateAPI:
|
|
|
268
263
|
feedback: str = "",
|
|
269
264
|
flagged_rules: list[str] | None = None,
|
|
270
265
|
) -> bool:
|
|
266
|
+
"""Deprecated with the module function — see ``record_verdict``."""
|
|
271
267
|
return record_verdict(submission_id, reviewer, verdict, feedback, flagged_rules)
|
|
272
268
|
|
|
273
269
|
def list_pending(self, reviewer: str | None = None) -> list[dict]:
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
"""Review Workflow Engine — structured review phases for Quality Gate.
|
|
2
2
|
|
|
3
|
+
.. deprecated:: 4.44.0 (PR-B5)
|
|
4
|
+
This engine models review phases in memory and records verdicts
|
|
5
|
+
WITHOUT the reviewer ledger or the aggregate guard behind them —
|
|
6
|
+
nothing here proves a verdict was authored at the hook boundary.
|
|
7
|
+
The guarded path is ``core.evals.record_cli``: ``--kind qg`` passes
|
|
8
|
+
``aggregate_guard.check_aggregate``, which requires hook-captured
|
|
9
|
+
reviewer artifacts in the session ledger. The module stays
|
|
10
|
+
importable because live tests pin its phase mechanics, but no new
|
|
11
|
+
caller should route verdicts through it.
|
|
12
|
+
|
|
3
13
|
Phases:
|
|
4
14
|
1. Submission — deliverable submitted for review
|
|
5
15
|
2. Triage — initial assessment, assign reviewers
|
|
@@ -16,13 +26,17 @@ Verdicts:
|
|
|
16
26
|
"""
|
|
17
27
|
|
|
18
28
|
import uuid
|
|
29
|
+
from collections.abc import Callable
|
|
19
30
|
from dataclasses import dataclass, field
|
|
20
|
-
from datetime import
|
|
31
|
+
from datetime import UTC, datetime
|
|
21
32
|
from enum import Enum
|
|
22
|
-
from typing import Callable
|
|
23
33
|
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
# UP042 suppressed on the three enums below: switching to StrEnum changes
|
|
36
|
+
# str(member) from "Verdict.APPROVED" to "APPROVED" — behaviour, not
|
|
37
|
+
# style — and this module is deprecated (see the module docstring), not
|
|
38
|
+
# being modernised.
|
|
39
|
+
class ReviewPhase(str, Enum): # noqa: UP042
|
|
26
40
|
SUBMISSION = "submission"
|
|
27
41
|
TRIAGE = "triage"
|
|
28
42
|
REVIEW = "review"
|
|
@@ -31,14 +45,14 @@ class ReviewPhase(str, Enum):
|
|
|
31
45
|
DELIVERY = "delivery"
|
|
32
46
|
|
|
33
47
|
|
|
34
|
-
class Verdict(str, Enum):
|
|
48
|
+
class Verdict(str, Enum): # noqa: UP042
|
|
35
49
|
APPROVED = "APPROVED"
|
|
36
50
|
REJECTED = "REJECTED"
|
|
37
51
|
REQUEST_CHANGES = "REQUEST_CHANGES"
|
|
38
52
|
ESCALATE = "ESCALATE"
|
|
39
53
|
|
|
40
54
|
|
|
41
|
-
class ReviewerOpinion(str, Enum):
|
|
55
|
+
class ReviewerOpinion(str, Enum): # noqa: UP042
|
|
42
56
|
APPROVE = "APPROVE"
|
|
43
57
|
REJECT = "REJECT"
|
|
44
58
|
CHANGES = "REQUEST_CHANGES"
|
|
@@ -79,7 +93,7 @@ class ReviewWorkflow:
|
|
|
79
93
|
|
|
80
94
|
def __post_init__(self):
|
|
81
95
|
if not self.submitted_at:
|
|
82
|
-
self.submitted_at = datetime.now(
|
|
96
|
+
self.submitted_at = datetime.now(UTC).isoformat()
|
|
83
97
|
|
|
84
98
|
|
|
85
99
|
@dataclass
|
|
@@ -156,7 +170,7 @@ class ReviewWorkflowEngine:
|
|
|
156
170
|
self._announce_phase_start(ReviewPhase.TRIAGE, workflow_id)
|
|
157
171
|
|
|
158
172
|
workflow.phase = ReviewPhase.TRIAGE
|
|
159
|
-
workflow.triage_at = datetime.now(
|
|
173
|
+
workflow.triage_at = datetime.now(UTC).isoformat()
|
|
160
174
|
|
|
161
175
|
result = PhaseResult(
|
|
162
176
|
phase=ReviewPhase.TRIAGE,
|
|
@@ -191,7 +205,7 @@ class ReviewWorkflowEngine:
|
|
|
191
205
|
self._announce_phase_start(ReviewPhase.REVIEW, workflow_id)
|
|
192
206
|
|
|
193
207
|
workflow.phase = ReviewPhase.REVIEW
|
|
194
|
-
workflow.review_started_at = datetime.now(
|
|
208
|
+
workflow.review_started_at = datetime.now(UTC).isoformat()
|
|
195
209
|
|
|
196
210
|
result = PhaseResult(
|
|
197
211
|
phase=ReviewPhase.REVIEW,
|
|
@@ -248,7 +262,7 @@ class ReviewWorkflowEngine:
|
|
|
248
262
|
opinion=opinion,
|
|
249
263
|
comments=comments,
|
|
250
264
|
flagged_rules=flagged_rules or [],
|
|
251
|
-
voted_at=datetime.now(
|
|
265
|
+
voted_at=datetime.now(UTC).isoformat(),
|
|
252
266
|
evidence_overall=evidence_overall,
|
|
253
267
|
)
|
|
254
268
|
workflow.votes.append(vote)
|
|
@@ -279,7 +293,7 @@ class ReviewWorkflowEngine:
|
|
|
279
293
|
self._announce_phase_start(ReviewPhase.DELIBERATION, workflow_id)
|
|
280
294
|
|
|
281
295
|
workflow.phase = ReviewPhase.DELIBERATION
|
|
282
|
-
workflow.deliberation_at = datetime.now(
|
|
296
|
+
workflow.deliberation_at = datetime.now(UTC).isoformat()
|
|
283
297
|
|
|
284
298
|
result = PhaseResult(
|
|
285
299
|
phase=ReviewPhase.DELIBERATION,
|
|
@@ -331,7 +345,7 @@ class ReviewWorkflowEngine:
|
|
|
331
345
|
workflow.phase = ReviewPhase.VERDICT
|
|
332
346
|
workflow.verdict = verdict
|
|
333
347
|
workflow.feedback = feedback
|
|
334
|
-
workflow.verdict_at = datetime.now(
|
|
348
|
+
workflow.verdict_at = datetime.now(UTC).isoformat()
|
|
335
349
|
|
|
336
350
|
self._announce_verdict(verdict, workflow_id)
|
|
337
351
|
|
|
@@ -370,7 +384,7 @@ class ReviewWorkflowEngine:
|
|
|
370
384
|
)
|
|
371
385
|
|
|
372
386
|
workflow.phase = ReviewPhase.DELIVERY
|
|
373
|
-
workflow.delivered_at = datetime.now(
|
|
387
|
+
workflow.delivered_at = datetime.now(UTC).isoformat()
|
|
374
388
|
|
|
375
389
|
result = PhaseResult(
|
|
376
390
|
phase=ReviewPhase.DELIVERY,
|
package/core/hooks/stop.py
CHANGED
|
@@ -371,6 +371,60 @@ def _flow_checks(
|
|
|
371
371
|
clear_flow_required(session_id)
|
|
372
372
|
|
|
373
373
|
|
|
374
|
+
def _qg_aggregate_verdict(session_id: str) -> bool | None:
|
|
375
|
+
"""Verdict from the session's guard-accepted ``AGGREGATE.json``.
|
|
376
|
+
|
|
377
|
+
True/False when a readable aggregate for THIS session exists — the
|
|
378
|
+
aggregate only lands on disk through aggregate_guard (PR-B3), so it
|
|
379
|
+
is authoritative in both directions. None when absent, foreign or
|
|
380
|
+
unreadable: only then may the caller fall back to the telemetry log.
|
|
381
|
+
"""
|
|
382
|
+
try:
|
|
383
|
+
from core.governance.reviewer_ledger import (
|
|
384
|
+
AGGREGATE_NAME,
|
|
385
|
+
_safe_id,
|
|
386
|
+
ledger_root,
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
if not _safe_id(session_id):
|
|
390
|
+
return None
|
|
391
|
+
rec = json.loads(
|
|
392
|
+
(ledger_root() / session_id / AGGREGATE_NAME).read_text(
|
|
393
|
+
encoding="utf-8"
|
|
394
|
+
)
|
|
395
|
+
)
|
|
396
|
+
except Exception:
|
|
397
|
+
return None
|
|
398
|
+
if not isinstance(rec, dict) or rec.get("session_id") != session_id:
|
|
399
|
+
return None
|
|
400
|
+
verdict = (rec.get("aggregate") or {}).get("verdict", "")
|
|
401
|
+
return str(verdict).upper() == "APPROVED"
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _qg_telemetry_approved(session_id: str) -> bool:
|
|
405
|
+
"""Legacy fallback: newest ``qg.jsonl`` record for this session.
|
|
406
|
+
|
|
407
|
+
Pre-B3 sessions have no aggregate, so its absence proves nothing;
|
|
408
|
+
the unguarded telemetry log then keeps its historical role.
|
|
409
|
+
"""
|
|
410
|
+
qg_log = Path.home() / ".arkaos" / "telemetry" / "qg.jsonl"
|
|
411
|
+
if not qg_log.exists():
|
|
412
|
+
return False
|
|
413
|
+
try:
|
|
414
|
+
for line in reversed(qg_log.read_text(encoding="utf-8").splitlines()):
|
|
415
|
+
if not line.strip():
|
|
416
|
+
continue
|
|
417
|
+
try:
|
|
418
|
+
rec = json.loads(line)
|
|
419
|
+
except Exception:
|
|
420
|
+
continue
|
|
421
|
+
if rec.get("session_id") == session_id:
|
|
422
|
+
return rec.get("verdict", "").upper() == "APPROVED"
|
|
423
|
+
except Exception:
|
|
424
|
+
pass
|
|
425
|
+
return False
|
|
426
|
+
|
|
427
|
+
|
|
374
428
|
def _auto_doc_enqueue(
|
|
375
429
|
session_id: str, transcript_path: str, raw: str | None
|
|
376
430
|
) -> None:
|
|
@@ -389,27 +443,19 @@ def _auto_doc_enqueue(
|
|
|
389
443
|
except Exception:
|
|
390
444
|
last = ""
|
|
391
445
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
continue
|
|
406
|
-
if rec.get("session_id") == session_id:
|
|
407
|
-
qg_approved = (
|
|
408
|
-
rec.get("verdict", "").upper() == "APPROVED"
|
|
409
|
-
)
|
|
410
|
-
break
|
|
411
|
-
except Exception:
|
|
412
|
-
pass
|
|
446
|
+
# The guard-accepted aggregate is authoritative either way (PR-B5,
|
|
447
|
+
# G7) — over the telemetry log AND over the assistant's own
|
|
448
|
+
# [arka:qg:approved] marker: narration must not outrank the record
|
|
449
|
+
# it narrates (the same laundering shape G7 closes one layer down).
|
|
450
|
+
# Marker and telemetry keep their historical roles only when no
|
|
451
|
+
# aggregate exists for the session.
|
|
452
|
+
from_aggregate = _qg_aggregate_verdict(session_id)
|
|
453
|
+
if from_aggregate is not None:
|
|
454
|
+
qg_approved = from_aggregate
|
|
455
|
+
else:
|
|
456
|
+
qg_approved = bool(
|
|
457
|
+
re.search(r"\[arka:qg:approved\]", last, re.IGNORECASE)
|
|
458
|
+
) or _qg_telemetry_approved(session_id)
|
|
413
459
|
if not qg_approved:
|
|
414
460
|
return
|
|
415
461
|
|
package/harness/codex/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ArkaOS — The Operating System for AI Agent Teams
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.44.0 — 89 agents, 17 departments, 332 skills. Generated by `scripts/harness_gen.py`; do not edit.
|
|
4
4
|
|
|
5
5
|
You are operating within ArkaOS. Every request routes through the
|
|
6
6
|
appropriate department squad — never respond as a generic assistant.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ArkaOS — The Operating System for AI Agent Teams
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.44.0 — 89 agents, 17 departments, 332 skills. Generated by `scripts/harness_gen.py`; do not edit.
|
|
4
4
|
|
|
5
5
|
You are operating within ArkaOS. Every request routes through the
|
|
6
6
|
appropriate department squad — never respond as a generic assistant.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: ArkaOS v4.
|
|
2
|
+
description: ArkaOS v4.44.0 agent-team contract
|
|
3
3
|
alwaysApply: true
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# ArkaOS — The Operating System for AI Agent Teams
|
|
7
7
|
|
|
8
|
-
> v4.
|
|
8
|
+
> v4.44.0 — 89 agents, 17 departments, 332 skills. Generated by `scripts/harness_gen.py`; do not edit.
|
|
9
9
|
|
|
10
10
|
You are operating within ArkaOS. Every request routes through the
|
|
11
11
|
appropriate department squad — never respond as a generic assistant.
|
package/harness/gemini/GEMINI.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ArkaOS — The Operating System for AI Agent Teams
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.44.0 — 89 agents, 17 departments, 332 skills. Generated by `scripts/harness_gen.py`; do not edit.
|
|
4
4
|
|
|
5
5
|
You are operating within ArkaOS. Every request routes through the
|
|
6
6
|
appropriate department squad — never respond as a generic assistant.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ArkaOS — The Operating System for AI Agent Teams
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.44.0 — 89 agents, 17 departments, 332 skills. Generated by `scripts/harness_gen.py`; do not edit.
|
|
4
4
|
|
|
5
5
|
You are operating within ArkaOS. Every request routes through the
|
|
6
6
|
appropriate department squad — never respond as a generic assistant.
|
|
@@ -3,7 +3,7 @@ description: "Software Architect — ArkaOS /dev department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Gabriel, Software Architect of the ArkaOS /dev department (v4.
|
|
6
|
+
You are Gabriel, Software Architect of the ArkaOS /dev department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: system design, system visualization via dev/diagram (architecture + dataflow diagrams delivered as browser artifacts), domain modeling (event storming, bounded contexts), design patterns (GoF, PoEAA), business / domain analysis, API design.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Creative Director — ArkaOS /brand department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Valentina, Creative Director of the ArkaOS /brand department (v4.
|
|
6
|
+
You are Valentina, Creative Director of the ArkaOS /brand department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: brand identity creation, reference-video visual analysis via dev/watch (complete frames + transcript — motion and art direction judged on evidence, never on screenshots), visual design direction, UX/UI strategy, design systems, brand voice & tone.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Chief Financial Officer — ArkaOS /fin department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Helena, Chief Financial Officer of the ArkaOS /fin department (v4.
|
|
6
|
+
You are Helena, Chief Financial Officer of the ArkaOS /fin department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: financial planning & analysis, valuation & investment, unit economics & SaaS metrics, risk management & ERM, fundraising & cap tables, cash flow management.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Chief of Staff & Governance Lead — ArkaOS /org department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Afonso, Chief of Staff & Governance Lead of the ArkaOS /org department (v4.
|
|
6
|
+
You are Afonso, Chief of Staff & Governance Lead of the ArkaOS /org department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: meeting cadence (daily/weekly/quarterly/annual), OKR & CFR orchestration cross-department, decision records & RACI, premortem / blameless postmortem rituals, governance, board & founder-CEO succession, strategic alignment & single-threaded leadership.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Community Strategist — ArkaOS /community department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Beatriz, Community Strategist of the ArkaOS /community department (v4.
|
|
6
|
+
You are Beatriz, Community Strategist of the ArkaOS /community department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: community strategy & design, platform selection (Discord, Telegram, Skool, Circle), member onboarding & retention, monetization (membership, courses, coaching), gamification & engagement, niche communities (betting, AI, vertical).
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Content Strategist — ArkaOS /content department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Rafael, Content Strategist of the ArkaOS /content department (v4.
|
|
6
|
+
You are Rafael, Content Strategist of the ArkaOS /content department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: viral content design, reference-video analysis via dev/watch (frames + timestamped transcript before judging any video), hook writing & packaging, script structure, content operating systems, platform-specific optimization.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Conversion Strategist — ArkaOS /landing department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Ines, Conversion Strategist of the ArkaOS /landing department (v4.
|
|
6
|
+
You are Ines, Conversion Strategist of the ArkaOS /landing department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: sales funnels, landing page optimization, offer creation, copywriting (direct response), launch sequences, affiliate marketing.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Chief Operations Officer — ArkaOS /org department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Sofia, Chief Operations Officer of the ArkaOS /org department (v4.
|
|
6
|
+
You are Sofia, Chief Operations Officer of the ArkaOS /org department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: organizational design, process optimization, cross-department coordination, culture & team health, scaling operations, workflow automation.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Copy & Language Director — ArkaOS /quality department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Eduardo, Copy & Language Director of the ArkaOS /quality department (v4.
|
|
6
|
+
You are Eduardo, Copy & Language Director of the ArkaOS /quality department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: spelling and grammar (EN, PT-PT, PT-BR, ES, FR), tone and voice consistency, AI pattern detection and removal, accentuation and orthography, copywriting quality, factual accuracy in text.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Chief Quality Officer — ArkaOS /quality department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Marta, Chief Quality Officer of the ArkaOS /quality department (v4.
|
|
6
|
+
You are Marta, Chief Quality Officer of the ArkaOS /quality department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: quality assurance orchestration, cross-department quality standards, text quality (spelling, grammar, tone), technical quality (code, UX, data), compliance and audit.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Chief Technology Officer — ArkaOS /dev department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Marco, Chief Technology Officer of the ArkaOS /dev department (v4.
|
|
6
|
+
You are Marco, Chief Technology Officer of the ArkaOS /dev department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: software architecture, system design, tech strategy, cloud infrastructure, ai/ml systems.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Design Ops Lead — ArkaOS /brand department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Iris, Design Ops Lead of the ArkaOS /brand department (v4.
|
|
6
|
+
You are Iris, Design Ops Lead of the ArkaOS /brand department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: design tokens (JSON + CSS variables), component libraries (shadcn/ui, Radix, Headless UI), design system governance, figma → code pipelines, accessibility compliance (WCAG 2.2 AA/AAA), cross-platform tokenisation (Style Dictionary, Tailwind).
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "E-Commerce Director — ArkaOS /ecom department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Ricardo, E-Commerce Director of the ArkaOS /ecom department (v4.
|
|
6
|
+
You are Ricardo, E-Commerce Director of the ArkaOS /ecom department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: e-commerce strategy, conversion optimization, marketplace operations, pricing strategy, fulfillment & logistics, email & retention.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Knowledge Director — ArkaOS /kb department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Clara, Knowledge Director of the ArkaOS /kb department (v4.
|
|
6
|
+
You are Clara, Knowledge Director of the ArkaOS /kb department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: knowledge management, research methodology, persona building, content curation, taxonomy & ontology, Obsidian vault management.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Leadership & People Director — ArkaOS /lead department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Rodrigo, Leadership & People Director of the ArkaOS /lead department (v4.
|
|
6
|
+
You are Rodrigo, Leadership & People Director of the ArkaOS /lead department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: team assessment & health, leadership development, hiring & onboarding, performance management, feedback & 1-on-1s, culture building.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Marketing Director — ArkaOS /mkt department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Luna, Marketing Director of the ArkaOS /mkt department (v4.
|
|
6
|
+
You are Luna, Marketing Director of the ArkaOS /mkt department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: growth strategy, video-ad teardown via dev/watch (hook, pacing and spoken-copy evidence from frames + transcript), content marketing, SEO, paid acquisition, social media.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Operations Lead — ArkaOS /ops department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Daniel, Operations Lead of the ArkaOS /ops department (v4.
|
|
6
|
+
You are Daniel, Operations Lead of the ArkaOS /ops department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: workflow automation (Zapier, Make, n8n), SOP/process visualization via dev/diagram (workflow + lifecycle diagrams for automations and runbooks), process mapping & optimization, SOP creation & management, bottleneck analysis, integration design.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Product Manager — ArkaOS /pm department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Carolina, Product Manager of the ArkaOS /pm department (v4.
|
|
6
|
+
You are Carolina, Product Manager of the ArkaOS /pm department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: continuous product discovery (daily habit), deliverable visualization via dev/diagram (workflow diagrams so stakeholders see scope before build), weekly customer interviewing, dual-track agile (discovery + delivery), product risk assessment (value/usability/feasibility/viability), framing problems for empowered teams (not features).
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "RevOps Lead — ArkaOS /saas department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Vicente, RevOps Lead of the ArkaOS /saas department (v4.
|
|
6
|
+
You are Vicente, RevOps Lead of the ArkaOS /saas department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: revenue operations (cross mkt + sales + CS), unified funnel & CRM hygiene, SLA MQL→SQL between marketing and sales, revenue metrics (LTV/CAC, NRR, payback), lead scoring & routing, commission & forecast modeling.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "SaaS Strategist — ArkaOS /saas department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Tiago, SaaS Strategist of the ArkaOS /saas department (v4.
|
|
6
|
+
You are Tiago, SaaS Strategist of the ArkaOS /saas department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: SaaS metrics & benchmarking, product-led growth, pricing strategy, customer success, micro-SaaS validation, go-to-market for SaaS.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Sales Director — ArkaOS /sales department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Miguel, Sales Director of the ArkaOS /sales department (v4.
|
|
6
|
+
You are Miguel, Sales Director of the ArkaOS /sales department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: consultative selling, pipeline management, proposal writing, negotiation, discovery calls, deal qualification.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Chief Strategist — ArkaOS /strat department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Tomas, Chief Strategist of the ArkaOS /strat department (v4.
|
|
6
|
+
You are Tomas, Chief Strategist of the ArkaOS /strat department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: competitive strategy, business-flow visualization via dev/diagram (architecture + dataflow diagrams of business models and value chains), market analysis, business model design, positioning, innovation strategy.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Technical & UX Quality Director — ArkaOS /quality department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Francisca, Technical & UX Quality Director of the ArkaOS /quality department (v4.
|
|
6
|
+
You are Francisca, Technical & UX Quality Director of the ArkaOS /quality department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: code quality (SOLID, Clean Code, DRY), test coverage and quality, UX/UI review (heuristics, accessibility), security review (OWASP), performance review (CWV, API latency), data integrity and API contracts.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Tech Lead — ArkaOS /dev department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Paulo, Tech Lead of the ArkaOS /dev department (v4.
|
|
6
|
+
You are Paulo, Tech Lead of the ArkaOS /dev department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: workflow orchestration, visual spec/plan companions via dev/diagram (typed IR -> interactive HTML the user opens before build), code quality enforcement, sprint/cycle management, technical decision-making, developer experience.
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ description: "Video Producer & Production Lead — ArkaOS /content department"
|
|
|
3
3
|
mode: subagent
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are Simão, Video Producer & Production Lead of the ArkaOS /content department (v4.
|
|
6
|
+
You are Simão, Video Producer & Production Lead of the ArkaOS /content department (v4.44.0; generated by scripts/harness_gen.py — do not edit).
|
|
7
7
|
|
|
8
8
|
Expertise: video production pipelines (script → storyboard → assets → edit → render), cut review via dev/watch (frame + transcript evidence on own renders before the Quality Gate), Hyperframes video-as-code editing (HTML/CSS/JS + GSAP → MP4), Higgsfield generation orchestration (image, video, audio, motion control, upscale, reframe), shot lists and EDLs (scene/shot/VO/on-screen-text columns), transcription-synced cuts and word-level captions.
|
|
9
9
|
|
package/harness/zed/.rules
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ArkaOS — The Operating System for AI Agent Teams
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.44.0 — 89 agents, 17 departments, 332 skills. Generated by `scripts/harness_gen.py`; do not edit.
|
|
4
4
|
|
|
5
5
|
You are operating within ArkaOS. Every request routes through the
|
|
6
6
|
appropriate department squad — never respond as a generic assistant.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, copyFileSync, statSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, copyFileSync, statSync, renameSync } from "node:fs";
|
|
2
2
|
import { join, dirname, resolve } from "node:path";
|
|
3
3
|
import { platform } from "node:os";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -31,8 +31,12 @@ export function deployProjectAgents(projectDir, sourceRoot = ARKAOS_ROOT) {
|
|
|
31
31
|
let deployed = 0;
|
|
32
32
|
try {
|
|
33
33
|
mkdirSync(agentsDest, { recursive: true });
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const sourceFiles = readdirSync(agentsSrc).filter((f) => f.endsWith(".md"));
|
|
35
|
+
retireLegacyPersonas(
|
|
36
|
+
agentsDest,
|
|
37
|
+
new Set(sourceFiles.map((f) => f.slice(0, -3))),
|
|
38
|
+
);
|
|
39
|
+
for (const file of sourceFiles) {
|
|
36
40
|
const srcFile = join(agentsSrc, file);
|
|
37
41
|
try {
|
|
38
42
|
if (!statSync(srcFile).isFile()) continue;
|
|
@@ -48,6 +52,65 @@ export function deployProjectAgents(projectDir, sourceRoot = ARKAOS_ROOT) {
|
|
|
48
52
|
return deployed;
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
// PR-B5 (N5): personas from the v1 agent payload predate the QGVerdict
|
|
56
|
+
// contract. Left in place they stay dispatchable — a Quality Gate in that
|
|
57
|
+
// project reaches `cqo` (no contract, no fence) instead of `marta-cqo`,
|
|
58
|
+
// which is exactly the dead-relay shape the campaign repaired. Retirement
|
|
59
|
+
// is a rename into .claude/agents/.arkaos-legacy/, never a delete, and
|
|
60
|
+
// only fires under a double guard: the name is on this list AND absent
|
|
61
|
+
// from the current source set (a name ArkaOS ships again is deployed,
|
|
62
|
+
// not retired). Files outside the list are untouched — they are the
|
|
63
|
+
// user's.
|
|
64
|
+
export const LEGACY_PERSONAS = new Set([
|
|
65
|
+
"analyst",
|
|
66
|
+
"content-creator",
|
|
67
|
+
"copy-director",
|
|
68
|
+
"cqo",
|
|
69
|
+
"creative-director",
|
|
70
|
+
"devops",
|
|
71
|
+
"ecommerce-manager",
|
|
72
|
+
"motion-designer",
|
|
73
|
+
"qa",
|
|
74
|
+
"security",
|
|
75
|
+
"senior-dev",
|
|
76
|
+
"strategist",
|
|
77
|
+
"tech-lead",
|
|
78
|
+
"tech-ux-director",
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
function retireLegacyPersonas(agentsDest, sourceNames) {
|
|
82
|
+
const legacyDir = join(agentsDest, ".arkaos-legacy");
|
|
83
|
+
let retired = 0;
|
|
84
|
+
let entries;
|
|
85
|
+
try {
|
|
86
|
+
entries = readdirSync(agentsDest);
|
|
87
|
+
} catch {
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
for (const file of entries) {
|
|
91
|
+
if (!file.endsWith(".md")) continue;
|
|
92
|
+
const base = file.slice(0, -3);
|
|
93
|
+
if (!LEGACY_PERSONAS.has(base) || sourceNames.has(base)) continue;
|
|
94
|
+
try {
|
|
95
|
+
mkdirSync(legacyDir, { recursive: true });
|
|
96
|
+
let dest = join(legacyDir, file);
|
|
97
|
+
for (let n = 1; existsSync(dest); n++) {
|
|
98
|
+
dest = join(legacyDir, `${base}-${n}.md`);
|
|
99
|
+
}
|
|
100
|
+
renameSync(join(agentsDest, file), dest);
|
|
101
|
+
// Never silent (QG r1 M3): these are generic names — the owner
|
|
102
|
+
// must see the move and where the file went.
|
|
103
|
+
console.log(
|
|
104
|
+
` Retired v1 persona: ${file} -> .claude/agents/.arkaos-legacy/`
|
|
105
|
+
);
|
|
106
|
+
retired++;
|
|
107
|
+
} catch {
|
|
108
|
+
// Best-effort: an unmovable persona stays in place, never deleted.
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return retired;
|
|
112
|
+
}
|
|
113
|
+
|
|
51
114
|
/**
|
|
52
115
|
* Build a complete inner hook-entry object for Claude Code's settings.json.
|
|
53
116
|
*
|
|
@@ -180,6 +243,28 @@ export default {
|
|
|
180
243
|
{ hooks: [hookEntry(hooksDir, "pre-tool-use", 10)] },
|
|
181
244
|
];
|
|
182
245
|
|
|
246
|
+
// PreToolUse (Task matcher) — dynamic agent provisioning (PR-B5,
|
|
247
|
+
// N3). config/settings-template.json declared this entry for
|
|
248
|
+
// months, but the template is not the executed path: THIS adapter
|
|
249
|
+
// writes settings.json, and it never registered the hook, so
|
|
250
|
+
// agent-provision.sh shipped in the package and was never deployed
|
|
251
|
+
// on the npm path while projects dispatched v1 personas.
|
|
252
|
+
// POSIX-only (no .ps1 port exists) and conditional on the script
|
|
253
|
+
// existing — an older package must not register a dead command
|
|
254
|
+
// (same rule as the fastpath shim above).
|
|
255
|
+
if (!IS_WINDOWS && existsSync(join(hooksDir, "agent-provision.sh"))) {
|
|
256
|
+
settings.hooks.PreToolUse.push({
|
|
257
|
+
matcher: "Task",
|
|
258
|
+
hooks: [
|
|
259
|
+
{
|
|
260
|
+
type: "command",
|
|
261
|
+
command: join(hooksDir, "agent-provision.sh"),
|
|
262
|
+
timeout: 10,
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
183
268
|
// Stop — Flow completion validator (WARN mode in v2.20.0; promotion
|
|
184
269
|
// to STRICT mode is gated on ≥ 2 weeks of clean telemetry per ADR
|
|
185
270
|
// 2026-04-17-binding-flow-enforcement).
|
package/installer/doctor.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
resolveServicesForProfile,
|
|
15
15
|
} from "./services.js";
|
|
16
16
|
import { menubarHealthy } from "./menubar.js";
|
|
17
|
+
import { LEGACY_PERSONAS } from "./adapters/claude-code.js";
|
|
17
18
|
|
|
18
19
|
const INSTALL_DIR = join(homedir(), ".arkaos");
|
|
19
20
|
|
|
@@ -36,9 +37,21 @@ export function currentInstallProfile(
|
|
|
36
37
|
|
|
37
38
|
/** Null when the check applies; otherwise the human-readable skip reason. */
|
|
38
39
|
export function checkSkipReason(check, activeProfile) {
|
|
39
|
-
if (!check.minProfile)
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
if (check.minProfile && !profileIncludes(activeProfile, check.minProfile)) {
|
|
41
|
+
return `not in ${activeProfile} profile`;
|
|
42
|
+
}
|
|
43
|
+
// PR-B5: per-check applicability — a project-scoped check run outside
|
|
44
|
+
// a project is an informational skip (same rendering as the profile
|
|
45
|
+
// gate), never a misleading fail. A predicate that throws must not
|
|
46
|
+
// hide its check, so the error path runs the check normally.
|
|
47
|
+
if (typeof check.skipIf === "function") {
|
|
48
|
+
try {
|
|
49
|
+
return check.skipIf() || null;
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
// Resolve a single command via the platform-native locator. Returns true
|
|
@@ -206,6 +219,77 @@ export function watchMediaTooling() {
|
|
|
206
219
|
return missing;
|
|
207
220
|
}
|
|
208
221
|
|
|
222
|
+
// PR-B5 (N5): a project is "repaired" when the three Quality Gate
|
|
223
|
+
// reviewers are deployed WITH the QGVerdict contract and no v1 persona
|
|
224
|
+
// remains dispatchable — at project scope OR at user scope, where the
|
|
225
|
+
// installer used to write them as arka-<name>.md (QG r1 B2: the arka-
|
|
226
|
+
// prefix defeats basename matching, so user-level detection reads the
|
|
227
|
+
// frontmatter name instead). Injectable for tests; the check uses the
|
|
228
|
+
// cwd and the real user agents dir.
|
|
229
|
+
export function qgAgentsRepaired(
|
|
230
|
+
agentsDir = join(process.cwd(), ".claude", "agents"),
|
|
231
|
+
userAgentsDir = join(homedir(), ".claude", "agents")
|
|
232
|
+
) {
|
|
233
|
+
for (const reviewer of ["marta-cqo", "eduardo-copy", "francisca-tech"]) {
|
|
234
|
+
try {
|
|
235
|
+
const text = readFileSync(join(agentsDir, `${reviewer}.md`), "utf-8");
|
|
236
|
+
if (!text.includes("QGVerdict")) return false;
|
|
237
|
+
} catch {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
for (const file of readdirSync(agentsDir)) {
|
|
243
|
+
if (!file.endsWith(".md")) continue;
|
|
244
|
+
if (LEGACY_PERSONAS.has(file.slice(0, -3))) return false;
|
|
245
|
+
}
|
|
246
|
+
} catch {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
for (const file of readdirSync(userAgentsDir)) {
|
|
251
|
+
if (!file.endsWith(".md")) continue;
|
|
252
|
+
if (isLegacyQgPersonaFile(join(userAgentsDir, file))) return false;
|
|
253
|
+
}
|
|
254
|
+
} catch {
|
|
255
|
+
// No user-level agents dir — nothing legacy can be dispatched there.
|
|
256
|
+
}
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// The v1 QG trio at user scope: dispatchability follows the frontmatter
|
|
261
|
+
// `name:`, not the filename. Detection only — retirement of user-level
|
|
262
|
+
// files belongs to the deployer that wrote them (skill-deploy.js).
|
|
263
|
+
export function isLegacyQgPersonaFile(path) {
|
|
264
|
+
try {
|
|
265
|
+
// First 500 chars only: enough for installer-written files, whose
|
|
266
|
+
// frontmatter opens the file deterministically (skill-deploy copies
|
|
267
|
+
// departments/*/agents/*.md verbatim). A hand-crafted file with the
|
|
268
|
+
// name buried deeper is out of detection scope on purpose — this
|
|
269
|
+
// check hunts the installer's own deploys, not user files.
|
|
270
|
+
const head = readFileSync(path, "utf-8").slice(0, 500);
|
|
271
|
+
const match = head.match(/^name:\s*([A-Za-z0-9-]+)\s*$/m);
|
|
272
|
+
return (
|
|
273
|
+
!!match &&
|
|
274
|
+
["cqo", "copy-director", "tech-ux-director"].includes(match[1])
|
|
275
|
+
);
|
|
276
|
+
} catch {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// PR-B5: the hook-boundary channel has captured at least one session's
|
|
282
|
+
// verdicts on this machine. Injectable for tests.
|
|
283
|
+
export function qgLedgerPopulated(
|
|
284
|
+
root = join(INSTALL_DIR, "quality-gate")
|
|
285
|
+
) {
|
|
286
|
+
try {
|
|
287
|
+
return readdirSync(root).length > 0;
|
|
288
|
+
} catch {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
209
293
|
export const checks = [
|
|
210
294
|
{
|
|
211
295
|
name: "install-dir",
|
|
@@ -412,6 +496,40 @@ export const checks = [
|
|
|
412
496
|
fix: () =>
|
|
413
497
|
"Remove the ARKAOS_ROOT export from your shell rc (~/.zshrc) — the hooks resolve the root themselves",
|
|
414
498
|
},
|
|
499
|
+
{
|
|
500
|
+
name: "qg-agents",
|
|
501
|
+
description: "Quality Gate reviewers deployed (QGVerdict contract, project + user scope)",
|
|
502
|
+
severity: "fail",
|
|
503
|
+
// PR-B5 (N5): a project whose .claude/agents/ lacks the three
|
|
504
|
+
// reviewers with the QGVerdict contract — or still carries
|
|
505
|
+
// dispatchable v1 personas — runs every Quality Gate through a
|
|
506
|
+
// contract-less agent: the dead-relay shape the campaign repaired.
|
|
507
|
+
// Project-scoped: skipped outside a project directory.
|
|
508
|
+
skipIf: () =>
|
|
509
|
+
existsSync(join(process.cwd(), ".claude", "agents"))
|
|
510
|
+
? null
|
|
511
|
+
: "no .claude/agents here — run inside a project",
|
|
512
|
+
check: () => qgAgentsRepaired(),
|
|
513
|
+
// The two arms need two different commands: init reaches only the
|
|
514
|
+
// project scope (installer/init.js -> deployProjectAgents), while
|
|
515
|
+
// the user-scope retirement runs in deploySkills, reached from
|
|
516
|
+
// install and update — a fix string naming init alone sends the
|
|
517
|
+
// user in a dead-end loop (QG r2, both reviewers independently).
|
|
518
|
+
fix: () =>
|
|
519
|
+
"Run: npx arkaos update (retires v1 QG personas from ~/.claude/agents/), then npx arkaos init in the project (deploys the QGVerdict reviewers into .claude/agents/)",
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
name: "qg-ledger",
|
|
523
|
+
description: "Quality Gate reviewer ledger has captured verdicts",
|
|
524
|
+
severity: "warn",
|
|
525
|
+
// PR-B5: an empty ledger root means the hook-boundary channel has
|
|
526
|
+
// never captured a verdict on this machine — the relay may still be
|
|
527
|
+
// dead in practice even with every contract deployed. Warn, not
|
|
528
|
+
// fail: a fresh install legitimately starts empty.
|
|
529
|
+
check: () => qgLedgerPopulated(),
|
|
530
|
+
fix: () =>
|
|
531
|
+
"Run a Quality Gate review — reviewer verdicts are hook-captured to ~/.arkaos/quality-gate/<session>/",
|
|
532
|
+
},
|
|
415
533
|
{
|
|
416
534
|
name: "profile",
|
|
417
535
|
description: "User profile exists",
|
package/installer/index.js
CHANGED
|
@@ -817,6 +817,23 @@ function installHooks(installDir) {
|
|
|
817
817
|
}
|
|
818
818
|
}
|
|
819
819
|
|
|
820
|
+
// PR-B5 (N3): agent-provision.sh is a PreToolUse(Task) gate, not a
|
|
821
|
+
// lifecycle hook, and it is POSIX-only (no .ps1 port exists, and the
|
|
822
|
+
// adapter only registers it off-Windows). It lives OUTSIDE hookNames
|
|
823
|
+
// on purpose: that list's consistency tests require a .sh/.ps1 pair
|
|
824
|
+
// for every universal hook. Before this block the script was neither
|
|
825
|
+
// copied nor registered — settings-template.json declared it, but the
|
|
826
|
+
// template is not the executed path.
|
|
827
|
+
if (hookExt === ".sh") {
|
|
828
|
+
const provisionSrc = join(srcHooksDir, "agent-provision.sh");
|
|
829
|
+
if (existsSync(provisionSrc)) {
|
|
830
|
+
const provisionDest = join(hooksDir, "agent-provision.sh");
|
|
831
|
+
writeFileSync(provisionDest, readFileSync(provisionSrc, "utf-8"));
|
|
832
|
+
try { chmodSync(provisionDest, 0o755); } catch {}
|
|
833
|
+
ok("Hook: agent-provision.sh");
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
820
837
|
if (copyHookLib(srcHooksDir, hooksDir)) {
|
|
821
838
|
ok("Hook lib: _lib/");
|
|
822
839
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
copyFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync,
|
|
3
|
-
statSync, writeFileSync,
|
|
3
|
+
renameSync, statSync, writeFileSync,
|
|
4
4
|
} from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
|
|
@@ -64,7 +64,8 @@ function deployTopLevelSkill(skillSrcDir, arkaName, skillsBase) {
|
|
|
64
64
|
/**
|
|
65
65
|
* Deploy the full skill surface: main /arka skill (+ nested reference
|
|
66
66
|
* bundle), department hubs, sub-skills, meta skills and agent personas.
|
|
67
|
-
* Copy-
|
|
67
|
+
* Copy-and-retire — never deletes anything already deployed (the v1 QG
|
|
68
|
+
* persona retirement renames into .arkaos-legacy/, it does not delete).
|
|
68
69
|
*
|
|
69
70
|
* Returns per-category counts so both callers can keep their own log
|
|
70
71
|
* style. `version`/`repoRoot` stamp the main skill's VERSION and
|
|
@@ -145,6 +146,7 @@ export function deploySkills({
|
|
|
145
146
|
// owner to a dispatchable source; hand-authored dept .md files win
|
|
146
147
|
// (already deployed above), compiled ones fill the gaps.
|
|
147
148
|
counts.agents += deployGateOwners(repoRoot, agentsBase, written);
|
|
149
|
+
retireLegacyQgPersonas(agentsBase);
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
log(counts);
|
|
@@ -205,10 +207,49 @@ function deployAgents(deptRoot, agentsBase, written = new Set()) {
|
|
|
205
207
|
return deployed;
|
|
206
208
|
}
|
|
207
209
|
|
|
210
|
+
// PR-B5 (QG r1 B2): the three v1 Quality Gate personas predate the
|
|
211
|
+
// QGVerdict contract. Deployed to ~/.claude/agents/ they keep a
|
|
212
|
+
// contract-less cqo / copy-director / tech-ux-director dispatchable at
|
|
213
|
+
// USER scope even after every project is repaired — the dead-relay
|
|
214
|
+
// shape workstream B closes. The dept loop skips them, and the targets
|
|
215
|
+
// this deployer itself wrote in earlier runs are retired — renamed
|
|
216
|
+
// into .arkaos-legacy/, never deleted (the copy-only contract holds:
|
|
217
|
+
// no delete primitive here). The real reviewers ship per project from
|
|
218
|
+
// config/claude-agents/ via deployProjectAgents.
|
|
219
|
+
const LEGACY_QG_PERSONA_FILES = [
|
|
220
|
+
"cqo.md", "copy-director.md", "tech-ux-director.md",
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
function retireLegacyQgPersonas(agentsBase) {
|
|
224
|
+
let retired = 0;
|
|
225
|
+
const legacyDir = join(agentsBase, ".arkaos-legacy");
|
|
226
|
+
for (const file of LEGACY_QG_PERSONA_FILES) {
|
|
227
|
+
const deployedName = `arka-${file}`;
|
|
228
|
+
const src = join(agentsBase, deployedName);
|
|
229
|
+
if (!existsSync(src)) continue;
|
|
230
|
+
try {
|
|
231
|
+
mkdirSync(legacyDir, { recursive: true });
|
|
232
|
+
let dest = join(legacyDir, deployedName);
|
|
233
|
+
for (let n = 1; existsSync(dest); n++) {
|
|
234
|
+
dest = join(legacyDir, `arka-${file.slice(0, -3)}-${n}.md`);
|
|
235
|
+
}
|
|
236
|
+
renameSync(src, dest);
|
|
237
|
+
// Full resolved destination: this retirement moves files in the
|
|
238
|
+
// user's HOME — the scope a reader is least able to guess.
|
|
239
|
+
console.log(` Retired v1 QG persona: ${deployedName} -> ${dest}`);
|
|
240
|
+
retired++;
|
|
241
|
+
} catch {
|
|
242
|
+
// Best-effort — an unmovable persona stays in place, never deleted.
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return retired;
|
|
246
|
+
}
|
|
247
|
+
|
|
208
248
|
function deployDeptAgents(agentsSrc, agentsBase, written) {
|
|
209
249
|
let deployed = 0;
|
|
210
250
|
for (const file of readdirSync(agentsSrc)) {
|
|
211
251
|
if (!file.endsWith(".md")) continue;
|
|
252
|
+
if (LEGACY_QG_PERSONA_FILES.includes(file)) continue;
|
|
212
253
|
const srcFile = join(agentsSrc, file);
|
|
213
254
|
try {
|
|
214
255
|
if (!statSync(srcFile).isFile()) continue;
|
package/installer/update.js
CHANGED
|
@@ -287,6 +287,18 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
287
287
|
try { chmodSync(destPath, 0o755); } catch {}
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
|
+
|
|
291
|
+
// PR-B5 (N3): the agent-provision PreToolUse(Task) gate — POSIX-only,
|
|
292
|
+
// outside hookNames on purpose (see the same block in index.js; the
|
|
293
|
+
// consistency tests require .sh/.ps1 pairs for the universal hooks).
|
|
294
|
+
if (hookExt === ".sh") {
|
|
295
|
+
const provisionSrc = join(srcHooksDir, "agent-provision.sh");
|
|
296
|
+
if (existsSync(provisionSrc)) {
|
|
297
|
+
const provisionDest = join(destHooksDir, "agent-provision.sh");
|
|
298
|
+
writeFileSync(provisionDest, readFileSync(provisionSrc, "utf-8"));
|
|
299
|
+
try { chmodSync(provisionDest, 0o755); } catch {}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
290
302
|
ok("Hook scripts updated");
|
|
291
303
|
|
|
292
304
|
// Shared hook libraries (config/hooks/_lib/ — the Python interpreter
|
package/package.json
CHANGED