arkaos 4.24.0 → 4.25.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 (35) hide show
  1. package/README.md +1 -1
  2. package/THE-ARKAOS-GUIDE.md +1 -1
  3. package/VERSION +1 -1
  4. package/arka/SKILL.md +1 -1
  5. package/bin/arka +8 -0
  6. package/config/claude-agents/shadcn-padronizer.md +3 -3
  7. package/departments/brand/agents/design-ops/shadcn-padronizer.yaml +1 -1
  8. package/departments/dev/skills/build-fix/SKILL.md +122 -0
  9. package/departments/dev/skills/react-review/SKILL.md +86 -0
  10. package/departments/ops/skills/hookify/SKILL.md +89 -0
  11. package/departments/pm/skills/epic-coordination/SKILL.md +79 -0
  12. package/harness/codex/AGENTS.md +139 -0
  13. package/harness/copilot/copilot-instructions.md +139 -0
  14. package/harness/cursor/rules/arkaos-stack-laravel.mdc +16 -0
  15. package/harness/cursor/rules/arkaos-stack-node.mdc +14 -0
  16. package/harness/cursor/rules/arkaos-stack-nuxt.mdc +15 -0
  17. package/harness/cursor/rules/arkaos-stack-php.mdc +14 -0
  18. package/harness/cursor/rules/arkaos-stack-python.mdc +14 -0
  19. package/harness/cursor/rules/arkaos-stack-react.mdc +14 -0
  20. package/harness/cursor/rules/arkaos-stack-vue.mdc +14 -0
  21. package/harness/cursor/rules/arkaos.mdc +72 -0
  22. package/harness/gemini/GEMINI.md +139 -0
  23. package/harness/opencode/AGENTS.md +139 -0
  24. package/harness/zed/.rules +139 -0
  25. package/installer/adapters/codex-cli.js +16 -27
  26. package/installer/adapters/cursor.js +22 -26
  27. package/installer/adapters/gemini-cli.js +15 -30
  28. package/installer/cli.js +1 -1
  29. package/installer/doctor.js +224 -0
  30. package/installer/harness-bundle.js +34 -0
  31. package/knowledge/agents-registry-v2.json +2 -2
  32. package/knowledge/skills-manifest.json +53 -1
  33. package/package.json +2 -1
  34. package/pyproject.toml +1 -1
  35. package/scripts/harness_gen.py +274 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_meta": {
3
3
  "generator": "scripts/marketplace_gen.py",
4
- "version": "4.24.0",
4
+ "version": "4.25.0",
5
5
  "marketplace": "arkaos"
6
6
  },
7
7
  "structural": {
@@ -420,6 +420,19 @@
420
420
  "origin": "arkaos"
421
421
  }
422
422
  },
423
+ "build-fix": {
424
+ "depts": [
425
+ "dev"
426
+ ],
427
+ "curated": false,
428
+ "plugins": [
429
+ "arkaos-dev@arkaos"
430
+ ],
431
+ "collision": false,
432
+ "provenance": {
433
+ "origin": "arkaos"
434
+ }
435
+ },
423
436
  "business-model": {
424
437
  "depts": [
425
438
  "community"
@@ -1095,6 +1108,19 @@
1095
1108
  "origin": "arkaos"
1096
1109
  }
1097
1110
  },
1111
+ "epic-coordination": {
1112
+ "depts": [
1113
+ "pm"
1114
+ ],
1115
+ "curated": false,
1116
+ "plugins": [
1117
+ "arkaos-pm@arkaos"
1118
+ ],
1119
+ "collision": false,
1120
+ "provenance": {
1121
+ "origin": "arkaos"
1122
+ }
1123
+ },
1098
1124
  "estimate-forecast": {
1099
1125
  "depts": [
1100
1126
  "pm"
@@ -1386,6 +1412,19 @@
1386
1412
  "origin": "arkaos"
1387
1413
  }
1388
1414
  },
1415
+ "hookify": {
1416
+ "depts": [
1417
+ "ops"
1418
+ ],
1419
+ "curated": false,
1420
+ "plugins": [
1421
+ "arkaos-ops@arkaos"
1422
+ ],
1423
+ "collision": false,
1424
+ "provenance": {
1425
+ "origin": "arkaos"
1426
+ }
1427
+ },
1389
1428
  "identity-system": {
1390
1429
  "depts": [
1391
1430
  "brand"
@@ -2390,6 +2429,19 @@
2390
2429
  "origin": "arkaos"
2391
2430
  }
2392
2431
  },
2432
+ "react-review": {
2433
+ "depts": [
2434
+ "dev"
2435
+ ],
2436
+ "curated": false,
2437
+ "plugins": [
2438
+ "arkaos-dev@arkaos"
2439
+ ],
2440
+ "collision": false,
2441
+ "provenance": {
2442
+ "origin": "arkaos"
2443
+ }
2444
+ },
2393
2445
  "red-team": {
2394
2446
  "depts": [
2395
2447
  "dev"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "4.24.0",
3
+ "version": "4.25.0",
4
4
  "description": "The Operating System for AI Agent Teams",
5
5
  "type": "module",
6
6
  "bin": {
@@ -43,6 +43,7 @@
43
43
  "installer/",
44
44
  "core/",
45
45
  "departments/",
46
+ "harness/",
46
47
  "mcps/",
47
48
  "scripts/",
48
49
  "config/",
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "arkaos-core"
3
- version = "4.24.0"
3
+ version = "4.25.0"
4
4
  description = "Core engine for ArkaOS — The Operating System for AI Agent Teams"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -0,0 +1,274 @@
1
+ """Generate harness/ — multi-runtime instruction bundles from one source.
2
+
3
+ Docs-as-code (marketplace_gen / guide_gen precedent): the ArkaOS
4
+ contract — identity, department routing, agent index, evidence
5
+ expectations, stack conventions — is COMPILED from the generated
6
+ registries and emitted once per supported harness, in that harness's
7
+ native instruction format. Nothing here is hand-typed per target;
8
+ adding a harness is one small emitter, not a maintained directory.
9
+
10
+ Targets (v1): codex (AGENTS.md), opencode (AGENTS.md), gemini
11
+ (GEMINI.md), zed (.rules), copilot (copilot-instructions.md), cursor
12
+ (rules/*.mdc with path-scoped stack rules).
13
+
14
+ Honesty note baked into every bundle: these are instruction-level
15
+ exports — the full ArkaOS engine (Synapse, hooks, Quality Gate
16
+ enforcement) runs on runtimes with an adapter; instructions carry the
17
+ contract, not the cognition.
18
+
19
+ Sources (all generated + drift-locked elsewhere):
20
+ - ``knowledge/agents-registry-v2.json`` — agents (name/role/dept/tier)
21
+ - ``knowledge/commands-registry.json`` — per-department command counts
22
+ - ``config/standards/stack-rules/*.md`` — path-scoped stack conventions
23
+ - ``VERSION`` + ``scripts/tools/docs_stats.py`` counters
24
+
25
+ Run: ``~/.arkaos/bin/arka-py scripts/harness_gen.py``
26
+
27
+ ``tests/python/test_harness_gen.py`` drift-gates the committed tree
28
+ byte for byte and enforces the size budget — an instruction file that
29
+ blows the target's context is the documented anti-pattern.
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import json
35
+ import sys
36
+ from pathlib import Path
37
+
38
+ sys.path.insert(0, str(Path(__file__).resolve().parent / "tools"))
39
+
40
+ from docs_stats import (
41
+ count_agents,
42
+ count_departments,
43
+ count_skills,
44
+ read_version,
45
+ repo_root,
46
+ )
47
+
48
+ ROOT = repo_root()
49
+ HARNESS_DIR = ROOT / "harness"
50
+ STACK_RULES_DIR = ROOT / "config" / "standards" / "stack-rules"
51
+
52
+ # Department prefix -> lead agent name. Leads are tier-1 agents; where a
53
+ # department has several squad leads the ORCHESTRATING lead is listed
54
+ # (same mapping the routing table in arka/SKILL.md uses).
55
+ DEPT_LEADS = {
56
+ "dev": "Paulo", "mkt": "Luna", "brand": "Valentina", "fin": "Helena",
57
+ "strat": "Tomas", "ecom": "Ricardo", "kb": "Clara", "ops": "Daniel",
58
+ "pm": "Carolina", "saas": "Tiago", "landing": "Ines",
59
+ "content": "Rafael", "community": "Beatriz", "sales": "Miguel",
60
+ "lead": "Rodrigo", "org": "Sofia",
61
+ }
62
+
63
+ # Registry department slug -> routing prefix (registry stores directory
64
+ # names; the user-facing prefixes differ for four departments).
65
+ DIR_TO_PREFIX = {
66
+ "marketing": "mkt", "strategy": "strat", "finance": "fin",
67
+ "leadership": "lead",
68
+ }
69
+
70
+ # Size budget per emitted main file. Instruction files that outgrow the
71
+ # target's context stop being read — the budget is the feature.
72
+ MAIN_FILE_BUDGET_BYTES = 16_000
73
+
74
+
75
+ def _load_agents() -> list[dict]:
76
+ data = json.loads(
77
+ (ROOT / "knowledge" / "agents-registry-v2.json").read_text())
78
+ return data["agents"]
79
+
80
+
81
+ def _load_command_counts() -> dict[str, int]:
82
+ data = json.loads(
83
+ (ROOT / "knowledge" / "commands-registry.json").read_text())
84
+ return data["_meta"]["departments"]
85
+
86
+
87
+ def _split_frontmatter(text: str) -> tuple[list[str], str]:
88
+ """Return (paths globs, body) from a stack-rules file."""
89
+ if not text.startswith("---"):
90
+ return [], text
91
+ _, fm, body = text.split("---", 2)
92
+ globs = [
93
+ line.strip().lstrip("- ").strip('"')
94
+ for line in fm.strip().splitlines()
95
+ if line.strip().startswith("- ")
96
+ ]
97
+ return globs, body.strip()
98
+
99
+
100
+ def _stack_rules() -> list[tuple[str, list[str], str]]:
101
+ rules = []
102
+ for path in sorted(STACK_RULES_DIR.glob("*.md")):
103
+ globs, body = _split_frontmatter(path.read_text())
104
+ rules.append((path.stem, globs, body))
105
+ return rules
106
+
107
+
108
+ def _department_table(counts: dict[str, int]) -> str:
109
+ # commands-registry keys one department by directory name where the
110
+ # prefix differs ("leadership" for /lead).
111
+ prefix_to_registry = {"lead": "leadership"}
112
+ rows = ["| Prefix | Lead | Commands |", "|---|---|---|"]
113
+ for prefix, lead in DEPT_LEADS.items():
114
+ key = prefix_to_registry.get(prefix, prefix)
115
+ rows.append(f"| `/{prefix}` | {lead} | {counts.get(key, 0)} |")
116
+ return "\n".join(rows)
117
+
118
+
119
+ def _agent_index(agents: list[dict]) -> str:
120
+ by_dept: dict[str, list[dict]] = {}
121
+ for agent in agents:
122
+ prefix = DIR_TO_PREFIX.get(agent["department"], agent["department"])
123
+ by_dept.setdefault(prefix, []).append(agent)
124
+ lines = []
125
+ for prefix in sorted(by_dept):
126
+ members = sorted(
127
+ by_dept[prefix], key=lambda a: (a["tier"], a["name"]))
128
+ listing = " · ".join(
129
+ f"{a['name']} ({a['role']})" for a in members)
130
+ lines.append(f"- **{prefix}**: {listing}")
131
+ return "\n".join(lines)
132
+
133
+
134
+ def _stack_section(rules: list[tuple[str, list[str], str]]) -> str:
135
+ # Rule bodies carry their own "## <Stack> Conventions" title; demote
136
+ # one level so they nest correctly under "## Stack conventions".
137
+ parts = []
138
+ for _stack, _globs, body in rules:
139
+ demoted = "\n".join(
140
+ f"#{line}" if line.startswith("## ") else line
141
+ for line in body.splitlines()
142
+ )
143
+ parts.append(demoted)
144
+ return "\n\n".join(parts)
145
+
146
+
147
+ def _contract_body() -> str:
148
+ version = read_version(ROOT)
149
+ departments = count_departments(ROOT)
150
+ agents_total = count_agents(ROOT)["files"]
151
+ skills = count_skills(ROOT)["core"]
152
+ counts = _load_command_counts()
153
+ agents = _load_agents()
154
+ return f"""# ArkaOS — The Operating System for AI Agent Teams
155
+
156
+ > v{version} — {agents_total} agents, {departments} departments, \
157
+ {skills} skills. Generated by `scripts/harness_gen.py`; do not edit.
158
+
159
+ You are operating within ArkaOS. Every request routes through the
160
+ appropriate department squad — never respond as a generic assistant.
161
+
162
+ ## How to work
163
+
164
+ 1. **Route** every request to a department (table below) and say so:
165
+ `[arka:routing] <dept> -> <lead>`.
166
+ 2. **Plan before code.** State the plan and wait for explicit approval
167
+ on non-trivial work.
168
+ 3. **Evidence over narration.** Run the real tests and report the real
169
+ exit code; a claim about code that was never executed is not a
170
+ result.
171
+ 4. **Quality Gate.** Before delivering, review the work as a critical
172
+ second reader (copy AND technical) and say honestly what is
173
+ unfinished. Nothing ships with known defects undisclosed.
174
+
175
+ ## Departments
176
+
177
+ {_department_table(counts)}
178
+
179
+ ## Agents
180
+
181
+ Adopt the matching persona when executing department work:
182
+
183
+ {_agent_index(agents)}
184
+
185
+ ## Stack conventions
186
+
187
+ Apply the section matching the files you touch.
188
+
189
+ {_stack_section(_stack_rules())}
190
+
191
+ ## Scope of this file
192
+
193
+ Instruction-level export for this runtime. The full ArkaOS engine —
194
+ context injection, hooks, enforced quality gates, knowledge base — runs
195
+ on runtimes with a native adapter (`npx arkaos install`). This file
196
+ carries the contract so the team behaves like ArkaOS anywhere.
197
+ """
198
+
199
+
200
+ def _cursor_files() -> dict[str, str]:
201
+ """Cursor gets native path-scoped rules instead of one flat file."""
202
+ version = read_version(ROOT)
203
+ files: dict[str, str] = {}
204
+ body = _contract_body()
205
+ # Strip the stack section from the always-on rule — stacks ship as
206
+ # individually scoped .mdc files below, Cursor's native strength.
207
+ main = body.split("## Stack conventions")[0].rstrip()
208
+ main += (
209
+ "\n\n## Stack conventions\n\nPath-scoped rules in this directory "
210
+ "(`arkaos-stack-*.mdc`) apply automatically to matching files.\n"
211
+ )
212
+ files["rules/arkaos.mdc"] = (
213
+ f"---\ndescription: ArkaOS v{version} agent-team contract\n"
214
+ f"alwaysApply: true\n---\n\n{main}\n"
215
+ )
216
+ for stack, globs, rule_body in _stack_rules():
217
+ globs_line = ", ".join(globs)
218
+ files[f"rules/arkaos-stack-{stack}.mdc"] = (
219
+ f"---\ndescription: ArkaOS {stack} stack conventions\n"
220
+ f"globs: {globs_line}\nalwaysApply: false\n---\n\n"
221
+ f"{rule_body}\n"
222
+ )
223
+ return files
224
+
225
+
226
+ def generate() -> dict[str, str]:
227
+ """Return {relative path under harness/: content}."""
228
+ body = _contract_body()
229
+ files: dict[str, str] = {
230
+ "codex/AGENTS.md": body,
231
+ "opencode/AGENTS.md": body,
232
+ "gemini/GEMINI.md": body,
233
+ "zed/.rules": body,
234
+ "copilot/copilot-instructions.md": body,
235
+ }
236
+ for rel, content in _cursor_files().items():
237
+ files[f"cursor/{rel}"] = content
238
+ return files
239
+
240
+
241
+ def check_budget(files: dict[str, str]) -> list[str]:
242
+ over = []
243
+ for rel, content in files.items():
244
+ size = len(content.encode("utf-8"))
245
+ if size > MAIN_FILE_BUDGET_BYTES:
246
+ over.append(f"{rel}: {size} bytes > {MAIN_FILE_BUDGET_BYTES}")
247
+ return over
248
+
249
+
250
+ def main() -> int:
251
+ files = generate()
252
+ over = check_budget(files)
253
+ if over:
254
+ print("BUDGET EXCEEDED:\n " + "\n ".join(over))
255
+ return 1
256
+ if HARNESS_DIR.exists():
257
+ for stale in HARNESS_DIR.rglob("*"):
258
+ if stale.is_file():
259
+ rel = str(stale.relative_to(HARNESS_DIR))
260
+ if rel not in files:
261
+ stale.unlink()
262
+ for rel, content in files.items():
263
+ target = HARNESS_DIR / rel
264
+ target.parent.mkdir(parents=True, exist_ok=True)
265
+ target.write_text(content)
266
+ total = sum(len(c.encode()) for c in files.values())
267
+ print(
268
+ f"harness generated: {len(files)} files, 6 targets, "
269
+ f"{total} bytes total")
270
+ return 0
271
+
272
+
273
+ if __name__ == "__main__":
274
+ raise SystemExit(main())