arkaos 4.11.0 → 4.12.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 (71) hide show
  1. package/README.md +1 -1
  2. package/VERSION +1 -1
  3. package/arka/SKILL.md +10 -1
  4. package/arka/skills/flow/SKILL.md +23 -1
  5. package/arka/skills/recipes/SKILL.md +69 -0
  6. package/arka/skills/refine/SKILL.md +81 -0
  7. package/config/constitution.yaml +8 -0
  8. package/config/mcp-policy.yaml +8 -0
  9. package/config/output-styles/arkaos.md +52 -0
  10. package/core/evals/__init__.py +4 -0
  11. package/core/evals/__pycache__/__init__.cpython-313.pyc +0 -0
  12. package/core/evals/__pycache__/record_cli.cpython-313.pyc +0 -0
  13. package/core/evals/__pycache__/verdict_labels.cpython-313.pyc +0 -0
  14. package/core/evals/record_cli.py +41 -8
  15. package/core/evals/verdict_labels.py +53 -13
  16. package/core/forge/__pycache__/complexity.cpython-313.pyc +0 -0
  17. package/core/forge/complexity.py +9 -0
  18. package/core/governance/__pycache__/evidence_checks.cpython-313.pyc +0 -0
  19. package/core/governance/__pycache__/judge.cpython-313.pyc +0 -0
  20. package/core/governance/__pycache__/phantom_action_check.cpython-313.pyc +0 -0
  21. package/core/governance/__pycache__/phantom_action_check.cpython-314.pyc +0 -0
  22. package/core/governance/evidence_checks.py +60 -4
  23. package/core/governance/judge.py +95 -0
  24. package/core/governance/phantom_action_check.py +41 -0
  25. package/core/hooks/__pycache__/post_tool_use.cpython-313.pyc +0 -0
  26. package/core/hooks/__pycache__/stop.cpython-313.pyc +0 -0
  27. package/core/hooks/__pycache__/stop.cpython-314.pyc +0 -0
  28. package/core/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  29. package/core/hooks/post_tool_use.py +13 -0
  30. package/core/hooks/stop.py +23 -0
  31. package/core/hooks/user_prompt_submit.py +69 -0
  32. package/core/knowledge/__pycache__/recipes.cpython-313.pyc +0 -0
  33. package/core/knowledge/__pycache__/recipes_cli.cpython-313.pyc +0 -0
  34. package/core/knowledge/recipes.py +237 -0
  35. package/core/knowledge/recipes_cli.py +99 -0
  36. package/core/shared/__pycache__/safe_session_id.cpython-313.pyc +0 -0
  37. package/core/shared/__pycache__/safe_session_id.cpython-314.pyc +0 -0
  38. package/core/shared/safe_session_id.py +11 -3
  39. package/core/synapse/__pycache__/engine.cpython-313.pyc +0 -0
  40. package/core/synapse/__pycache__/engine.cpython-314.pyc +0 -0
  41. package/core/synapse/__pycache__/pattern_library_layer.cpython-313.pyc +0 -0
  42. package/core/synapse/__pycache__/recipe_layer.cpython-313.pyc +0 -0
  43. package/core/synapse/engine.py +6 -0
  44. package/core/synapse/pattern_library_layer.py +10 -2
  45. package/core/synapse/recipe_layer.py +114 -0
  46. package/core/sync/__pycache__/mcp_optimizer.cpython-313.pyc +0 -0
  47. package/core/sync/__pycache__/mcp_syncer.cpython-313.pyc +0 -0
  48. package/core/sync/__pycache__/settings_syncer.cpython-313.pyc +0 -0
  49. package/core/sync/mcp_optimizer.py +4 -1
  50. package/core/sync/mcp_syncer.py +50 -6
  51. package/core/sync/settings_syncer.py +9 -2
  52. package/core/workflow/__pycache__/flow_enforcer.cpython-313.pyc +0 -0
  53. package/core/workflow/__pycache__/flow_enforcer.cpython-314.pyc +0 -0
  54. package/core/workflow/__pycache__/plan_approval.cpython-313.pyc +0 -0
  55. package/core/workflow/__pycache__/plan_approval.cpython-314.pyc +0 -0
  56. package/core/workflow/flow_enforcer.py +63 -0
  57. package/core/workflow/plan_approval.py +185 -0
  58. package/departments/dev/SKILL.md +10 -0
  59. package/departments/dev/skills/onboard/SKILL.md +6 -2
  60. package/departments/dev/skills/refactor-plan/SKILL.md +7 -0
  61. package/departments/dev/skills/scaffold/SKILL.md +6 -0
  62. package/departments/quality/SKILL.md +16 -0
  63. package/installer/doctor.js +7 -0
  64. package/installer/index.js +20 -0
  65. package/installer/output-style.js +92 -0
  66. package/installer/update.js +19 -0
  67. package/installer/worktree-baseref.js +8 -2
  68. package/knowledge/commands-keywords.json +4 -0
  69. package/knowledge/commands-registry.json +41 -3
  70. package/package.json +1 -1
  71. package/pyproject.toml +1 -1
@@ -0,0 +1,185 @@
1
+ """Per-session plan-approval state machine (Interaction Reform PR3).
2
+
3
+ The flow contract says Gate 2 "waits for EXPLICIT user approval", but
4
+ nothing executable ever verified it — the enforcer only checked marker
5
+ PRESENCE, so a bare ``[arka:routing]`` unlocked writes. This module
6
+ tracks the missing signal:
7
+
8
+ none → presented → approved
9
+
10
+ - **presented** — the Stop hook observed the turn ending at Gate 2
11
+ (plan shown, no Gate 3 yet).
12
+ - **approved** — the UserPromptSubmit hook classified the NEXT user
13
+ message as an approval, or PostToolUse saw a successful
14
+ ``ExitPlanMode`` (the native plan-mode approve button IS approval).
15
+
16
+ A new ``presented`` invalidates an older ``approved`` (plan B after an
17
+ approved plan A requires fresh approval): approval is only live when
18
+ ``approved_ts >= presented_ts``.
19
+
20
+ Same persistence contract as ``flow_authorization``: CWE-22-safe state
21
+ files under ``arkaos_temp_dir`` (override ``ARKA_PLAN_APPROVAL_DIR``),
22
+ 12h TTL, never raises — hooks must not break a turn. In PR3 the
23
+ enforcer only WARNS on missing approval (telemetry to measure false
24
+ positives across the install base); hard deny is PR4, gated on that
25
+ telemetry.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import json
31
+ import os
32
+ import re
33
+ import time
34
+ from dataclasses import asdict, dataclass
35
+ from pathlib import Path
36
+
37
+ from core.shared.safe_session_id import safe_session_id
38
+ from core.shared.temp_paths import arkaos_temp_dir
39
+
40
+ DEFAULT_TTL_SECONDS = 12 * 60 * 60
41
+
42
+ _APPROVE_RE = re.compile(
43
+ r"\b(aprovo|aprovado|avan[çc]a(?:m|mos)?|segue em frente|for[çc]a"
44
+ r"|manda|bora|go ahead|approved?|proceed|ship it|lgtm)\b",
45
+ re.IGNORECASE,
46
+ )
47
+ _REJECT_RE = re.compile(
48
+ r"\b(n[ãa]o|para|espera|aguarda|cancela?|stop|reject|hold)\b",
49
+ re.IGNORECASE,
50
+ )
51
+ _SHORT_YES_RE = re.compile(r"\b(sim|ok|okay|yes|yep|sure|dale)\b", re.IGNORECASE)
52
+
53
+
54
+ def _state_dir() -> Path | None:
55
+ """Resolve the state dir, creating it. None when the mkdir fails.
56
+
57
+ The module's never-raises contract must hold in its OWN internals:
58
+ a read-only override dir or a full disk returns None (callers treat
59
+ it as "no state") instead of propagating an OSError into a hook
60
+ (QG 2026-07-09, PR4 prerequisite #3).
61
+ """
62
+ override = os.environ.get("ARKA_PLAN_APPROVAL_DIR", "").strip()
63
+ try:
64
+ if override:
65
+ path = Path(override)
66
+ path.mkdir(parents=True, exist_ok=True)
67
+ return path
68
+ return arkaos_temp_dir("arkaos-plan-approval")
69
+ except OSError:
70
+ return None
71
+
72
+
73
+ def _state_file(session_id: str) -> Path | None:
74
+ safe = safe_session_id(session_id)
75
+ if safe is None:
76
+ return None
77
+ state_dir = _state_dir()
78
+ if state_dir is None:
79
+ return None
80
+ return state_dir / f"{safe}.json"
81
+
82
+
83
+ @dataclass
84
+ class ApprovalState:
85
+ state: str = "none" # none | presented | approved
86
+ presented_ts: float = 0.0
87
+ approved_ts: float = 0.0
88
+ source: str = "" # text | exit-plan-mode
89
+ excerpt: str = ""
90
+
91
+
92
+ def _read(session_id: str) -> ApprovalState:
93
+ path = _state_file(session_id)
94
+ if path is None or not path.exists():
95
+ return ApprovalState()
96
+ try:
97
+ data = json.loads(path.read_text(encoding="utf-8"))
98
+ return ApprovalState(**{
99
+ k: data.get(k, getattr(ApprovalState(), k))
100
+ for k in ApprovalState().__dict__
101
+ })
102
+ except Exception: # noqa: BLE001 — corrupt state resets, never raises
103
+ return ApprovalState()
104
+
105
+
106
+ def _write(session_id: str, state: ApprovalState) -> None:
107
+ path = _state_file(session_id)
108
+ if path is None:
109
+ return
110
+ try:
111
+ path.write_text(
112
+ json.dumps(asdict(state)) + "\n", encoding="utf-8"
113
+ )
114
+ except OSError:
115
+ return
116
+
117
+
118
+ def mark_presented(session_id: str) -> None:
119
+ """The turn ended at Gate 2: a plan is on the table."""
120
+ state = _read(session_id)
121
+ state.state = "presented"
122
+ state.presented_ts = time.time()
123
+ _write(session_id, state)
124
+
125
+
126
+ def mark_approved(
127
+ session_id: str, source: str = "text", excerpt: str = ""
128
+ ) -> None:
129
+ state = _read(session_id)
130
+ state.state = "approved"
131
+ state.approved_ts = time.time()
132
+ state.source = source
133
+ state.excerpt = excerpt[:120]
134
+ _write(session_id, state)
135
+
136
+
137
+ def mark_rejected(session_id: str) -> None:
138
+ _write(session_id, ApprovalState())
139
+
140
+
141
+ def get_state(session_id: str) -> ApprovalState:
142
+ return _read(session_id)
143
+
144
+
145
+ def is_presented(session_id: str) -> bool:
146
+ state = _read(session_id)
147
+ return (
148
+ state.state in ("presented", "approved")
149
+ and time.time() - state.presented_ts < DEFAULT_TTL_SECONDS
150
+ )
151
+
152
+
153
+ def is_approved(session_id: str) -> bool:
154
+ """Approval is live only when it POSTdates the latest presented plan."""
155
+ state = _read(session_id)
156
+ if state.state != "approved" or not state.approved_ts:
157
+ return False
158
+ if state.approved_ts + 0.001 < state.presented_ts:
159
+ return False
160
+ return time.time() - state.approved_ts < DEFAULT_TTL_SECONDS
161
+
162
+
163
+ def classify_reply(text: str, has_creation_verb: bool = False) -> str:
164
+ """Classify a user message that follows a presented plan.
165
+
166
+ Returns "approve" | "reject" | "other". A short bare "sim/ok/yes"
167
+ counts as approval ONLY when unambiguous: <= 5 tokens, no creation
168
+ verb (a new instruction, not consent), and no question mark.
169
+ """
170
+ stripped = (text or "").strip()
171
+ if not stripped:
172
+ return "other"
173
+ if _REJECT_RE.search(stripped):
174
+ return "reject"
175
+ if _APPROVE_RE.search(stripped) and not has_creation_verb:
176
+ return "approve"
177
+ tokens = stripped.split()
178
+ if (
179
+ len(tokens) <= 5
180
+ and _SHORT_YES_RE.search(stripped)
181
+ and not has_creation_verb
182
+ and "?" not in stripped
183
+ ):
184
+ return "approve"
185
+ return "other"
@@ -70,6 +70,16 @@ Phase 7: QUALITY GATE → Marta + Eduardo (copy) + Francisca (tech) → APPROVED
70
70
  Phase 8: DOCUMENTATION → ADR + docs to Obsidian
71
71
  ```
72
72
 
73
+ ## Codebase grounding (codebase-memory MCP)
74
+
75
+ When the `codebase-memory` MCP is active in the project, consult it
76
+ BEFORE touching complex code — in Phase 1 RESEARCH and in every
77
+ Diagnose step: `get_architecture` for the structural map,
78
+ `search_graph`/`get_code_snippet` to locate the real implementations,
79
+ `trace_path` for impact analysis before a refactor. The graph is a
80
+ PRIOR, not ground truth: verify with Read before editing. When the MCP
81
+ is absent the phases run as before (Grep/Read exploration).
82
+
73
83
  ## Focused Workflow (4 Phases)
74
84
 
75
85
  For `/dev debug`, `/dev refactor`, `/dev db`, `/dev performance`, `/dev pipeline`: Diagnose → Implement with tests → Rita validates → Quality Gate (Marta).
@@ -44,8 +44,12 @@ The onboard flow is a 12-step pipeline, split across two reference files:
44
44
  8. Generate `PROJECT.md` in project root
45
45
  9. Register in `$ARKA_OS/projects/<name>/`
46
46
  10. Apply MCP profile — generate `.mcp.json` + `.claude/settings.local.json`
47
- 11. Create Obsidian docsHome, Architecture, Projects MOC, Ecosystem MOC
48
- 12. Report summary + next steps
47
+ 11. Index the codebase graph when the `codebase-memory-mcp` binary
48
+ exists, run `codebase-memory-mcp cli index_repository
49
+ '{"repo_path": "<abs project path>"}'` so the consistency layer is
50
+ warm from day one; skip silently when the binary is absent
51
+ 12. Create Obsidian docs — Home, Architecture, Projects MOC, Ecosystem MOC
52
+ 13. Report — summary + next steps (mention the graph index status)
49
53
 
50
54
  The `ecosystem` subcommands (list/create/add) and error handling also live in mcp-config.md.
51
55
 
@@ -26,6 +26,13 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
26
26
 
27
27
  Plan a refactoring: identify code smells, select refactoring patterns, ensure test safety net.
28
28
 
29
+ When the `codebase-memory` MCP is active, ground the plan in the real
30
+ structure BEFORE proposing moves: `get_architecture` for the module
31
+ map, `trace_path` for every call-site the refactor touches (impact
32
+ analysis), `search_graph` to find duplicated implementations worth
33
+ consolidating. The graph is a prior — verify with Read before planning
34
+ an edit.
35
+
29
36
  ## Output
30
37
 
31
38
  Refactoring plan with patterns, risk assessment, and test verification steps
@@ -109,6 +109,12 @@ Profile mapping:
109
109
 
110
110
  This generates `.mcp.json` and `.claude/settings.local.json`.
111
111
 
112
+ After the profile is applied, warm the consistency layer: when the
113
+ `codebase-memory-mcp` binary exists, run
114
+ `codebase-memory-mcp cli index_repository '{"repo_path": "<abs path>"}'`
115
+ so the graph is available from the first feature. Skip silently when
116
+ the binary is absent (the sync defers the MCP entry until installed).
117
+
112
118
  ### Step 6: Generate PROJECT.md
113
119
 
114
120
  Create `PROJECT.md` in the project root with:
@@ -23,6 +23,13 @@ override it with narrative.
23
23
  Any Department Workflow:
24
24
  ...
25
25
  Phase N-1: QUALITY GATE
26
+ 0. Output-judge (constitution gate-judges, MEDIUM/HIGH work only):
27
+ one judge dispatched via the Agent tool with
28
+ JUDGE_VERDICT_JSON_SCHEMA (core.governance.judge), frontier
29
+ model, over deliverable + diff + evidence report. REVISE loops
30
+ the work back before the personas run (max 2); PASS findings
31
+ become reviewer input. Record it:
32
+ arka-py -m core.evals.record_cli --kind judge
26
33
  1. Run the evidence engine over the project/diff:
27
34
  ~/.arkaos/bin/arka-py -m core.governance.evidence_checks <project_dir> \
28
35
  [--changed-files f1,f2] [--test-command '...'] --json
@@ -46,6 +53,15 @@ Any Department Workflow:
46
53
  (~/.arkaos/telemetry/qg-verdicts.jsonl). Applies to EVERY review,
47
54
  not only eval runs; --eval-task-id only when the review judged a
48
55
  config/evals task.
56
+ 7. Recipe promotion (Interaction Reform PR7, APPROVED reusable
57
+ features only): when the deliverable is a feature worth reusing
58
+ across projects (auth flow, payment integration, a standard UI
59
+ pattern…), PROPOSE to the operator "promote this to a recipe?".
60
+ On confirmation, capture it —
61
+ `arka-py -m core.knowledge.recipes_cli capture --spec <spec.json>`
62
+ (spec = {recipe, narrative, files}). Capture is fail-closed:
63
+ every field and file is sanitized first, refused without a
64
+ redaction config. Never silent — always operator-confirmed.
49
65
  Phase N: DELIVERY
50
66
  → Only reaches user after APPROVED from all three
51
67
  ```
@@ -208,6 +208,13 @@ const checks = [
208
208
  check: () => graphifyDoctor().installed,
209
209
  fix: () => graphifyDoctor().hint || "Run: uv tool install graphifyy (or pipx install graphifyy)",
210
210
  },
211
+ {
212
+ name: "codebase-memory",
213
+ description: "codebase-memory-mcp binary present (default consistency layer for code stacks)",
214
+ severity: "warn",
215
+ check: () => commandExists("codebase-memory-mcp"),
216
+ fix: () => "Install codebase-memory-mcp (see mcps/registry.json entry for the one-liner), then /arka update to activate per project",
217
+ },
211
218
  {
212
219
  name: "magic-api-key",
213
220
  description: "Magic API key configured (frontend UI/UX — Magic MCP)",
@@ -372,6 +372,26 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
372
372
  console.log(` Warning: could not seed worktree.baseRef (${err.message})`);
373
373
  }
374
374
 
375
+ // Interaction Reform PR1 — install the ArkaOS output style and seed
376
+ // it as the Claude Code default. File copy is unconditional (making
377
+ // the style available is not a preference); the settings seed is
378
+ // if-absent only — an explicit operator choice is never overridden.
379
+ try {
380
+ const { installOutputStyles, seedOutputStyleDefault } = await import("./output-style.js");
381
+ const styleResult = installOutputStyles({
382
+ sourceDir: join(ARKAOS_ROOT, "config", "output-styles"),
383
+ });
384
+ if (styleResult.copied > 0) {
385
+ console.log(` ${styleResult.copied} output style(s) installed (~/.claude/output-styles/).`);
386
+ }
387
+ const seedResult = seedOutputStyleDefault({ runtime });
388
+ if (!seedResult.skipped && seedResult.action === "created") {
389
+ console.log(` outputStyle default set to "${seedResult.value}".`);
390
+ }
391
+ } catch (err) {
392
+ console.log(` Warning: could not install output style (${err.message})`);
393
+ }
394
+
375
395
  // PR43 v2.62.0 — auto-install default Claude Code plugins. Only runs
376
396
  // when runtime is Claude Code AND the `claude` CLI is available.
377
397
  // Idempotent: skips plugins already in installed_plugins.json.
@@ -0,0 +1,92 @@
1
+ // ArkaOS output style install + default seed (Interaction Reform PR1).
2
+ //
3
+ // The ArkaOS output style used to exist only as a hand-placed file in
4
+ // ~/.claude/output-styles/ — orphaned from the installer, so fresh
5
+ // installs never got the branded personality and /config showed the
6
+ // generic default. This module makes the repo the source of truth:
7
+ //
8
+ // 1. Copies config/output-styles/*.md → ~/.claude/output-styles/
9
+ // (always — the file being available is not a preference).
10
+ // 2. Seeds `"outputStyle": "ArkaOS"` in ~/.claude/settings.json
11
+ // ONLY when the key is absent. An operator who explicitly chose
12
+ // another style (including "default") is never overridden — the
13
+ // same seed-if-absent contract as worktree-baseref.js and
14
+ // config-seed.js.
15
+ //
16
+ // Never raises — failures are non-fatal install warnings.
17
+
18
+ import {
19
+ copyFileSync,
20
+ existsSync,
21
+ mkdirSync,
22
+ readdirSync,
23
+ readFileSync,
24
+ renameSync,
25
+ writeFileSync,
26
+ } from "node:fs";
27
+ import { homedir } from "node:os";
28
+ import { join } from "node:path";
29
+
30
+
31
+ export const DEFAULT_OUTPUT_STYLE = "ArkaOS";
32
+
33
+
34
+ export function installOutputStyles({
35
+ sourceDir,
36
+ home = homedir(),
37
+ } = {}) {
38
+ if (!sourceDir || !existsSync(sourceDir)) {
39
+ return { skipped: "source-not-found", copied: 0 };
40
+ }
41
+ try {
42
+ const destDir = join(home, ".claude", "output-styles");
43
+ mkdirSync(destDir, { recursive: true });
44
+ let copied = 0;
45
+ for (const name of readdirSync(sourceDir)) {
46
+ if (!name.endsWith(".md")) continue;
47
+ copyFileSync(join(sourceDir, name), join(destDir, name));
48
+ copied += 1;
49
+ }
50
+ return { skipped: null, copied };
51
+ } catch {
52
+ return { skipped: "copy-failed", copied: 0 };
53
+ }
54
+ }
55
+
56
+
57
+ export function seedOutputStyleDefault({
58
+ runtime = "claude-code",
59
+ home = homedir(),
60
+ defaultValue = DEFAULT_OUTPUT_STYLE,
61
+ } = {}) {
62
+ if (runtime !== "claude-code") {
63
+ return { skipped: "runtime-not-claude-code", action: null };
64
+ }
65
+ const settingsPath = join(home, ".claude", "settings.json");
66
+ if (!existsSync(settingsPath)) {
67
+ return { skipped: "claude-settings-not-found", action: null };
68
+ }
69
+ let settings;
70
+ try {
71
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
72
+ } catch {
73
+ return { skipped: "settings-not-parseable", action: null };
74
+ }
75
+ if (typeof settings !== "object" || settings === null) {
76
+ return { skipped: "settings-not-object", action: null };
77
+ }
78
+ if (typeof settings.outputStyle === "string" && settings.outputStyle) {
79
+ return { skipped: null, action: "noop", value: settings.outputStyle };
80
+ }
81
+ settings.outputStyle = defaultValue;
82
+ const tmp = `${settingsPath}.tmp-${process.pid}`;
83
+ try {
84
+ writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
85
+ renameSync(tmp, settingsPath);
86
+ } catch {
87
+ // Read-only ~/.claude, disk full… — "never raises" must be true of
88
+ // THIS module, not delegated to caller try/catch (QG blocker M1).
89
+ return { skipped: "write-failed", action: null };
90
+ }
91
+ return { skipped: null, action: "created", value: defaultValue };
92
+ }
@@ -174,6 +174,25 @@ export async function update() {
174
174
  copyFileSync(statuslineSrc, join(installDir, "config", statuslineFile));
175
175
  console.log(" ✓ Statusline updated");
176
176
  }
177
+ // Interaction Reform PR1 — refresh the ArkaOS output style file and
178
+ // seed the default (if-absent; explicit operator choice preserved).
179
+ try {
180
+ const { installOutputStyles, seedOutputStyleDefault } = await import("./output-style.js");
181
+ const styleResult = installOutputStyles({
182
+ sourceDir: join(ARKAOS_ROOT, "config", "output-styles"),
183
+ });
184
+ if (styleResult.copied > 0) {
185
+ console.log(" ✓ Output style updated");
186
+ }
187
+ const seedResult = seedOutputStyleDefault({
188
+ runtime: manifest.runtime || "claude-code",
189
+ });
190
+ if (!seedResult.skipped && seedResult.action === "created") {
191
+ console.log(` ✓ outputStyle default set to "${seedResult.value}"`);
192
+ }
193
+ } catch (err) {
194
+ console.log(` ⚠ Output style update failed (${err.message})`);
195
+ }
177
196
 
178
197
  // ── 3. Update hooks ──
179
198
  console.log(" [3/8] Updating hooks...");
@@ -51,8 +51,14 @@ export function seedWorktreeBaseRef({
51
51
  }
52
52
  settings.worktree = { ...(existing ?? {}), baseRef: defaultValue };
53
53
  const tmp = `${settingsPath}.tmp-${process.pid}`;
54
- writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
55
- renameSync(tmp, settingsPath);
54
+ try {
55
+ writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
56
+ renameSync(tmp, settingsPath);
57
+ } catch {
58
+ // Keeps the header's "never raises" claim true inside the module
59
+ // (QG blocker M1 parity, PR1 Interaction Reform).
60
+ return { skipped: "write-failed", action: null };
61
+ }
56
62
  return {
57
63
  skipped: null,
58
64
  action: existing ? "merged" : "created",
@@ -462,5 +462,9 @@
462
462
  "dev-spec-list": {
463
463
  "keywords": ["list specs", "show specs", "existing specs", "all specifications", "project specs"],
464
464
  "examples": ["show me all specs for this project", "list existing specifications", "what specs do we have"]
465
+ },
466
+ "arka-recipes": {
467
+ "keywords": ["recipe", "recipes", "receita", "reuse", "validated build", "apply recipe", "feature template"],
468
+ "examples": ["que receitas temos", "apply the laravel login recipe", "reusa a receita de auth"]
465
469
  }
466
470
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "_meta": {
3
3
  "version": "3.0.0",
4
- "generated": "2026-07-09T15:18:25Z",
5
- "total_commands": 262,
4
+ "generated": "2026-07-09T19:22:12Z",
5
+ "total_commands": 264,
6
6
  "generator": "core/registry/generator.py",
7
7
  "departments": {
8
- "arka": 19,
8
+ "arka": 21,
9
9
  "brand": 12,
10
10
  "community": 14,
11
11
  "content": 14,
@@ -317,6 +317,44 @@
317
317
  "requires_branch": false,
318
318
  "modifies_code": false
319
319
  },
320
+ {
321
+ "id": "arka-refine",
322
+ "command": "/arka refine <rough idea>",
323
+ "department": "arka",
324
+ "description": "Turn a vague or domain-unfamiliar ask into a precise English prompt by asking about the topic first (arka-refine). Auto-suggested on vague requests.",
325
+ "lead_agent": "arka",
326
+ "keywords": [],
327
+ "examples": [],
328
+ "source": "builtin",
329
+ "tier": 2,
330
+ "requires_branch": false,
331
+ "modifies_code": false
332
+ },
333
+ {
334
+ "id": "arka-recipes",
335
+ "command": "/arka recipes [list\\|show\\|apply] <slug>",
336
+ "department": "arka",
337
+ "description": "Reuse validated QG-approved feature builds (arka-recipes). Synapse L7.6 auto-surfaces matches.",
338
+ "lead_agent": "arka",
339
+ "keywords": [
340
+ "recipe",
341
+ "recipes",
342
+ "receita",
343
+ "reuse",
344
+ "validated build",
345
+ "apply recipe",
346
+ "feature template"
347
+ ],
348
+ "examples": [
349
+ "que receitas temos",
350
+ "apply the laravel login recipe",
351
+ "reusa a receita de auth"
352
+ ],
353
+ "source": "builtin",
354
+ "tier": 2,
355
+ "requires_branch": false,
356
+ "modifies_code": false
357
+ },
320
358
  {
321
359
  "id": "do",
322
360
  "command": "/do <description>",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "4.11.0",
3
+ "version": "4.12.0",
4
4
  "description": "The Operating System for AI Agent Teams",
5
5
  "type": "module",
6
6
  "bin": {
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "arkaos-core"
3
- version = "4.11.0"
3
+ version = "4.12.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"}