arkaos 2.22.1 → 2.28.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 (67) hide show
  1. package/README.md +105 -9
  2. package/VERSION +1 -1
  3. package/arka/SKILL.md +1 -0
  4. package/arka/skills/bootstrap-agent/SKILL.md +76 -0
  5. package/arka/skills/comfyui/SKILL.md +2 -2
  6. package/arka/skills/comfyui/references/workflows.md +6 -6
  7. package/arka/skills/costs/SKILL.md +11 -0
  8. package/arka/skills/design-ops/SKILL.md +68 -0
  9. package/arka/skills/design-ops/scripts/extract-colors.py +86 -0
  10. package/arka/skills/design-ops/scripts/shadcn-tokens.py +59 -0
  11. package/arka/skills/design-ops/scripts/wcag-contrast.py +92 -0
  12. package/arka/skills/research/SKILL.md +117 -0
  13. package/config/cognition/prompts/dreaming.md +3 -3
  14. package/config/cognition/prompts/research.md +4 -4
  15. package/config/constitution.yaml +4 -0
  16. package/config/hooks/post-tool-use.sh +17 -0
  17. package/config/hooks/user-prompt-submit.sh +22 -1
  18. package/core/agents/__pycache__/loader.cpython-313.pyc +0 -0
  19. package/core/agents/__pycache__/schema.cpython-313.pyc +0 -0
  20. package/core/agents/loader.py +4 -1
  21. package/core/agents/schema.py +29 -0
  22. package/core/cognition/__pycache__/auto_documentor.cpython-313.pyc +0 -0
  23. package/core/cognition/__pycache__/retrieval.cpython-313.pyc +0 -0
  24. package/core/cognition/capture/__pycache__/collector.cpython-313.pyc +0 -0
  25. package/core/cognition/capture/collector.py +10 -3
  26. package/core/cognition/retrieval.py +383 -0
  27. package/core/cognition/scheduler/__pycache__/daemon.cpython-313.pyc +0 -0
  28. package/core/cognition/scheduler/daemon.py +5 -0
  29. package/core/jobs/__pycache__/auto_doc_worker.cpython-313.pyc +0 -0
  30. package/core/obsidian/__pycache__/writer.cpython-313.pyc +0 -0
  31. package/core/obsidian/writer.py +5 -4
  32. package/core/runtime/__pycache__/base.cpython-313.pyc +0 -0
  33. package/core/runtime/__pycache__/claude_code.cpython-313.pyc +0 -0
  34. package/core/runtime/__pycache__/codex_cli.cpython-313.pyc +0 -0
  35. package/core/runtime/__pycache__/gemini_cli.cpython-313.pyc +0 -0
  36. package/core/runtime/__pycache__/llm_provider.cpython-313.pyc +0 -0
  37. package/core/runtime/__pycache__/path_resolver.cpython-313.pyc +0 -0
  38. package/core/runtime/path_resolver.py +202 -0
  39. package/core/shared/__pycache__/__init__.cpython-313.pyc +0 -0
  40. package/core/shared/__pycache__/safe_session_id.cpython-313.pyc +0 -0
  41. package/core/specs/SPEC-installer-cross-os.md +227 -0
  42. package/core/specs/SPEC-paths-portability.md +209 -0
  43. package/core/synapse/__pycache__/kb_cache.cpython-313.pyc +0 -0
  44. package/core/synapse/__pycache__/layers.cpython-313.pyc +0 -0
  45. package/core/workflow/__pycache__/flow_enforcer.cpython-313.pyc +0 -0
  46. package/core/workflow/__pycache__/marker_cache.cpython-313.pyc +0 -0
  47. package/core/workflow/__pycache__/research_gate.cpython-313.pyc +0 -0
  48. package/departments/brand/agents/design-ops/design-ops-lead.yaml +78 -0
  49. package/departments/brand/agents/design-ops/extraction-script-writer.yaml +74 -0
  50. package/departments/brand/agents/design-ops/shadcn-padronizer.yaml +76 -0
  51. package/departments/brand/agents/design-ops/wcag-auditor.yaml +76 -0
  52. package/departments/dev/skills/mcp/SKILL.md +16 -0
  53. package/departments/dev/skills/scaffold/SKILL.md +4 -4
  54. package/departments/kb/skills/knowledge/SKILL.md +1 -1
  55. package/departments/ops/skills/operations/SKILL.md +1 -1
  56. package/installer/cli.js +2 -1
  57. package/installer/doctor.js +48 -0
  58. package/installer/index.js +26 -1
  59. package/installer/migrate-user-data.js +17 -1
  60. package/installer/migrations/v3_path_schema.js +109 -0
  61. package/installer/package-manager.js +191 -0
  62. package/installer/path-resolver.js +124 -0
  63. package/installer/system-tools.js +243 -0
  64. package/installer/update.js +24 -3
  65. package/knowledge/obsidian-config.json +1 -1
  66. package/package.json +1 -1
  67. package/pyproject.toml +1 -1
@@ -0,0 +1,227 @@
1
+ ---
2
+ type: spec
3
+ status: approved
4
+ feature: installer-cross-os
5
+ project: ArkaOS
6
+ version: 2.24.0
7
+ pr: PR2 of 6 (Conclave roadmap 2026-05-13)
8
+ branch: feature/v2.24.0-installer-cross-os
9
+ date_created: 2026-05-13
10
+ tags: [spec, arkaos, installer, cross-os, v2.24.0, conclave-pr2]
11
+ ---
12
+
13
+ # SPEC: Installer Cross-OS Completo (v2.24.0)
14
+
15
+ ## Overview
16
+
17
+ **Problem.** ArkaOS installer is ~65 % cross-OS complete. Obsidian is never auto-installed (only path-detected). Node.js is never validated. `install.sh` hardcodes the GitHub repo URL on line 25 and only scans macOS paths for Obsidian vaults on lines 625–640.
18
+
19
+ **Goal.** Deliver a full cross-OS install flow (macOS / Linux / Windows) that auto-installs what it can without sudo, reports what needs sudo with copy-paste-ready commands, and falls back gracefully when no package manager is available.
20
+
21
+ **Actors.** End users running `npx arkaos install` on fresh macOS / Linux / Windows machines; CI pipelines running headless.
22
+
23
+ ## Scope
24
+
25
+ **In scope (PR2 / v2.24.0):**
26
+
27
+ | Item | Purpose |
28
+ |---|---|
29
+ | new `installer/package-manager.js` | brew / winget / snap / apt / choco detection + install helpers |
30
+ | new `installer/system-tools.js` | `ensureSystemTools()` phase: Obsidian, Node.js ≥ 20, Python ≥ 3.12 |
31
+ | modify `installer/index.js` | call `ensureSystemTools()` before venv creation |
32
+ | modify `installer/update.js` | re-run `ensureSystemTools()` on `npx arkaos update` |
33
+ | modify `installer/cli.js` | new `npx arkaos doctor` subcommand + `--no-system` flag |
34
+ | new `installer/doctor.js` | diagnose-only report (table format, exit codes 0/1/2) |
35
+ | modify `install.sh` line 25 | `ARKAOS_REPO_URL` env override (default canonical URL) |
36
+ | modify `install.sh` lines 625-640 | add Linux + Windows vault detection |
37
+ | modify `installer/index.js` dashboard step | `pnpm install` / `npm ci` in `dashboard/` if Node ≥ 20 |
38
+ | new `tests/installer/test_package_manager.mjs` | ≥ 10 Node tests |
39
+ | new `tests/installer/test_system_tools.mjs` | ≥ 5 Node tests |
40
+
41
+ **Out of scope:**
42
+
43
+ - Auto-update of system tools when newer versions exist (just detect + report).
44
+ - Flatpak / AppImage Obsidian variants on Linux (defer to PR6 cleanup if user demand).
45
+ - Interactive sudo prompt (André chose "print command for manual run" — headless-safe).
46
+ - Aggressive auto-install (André chose hybrid: install what can be installed without sudo; report rest).
47
+
48
+ ## Acceptance Criteria
49
+
50
+ 1. **Fresh macOS install.** Given a Mac without Obsidian, when `npx arkaos install` runs, then `brew install --cask obsidian` is invoked (or printed if brew missing) and Obsidian binary is detected on completion.
51
+
52
+ 2. **Fresh Ubuntu install.** Given Ubuntu without Obsidian / Node, when `npx arkaos install` runs, then the installer prints copy-paste commands like:
53
+ ```
54
+ To finish install, run:
55
+ sudo apt update && sudo apt install -y nodejs
56
+ sudo snap install obsidian --classic
57
+ Then re-run: npx arkaos install
58
+ ```
59
+ and exits with code 0 (informational, not a failure).
60
+
61
+ 3. **Fresh Windows 11.** Given Windows without Obsidian / Node, when `npx arkaos install` runs, then it invokes `winget install --id Obsidian.Obsidian --silent` (and similar for Node), or prints the command if elevation is denied.
62
+
63
+ 4. **`npx arkaos doctor`.** Given any state, when `npx arkaos doctor` runs, then it prints a table with Obsidian / Node / Python rows showing installed/version/location/action, with exit code 0 (all OK), 1 (missing), or 2 (version mismatch).
64
+
65
+ 5. **`install.sh` GitHub URL configurable.** Given `ARKAOS_REPO_URL=https://gitlab.example.com/x/y.git` is set, when `install.sh` runs in curl|bash mode, then it clones from the custom URL.
66
+
67
+ 6. **`install.sh` Linux vault detection.** Given Ubuntu user with vault at `~/.local/share/obsidian/vault` OR `~/Documents/Obsidian`, when `install.sh` runs vault auto-detection, then both candidate paths are scanned.
68
+
69
+ 7. **`install.sh` Windows vault detection.** Given Git Bash on Windows with vault at `$USERPROFILE/Documents/Obsidian`, when `install.sh` runs vault auto-detection, then the path is scanned.
70
+
71
+ 8. **`--no-system` flag.** Given `npx arkaos install --no-system`, when installer runs, then `ensureSystemTools()` is bypassed (legacy install-only flow preserved for CI).
72
+
73
+ 9. **Idempotent.** Given `ensureSystemTools()` has already installed everything, when it runs again, then no install commands fire, no side effects, exit success.
74
+
75
+ 10. **Regression-free.** Given PR2 merges, when full pytest suite runs, then all 3049 tests still pass. New Node tests add ≥ 15 cases for package-manager + system-tools.
76
+
77
+ 11. **shellcheck clean.** Given the updated `install.sh`, when `shellcheck install.sh` runs, then zero new warnings vs baseline.
78
+
79
+ ## Data Model
80
+
81
+ N/A — pure installer logic, no persisted schema changes.
82
+
83
+ ## API Contracts
84
+
85
+ ### `installer/package-manager.js`
86
+
87
+ ```javascript
88
+ /**
89
+ * Detect the highest-priority package manager available on this host.
90
+ *
91
+ * Priority order:
92
+ * macOS: brew
93
+ * Linux: apt > snap (apt for Node, snap for Obsidian classic-confined)
94
+ * Windows: winget > choco
95
+ *
96
+ * Returns the canonical name string or null when nothing is available.
97
+ */
98
+ export function detectPackageManager(): string | null
99
+
100
+ /**
101
+ * Install a single package via the detected (or specified) manager.
102
+ * Never invokes sudo automatically. When sudo is required, returns
103
+ * the command for the caller to print and the user to run.
104
+ */
105
+ export function installViaPackageManager(
106
+ pkg: string,
107
+ options?: { manager?: string, fallbackUrl?: string }
108
+ ): {
109
+ success: boolean,
110
+ command: string, // command that ran or should run
111
+ needsSudo: boolean,
112
+ installed: boolean, // did we actually install in this call?
113
+ fallbackOpened?: boolean, // did we open the download URL?
114
+ error?: string,
115
+ }
116
+
117
+ /** Format an array of missing-package commands into copy-paste text. */
118
+ export function formatSudoInstructions(missing: SudoCommand[]): string
119
+ ```
120
+
121
+ ### `installer/system-tools.js`
122
+
123
+ ```javascript
124
+ export type ToolStatus = {
125
+ name: "obsidian" | "node" | "python",
126
+ installed: boolean,
127
+ version?: string,
128
+ location?: string,
129
+ needsAction: "none" | "install" | "upgrade",
130
+ suggestedCommand?: string,
131
+ needsSudo?: boolean,
132
+ }
133
+
134
+ /**
135
+ * Check each required system tool. Install what can be installed without
136
+ * sudo. Collect commands for tools that need sudo into `sudoCommands`
137
+ * so the caller can print them to the user.
138
+ *
139
+ * Idempotent: tools already installed at sufficient version are no-ops.
140
+ */
141
+ export function ensureSystemTools(options?: {
142
+ skipSystem?: boolean,
143
+ dryRun?: boolean,
144
+ }): {
145
+ obsidian: ToolStatus,
146
+ node: ToolStatus,
147
+ python: ToolStatus,
148
+ sudoCommands: string[],
149
+ }
150
+
151
+ export function checkObsidian(): ToolStatus
152
+ export function checkNode(): ToolStatus
153
+ export function checkPython(): ToolStatus
154
+ ```
155
+
156
+ ### `installer/doctor.js`
157
+
158
+ ```javascript
159
+ /**
160
+ * `npx arkaos doctor` — diagnose-only report. Never installs.
161
+ * Returns exit code 0 (all OK), 1 (missing tool), 2 (version mismatch).
162
+ */
163
+ export function runDoctor(): number
164
+ ```
165
+
166
+ ### CLI integration
167
+
168
+ `installer/cli.js` gains:
169
+ - `npx arkaos doctor` subcommand → calls `runDoctor()`
170
+ - `--no-system` global flag → sets `options.skipSystem = true` for `ensureSystemTools()`
171
+
172
+ ## Edge Cases
173
+
174
+ 1. **brew not installed on macOS** → print Homebrew install one-liner, exit 0 with informational message.
175
+ 2. **snap available but `obsidian` not in store** (older Ubuntu) → fall back to `https://obsidian.md/download` opened in browser, or printed for headless.
176
+ 3. **Windows < 1809 without winget** → choco fallback, or printed download URL.
177
+ 4. **Node installed but version < 20** → `needsAction: "upgrade"`, suggested command per OS.
178
+ 5. **Multiple Python versions present** → prefer 3.12+, recommend `pyenv` if mixed.
179
+ 6. **User installed Obsidian via Flatpak** → detect via `flatpak list md.obsidian` (best-effort), accept as installed.
180
+ 7. **Concurrent installer runs** → checks read filesystem only; install commands themselves are idempotent (apt/brew/winget handle already-installed packages gracefully).
181
+ 8. **curl|bash mode** → `install.sh` clones repo first; `ARKAOS_REPO_URL` env wins over hardcoded default; supports private fork redirection.
182
+ 9. **Sudo denied** on Windows winget → print the command and ask user to re-run from an elevated prompt; do not loop or retry.
183
+ 10. **Headless CI** → `--no-system` flag skips entirely; `arka doctor` exit codes drive CI decisions.
184
+ 11. **Network failure during install** → catch, report, exit with copy-paste recovery command.
185
+
186
+ ## Test Scenarios
187
+
188
+ | # | Scenario | Type | Expected |
189
+ |---|---|---|---|
190
+ | 1 | `detectPackageManager` on macOS w/ brew | Unit | `"brew"` |
191
+ | 2 | `detectPackageManager` on Ubuntu w/ apt+snap | Unit | `"apt"` (then `"snap"` for Obsidian-specific calls) |
192
+ | 3 | `detectPackageManager` on Windows w/ winget | Unit | `"winget"` |
193
+ | 4 | `detectPackageManager` on Linux w/ none | Unit | `null` |
194
+ | 5 | `checkObsidian` when binary in PATH | Unit | `installed: true, location: <path>` |
195
+ | 6 | `checkObsidian` when binary missing | Unit | `installed: false, needsAction: "install"` |
196
+ | 7 | `checkNode` when version < 20 | Unit | `needsAction: "upgrade"` |
197
+ | 8 | `checkNode` when version ≥ 20 | Unit | `needsAction: "none"` |
198
+ | 9 | `checkPython` when 3.11 only | Unit | `needsAction: "upgrade"` |
199
+ | 10 | `ensureSystemTools` w/ all 3 missing | Integration | `sudoCommands` array populated |
200
+ | 11 | `ensureSystemTools` idempotent | Integration | second call: no commands |
201
+ | 12 | `runDoctor` exit codes | Integration | 0 / 1 / 2 verified |
202
+ | 13 | `install.sh` with `ARKAOS_REPO_URL` override | Manual / shell | clones from custom URL |
203
+ | 14 | `install.sh` Linux vault detection | Manual / shell | finds `~/.local/share/obsidian/...` |
204
+ | 15 | `install.sh` Windows vault detection | Manual / shell | finds `$USERPROFILE/Documents/Obsidian` |
205
+ | 16 | `--no-system` flag bypass | Integration | `ensureSystemTools` not called |
206
+ | 17 | full pytest regression | Integration | 3049 still pass |
207
+
208
+ ## Dependencies
209
+
210
+ - `installer/platform.js` (existing) — `IS_WINDOWS`, `CMD_FINDER`, `PYTHON_CMD`.
211
+ - `installer/path-resolver.js` (PR1) — for any path template substitution.
212
+ - `installer/python-resolver.js` (existing) — Python detection logic.
213
+ - Node.js `node:child_process` for `execSync` (already used).
214
+ - No new npm deps.
215
+
216
+ ## Quality Gate Criteria
217
+
218
+ - **Eduardo:** all error / status messages read naturally in EN; copy-paste sudo commands are accurate and OS-specific; no AI clichés.
219
+ - **Francisca:** package-manager detection covers macOS/Ubuntu/Debian/Fedora/Arch/Windows 10+/11; `ensureSystemTools()` is fully idempotent; no shell injection vectors in execSync calls; shellcheck clean on install.sh.
220
+ - **Marta:** verified on 3 synthetic environments — macOS with brew, Ubuntu without snap, Windows with winget — each producing the right printed commands and side effects.
221
+
222
+ ## References
223
+
224
+ - Plan: `~/.arkaos/plans/2026-05-13-arkaos-next-level-conclave.md` (PR2 section)
225
+ - Memory: [[project_next_level_conclave]]
226
+ - Existing: [[SPEC-paths-portability]] (PR1, dependency), [[platform.js]] (platform abstraction)
227
+ - HIGH items inherited from PR1 audit: `install.sh:25`, `install.sh:625-640`
@@ -0,0 +1,209 @@
1
+ ---
2
+ type: spec
3
+ status: approved
4
+ feature: paths-portability
5
+ project: ArkaOS
6
+ version: 2.23.0
7
+ pr: PR1 of 6 (Conclave roadmap 2026-05-13)
8
+ branch: feature/v2.23.0-paths-portability
9
+ date_created: 2026-05-13
10
+ date_updated: 2026-05-13
11
+ tags: [spec, arkaos, paths, portability, refactor, v2.23.0, conclave-pr1]
12
+ ---
13
+
14
+ # SPEC: Paths Portability (v2.23.0)
15
+
16
+ ## Overview
17
+
18
+ **Problem.** ArkaOS source contains hardcoded user-specific paths (`/Users/andreagroferreira/...`) across SKILL.md files, JSON configs, Python regexes, and cognitive prompts. These break for the **~20K users** currently running ArkaOS with different home directories and OS layouts.
19
+
20
+ **Goal.** Replace 7 CRITICAL hardcoded paths with profile-driven templates resolved at runtime, with **non-breaking auto-migration** for the existing user base.
21
+
22
+ **Actors.** ArkaOS core (skill loader, cognition collector, installer migration), end users (via `~/.arkaos/profile.json`).
23
+
24
+ ## Scope
25
+
26
+ **In scope (PR1 / v2.23.0):**
27
+
28
+ | # | File | Fix |
29
+ |---|---|---|
30
+ | 1 | `knowledge/obsidian-config.json:6` | `vault_path` value resolved at load via `path_resolver.resolve_dict` (profile.vaultPath) |
31
+ | 2 | `core/cognition/capture/collector.py:15-17` | Regex generated from `profile.projectRoots`; fallback `os.getcwd()` |
32
+ | 3 | `departments/kb/skills/knowledge/SKILL.md:25` | `${VAULT_PATH}` template |
33
+ | 4 | `departments/ops/skills/operations/SKILL.md:59` | `${VAULT_PATH}` template |
34
+ | 5 | `arka/skills/comfyui/SKILL.md:22-23` + `references/workflows.md` | `${ARKA_OS_REPOS}/{purz-comfyui-workflows,lora_tester}` |
35
+ | 6 | `config/cognition/prompts/dreaming.md` | `${VAULT_PATH}` template |
36
+ | 7 | `config/cognition/prompts/research.md` | `${VAULT_PATH}` template |
37
+ | 8 | `departments/dev/skills/scaffold/SKILL.md:19` | `${GIT_HOST}` template, default `github.com` HTTPS |
38
+ | — | new `core/runtime/path_resolver.py` | `resolve()`, `resolve_dict()`, `load_profile()` |
39
+ | — | new `installer/migrations/v3_path_schema.js` | Auto-migrate `projectsDir` text → `projectRoots` list + `reposRoot` |
40
+ | — | skill loader extension | Substitute `${VAR}` tokens at SKILL.md load |
41
+ | — | new `tests/python/test_path_resolver.py` | ≥ 15 tests |
42
+
43
+ **Out of scope (deferred):**
44
+
45
+ - `install.sh:25, 631-634` (GitHub URL hardcode + Mac-only Obsidian detection) → **PR2 v2.24.0** (cross-OS installer is the natural home for OS-aware logic)
46
+ - 50+ docs/superpowers/plans hardcoded paths (LOW priority, examples only) → **PR6 v2.28.0** cleanup pass
47
+ - Vision bridge migration (test_vision_bridge.py + scripts/tools/vision/*) → file was discarded; not relevant to PR1
48
+ - Migration of installed user skills under `~/.claude/skills/arka/` — installer rewrites these from source on every update; fixing source covers it
49
+
50
+ ## Acceptance Criteria
51
+
52
+ 1. **Zero CRITICAL grep hits.** Given a fresh checkout of `feature/v2.23.0-paths-portability`, when `grep -rn "/Users/andreagroferreira" core/ arka/ installer/ config/ departments/ knowledge/ --exclude-dir=node_modules --exclude-dir=__pycache__ --exclude-dir=.git --exclude-dir=docs` runs, then it returns **0 CRITICAL hits**. Hits inside `docs/superpowers/plans/` are tracked but acceptable (PR6 cleanup).
53
+
54
+ 2. **Synthetic install works end-to-end.** Given `$HOME=/tmp/testuser` and `~/.arkaos/profile.json` containing `{"version":"3","vaultPath":"/tmp/testuser/vault","reposRoot":"/tmp/testuser/repos","projectRoots":["/tmp/testuser/code"]}`, when every SKILL.md is loaded, then `${VAULT_PATH}`, `${ARKA_OS_REPOS}` and `${GIT_HOST}` resolve to the configured values with zero `${` leakage.
55
+
56
+ 3. **20K-user safe migration.** Given a legacy profile.json missing `projectRoots` and `reposRoot`, when `npx arkaos@latest update` runs, then:
57
+ - `projectRoots` is derived from parsing `projectsDir` text (regex extracts absolute paths).
58
+ - If parsing finds 0 paths, sensible defaults are applied (`["~/Herd","~/Work","~/AIProjects"]`).
59
+ - `reposRoot` defaults to `~/AIProjects` (or first match containing `AIProjects` if any).
60
+ - `version` bumps to `"3"`, `migrated_at` timestamp added.
61
+ - A `.bak-<timestamp>` backup is written first.
62
+ - `[arka:migrated] profile.json schema v2 → v3` logged.
63
+
64
+ 4. **Hard error on truly missing profile.** Given `~/.arkaos/profile.json` is absent or unparseable JSON, when any `path_resolver` call runs, then `ProfileMissingError("Run /arka setup to configure ArkaOS paths")` is raised. No silent fallback.
65
+
66
+ 5. **Env-var override.** Given `ARKAOS_VAULT_PATH=/tmp/override` is set, when `${VAULT_PATH}` is resolved, then the env var wins over profile. Same for `ARKAOS_REPOS_ROOT`, `ARKAOS_PROJECT_ROOTS`, `ARKAOS_GIT_HOST`. Empty string is treated as unset.
67
+
68
+ 6. **Regression-free.** Given PR1 is merged, when full pytest suite runs, then all existing 542+ tests pass and ≥ 15 new path_resolver tests pass. Coverage ≥ 80%.
69
+
70
+ 7. **Migration idempotent.** Given migration ran once, when it runs again, then profile.json is unchanged (no version re-bump, no second backup).
71
+
72
+ ## Data Model
73
+
74
+ | Field (new in profile.json v3) | Type | Default | Source |
75
+ |---|---|---|---|
76
+ | `version` | `"3"` (str) | — | bumped by migration |
77
+ | `projectRoots` | `list[str]` | `["~/Herd","~/Work","~/AIProjects"]` | parsed from `projectsDir` text on migration |
78
+ | `reposRoot` | `str` | `"~/AIProjects"` | matches first path containing `AIProjects`, else default |
79
+ | `migrated_at` | ISO8601 `str` | — | written at migration time |
80
+
81
+ **Backwards-compat fields kept verbatim:** `language`, `market`, `role`, `company`, `projectsDir` (kept for human reference), `vaultPath`, `created`, `updated`.
82
+
83
+ ## API Contracts
84
+
85
+ ### `core/runtime/path_resolver.py`
86
+
87
+ ```python
88
+ class ProfileMissingError(RuntimeError):
89
+ """Raised when ~/.arkaos/profile.json is absent or unparseable."""
90
+
91
+ @dataclass
92
+ class ProfileV3:
93
+ version: str
94
+ vault_path: str # ${VAULT_PATH}
95
+ repos_root: str # ${ARKA_OS_REPOS}
96
+ project_roots: list[str] # ${PROJECT_ROOTS}
97
+ raw: dict # full profile.json for forward-compat
98
+
99
+ def load_profile() -> ProfileV3:
100
+ """Load and cache ~/.arkaos/profile.json. Raises ProfileMissingError."""
101
+
102
+ def resolve(template: str) -> str:
103
+ """Substitute known tokens. Unknown tokens pass through unchanged.
104
+
105
+ Tokens:
106
+ ${VAULT_PATH} -> ARKAOS_VAULT_PATH env or profile.vaultPath
107
+ ${ARKA_OS_REPOS} -> ARKAOS_REPOS_ROOT env or profile.reposRoot
108
+ ${PROJECT_ROOTS} -> os.pathsep-joined profile.projectRoots
109
+ ${GIT_HOST} -> ARKAOS_GIT_HOST env or "github.com"
110
+ ${HOME} -> os.path.expanduser("~")
111
+ """
112
+
113
+ def resolve_dict(d: dict) -> dict:
114
+ """Recursively resolve string values in a JSON-shaped dict."""
115
+
116
+ def project_root_regex() -> re.Pattern:
117
+ """Compile regex from profile.projectRoots for collector.py."""
118
+ ```
119
+
120
+ ### Skill loader extension
121
+
122
+ Find existing skill loader (likely `core/agents/loader.py` or `arka/skills/.../loader`); extend:
123
+
124
+ ```python
125
+ def load_skill_markdown(path: Path) -> str:
126
+ return path_resolver.resolve(path.read_text())
127
+ ```
128
+
129
+ ### Migration script `installer/migrations/v3_path_schema.js`
130
+
131
+ ```javascript
132
+ function migrateV3(profile) {
133
+ if (profile.version === "3" || profile.projectRoots) return profile;
134
+ const roots = parseProjectsDirText(profile.projectsDir);
135
+ const reposRoot = roots.find(r => r.includes("AIProjects")) || "~/AIProjects";
136
+ return { ...profile, version: "3", projectRoots: roots,
137
+ reposRoot, migrated_at: new Date().toISOString() };
138
+ }
139
+ ```
140
+
141
+ Wired into `installer/migrate-user-data.js` (existing framework).
142
+
143
+ ## Edge Cases
144
+
145
+ 1. **`projectsDir` text is empty / null** → defaults applied (no error).
146
+ 2. **`vaultPath` empty string** → treated as missing → `ProfileMissingError`.
147
+ 3. **SKILL.md contains literal `${SOME_BASH_VAR}` for agent instructions** → resolver only touches the 5 known tokens; unknown tokens pass through.
148
+ 4. **Windows path separators in `${PROJECT_ROOTS}`** → uses `os.pathsep` (`;` on Windows, `:` on Unix). Internal storage is POSIX `/`.
149
+ 5. **Digest path from foreign OS** (cross-machine Obsidian sync) → `_detect_project` falls back to `os.getcwd()` if no `projectRoots` match (existing behaviour).
150
+ 6. **Concurrent calls during migration** → migration uses temp-file + atomic rename; safe.
151
+ 7. **User edits profile.json manually mid-session** → load_profile is cached per-process; re-import to refresh. Documented.
152
+ 8. **Migration corrupts profile** → `.bak-<timestamp>` rollback file always exists.
153
+
154
+ ## Test Scenarios
155
+
156
+ | # | Scenario | Type | Expected |
157
+ |---|---|---|---|
158
+ | 1 | `resolve("${VAULT_PATH}/foo")` with `vaultPath="/v"` | Unit | `"/v/foo"` |
159
+ | 2 | `resolve("${HOME}/bar")` | Unit | `"$HOME/bar"` expanded |
160
+ | 3 | `resolve("${UNKNOWN}/baz")` | Unit | `"${UNKNOWN}/baz"` unchanged |
161
+ | 4 | `resolve` with absent profile.json | Unit | `ProfileMissingError` |
162
+ | 5 | `resolve` with `ARKAOS_VAULT_PATH=/x` | Unit | env wins over profile |
163
+ | 6 | `resolve_dict` on obsidian-config.json fixture | Unit | All string values resolved |
164
+ | 7 | `_detect_project` with `projectRoots=["~/Herd"]` | Unit | matches path under `~/Herd` |
165
+ | 8 | `_detect_project` on Windows-style path | Unit | matches with `\` separator |
166
+ | 9 | `load_skill_markdown` on kb SKILL.md | Integration | `${VAULT_PATH}` substituted |
167
+ | 10 | full pytest suite | Regression | all 542+ tests pass |
168
+ | 11 | `migrateV3` on legacy profile (v2 schema) | Integration | new fields added, old kept, .bak written |
169
+ | 12 | `migrateV3` idempotent (second run no-op) | Integration | profile unchanged, no second .bak |
170
+ | 13 | Grep audit (CRITICAL paths) | Audit | 0 hits in core/ arka/ installer/ config/ departments/ knowledge/ |
171
+ | 14 | `scaffold SKILL.md ${GIT_HOST}` | Integration | `github.com` default |
172
+ | 15 | `comfyui SKILL.md ${ARKA_OS_REPOS}` | Integration | substituted correctly |
173
+ | 16 | `migrateV3` with empty `projectsDir` | Unit | defaults applied, no crash |
174
+ | 17 | env vars with empty string values | Unit | treated as unset, profile wins |
175
+
176
+ ## Dependencies
177
+
178
+ - No external deps. Reuses existing `installer/migrate-user-data.js` framework + `core/specs/` Living Specs engine.
179
+ - New Python module only depends on stdlib (`json`, `os`, `pathlib`, `re`, `dataclasses`).
180
+
181
+ ## Migration Plan for 20K Users
182
+
183
+ `npx arkaos@latest update` runs `migrate-user-data.js` which includes the new `migrateV3` step. Flow:
184
+
185
+ 1. Read `~/.arkaos/profile.json`. If absent → skip migration (user must run `/arka setup`).
186
+ 2. If `version === "3"` or `projectRoots` exists → no-op (idempotent).
187
+ 3. Otherwise:
188
+ - Write backup: `~/.arkaos/profile.json.bak-<unix-timestamp>`.
189
+ - Parse `projectsDir` text with `/((?:\/Users|\/home|[A-Z]:\\Users)\/\S+?\/(?:Herd|Work|AIProjects|code|repos))/g`.
190
+ - Apply defaults if parsing yields 0 results.
191
+ - Atomic write: temp file + `fs.rename`.
192
+ - Log `[arka:migrated] profile.json schema v2 → v3 ({N} roots, repos=...)` to `~/.arkaos/logs/migrate.log`.
193
+
194
+ **Rollback procedure (documented in installer):** restore `.bak-<timestamp>` over profile.json.
195
+
196
+ ## Quality Gate Criteria
197
+
198
+ Marta (CQO) requires APPROVED from all three reviewers:
199
+
200
+ - **Eduardo (Copy):** All SKILL.md files read naturally after substitution — no `${` leakage in human-facing prose. Error messages clear and actionable.
201
+ - **Francisca (Tech):** path_resolver handles all 8 edge cases. Migration is atomic + idempotent + reversible. 17 test scenarios all green. No crash on corrupt profile.
202
+ - **Marta (CQO):** Migration verified non-breaking by simulating 5 different legacy profile shapes (André's current one + 4 synthetic variants representing common 20K-user variations).
203
+
204
+ ## References
205
+
206
+ - Plan: `~/.arkaos/plans/2026-05-13-arkaos-next-level-conclave.md` (PR1 section)
207
+ - Memory: [[project_next_level_conclave]]
208
+ - KB: [[2026-04-29-claude-code-2-1-122-and-2-1-123]] (Claude Code features unblocked by 2.1.122)
209
+ - Existing Specs in this project: [[SPEC-cognitive-layer-feedback-loop]], [[SPEC-wave1-single-source-of-truth]]
@@ -0,0 +1,78 @@
1
+ id: design-ops-lead-iris
2
+ name: Iris
3
+ role: Design Ops Lead
4
+ department: brand
5
+ tier: 1
6
+ model: sonnet
7
+
8
+ parent_squad: brand
9
+ sub_squad_role: lead
10
+
11
+ behavioral_dna:
12
+ disc:
13
+ primary: D
14
+ secondary: C
15
+ communication_style: "Direct, blueprint-driven, defends production quality without smothering creative intent"
16
+ under_pressure: "Pushes back on shortcuts; protects the design system from drift"
17
+ motivator: "A design system that ships consistently across every surface"
18
+ enneagram:
19
+ type: 8
20
+ wing: 9
21
+ core_motivation: "Make the right thing also be the easy thing for designers and engineers"
22
+ core_fear: "Inconsistent UI shipped because nobody owned the production rails"
23
+ subtype: self-preservation
24
+ big_five:
25
+ openness: 60
26
+ conscientiousness: 88
27
+ extraversion: 52
28
+ agreeableness: 55
29
+ neuroticism: 28
30
+ mbti:
31
+ type: ESTJ
32
+
33
+ mental_models:
34
+ primary:
35
+ - "Atomic Design (Frost)"
36
+ - "Design Tokens W3C Spec"
37
+ - "Single Source of Truth (Wheeler)"
38
+ secondary:
39
+ - "Theory of Constraints (Goldratt)"
40
+ - "Cynefin (Snowden)"
41
+ - "WCAG 2.2 AA"
42
+
43
+ authority:
44
+ orchestrate: true
45
+ approve_quality: true
46
+ delegates_to:
47
+ - extraction-script-writer
48
+ - wcag-auditor
49
+ - shadcn-padronizer
50
+ escalates_to: brand-director-valentina
51
+
52
+ expertise:
53
+ domains:
54
+ - design tokens (JSON + CSS variables)
55
+ - component libraries (shadcn/ui, Radix, Headless UI)
56
+ - design system governance
57
+ - figma → code pipelines
58
+ - accessibility compliance (WCAG 2.2 AA/AAA)
59
+ - cross-platform tokenisation (Style Dictionary, Tailwind)
60
+ frameworks:
61
+ - Atomic Design (Frost)
62
+ - Design Tokens Community Group
63
+ - WCAG 2.2
64
+ - Style Dictionary
65
+ - shadcn/ui conventions
66
+ - Tailwind CSS configuration
67
+ depth: master
68
+ years_equivalent: 12
69
+
70
+ communication:
71
+ language: en
72
+ tone: "precise, blueprint-driven, low-drama"
73
+ vocabulary_level: advanced
74
+ preferred_format: "tables, JSON specs, before/after diffs"
75
+ avoid:
76
+ - "design by feel without a token spec"
77
+ - "ad-hoc one-off components"
78
+ - "shipping without accessibility audit"
@@ -0,0 +1,74 @@
1
+ id: extraction-script-writer-nia
2
+ name: Nia
3
+ role: Design Extraction Engineer
4
+ department: brand
5
+ tier: 2
6
+ model: sonnet
7
+
8
+ parent_squad: brand
9
+ sub_squad_role: extraction-script-writer
10
+
11
+ behavioral_dna:
12
+ disc:
13
+ primary: C
14
+ secondary: D
15
+ communication_style: "Investigative, evidence-first, writes the script before opining"
16
+ under_pressure: "Goes deeper into the source; refuses to guess"
17
+ motivator: "Reproducible extraction pipelines that turn a live site into structured tokens"
18
+ enneagram:
19
+ type: 5
20
+ wing: 6
21
+ core_motivation: "Understand a design system well enough to rebuild it from primitives"
22
+ core_fear: "Shipping a tokenisation that looks right but is silently wrong"
23
+ subtype: self-preservation
24
+ big_five:
25
+ openness: 78
26
+ conscientiousness: 82
27
+ extraversion: 35
28
+ agreeableness: 50
29
+ neuroticism: 30
30
+ mbti:
31
+ type: INTP
32
+
33
+ mental_models:
34
+ primary:
35
+ - "Design Tokens W3C Spec"
36
+ - "Unix Philosophy (Pike & Kernighan)"
37
+ - "Reverse-Engineering Discipline"
38
+ secondary:
39
+ - "AST-based code analysis"
40
+ - "CSS Specificity Model"
41
+ - "Color Theory (Albers)"
42
+
43
+ authority:
44
+ orchestrate: false
45
+ approve_quality: false
46
+ delegates_to: []
47
+ escalates_to: design-ops-lead-iris
48
+
49
+ expertise:
50
+ domains:
51
+ - CSS extraction (computed styles, custom properties)
52
+ - color palette reverse-engineering from screenshots / live DOM
53
+ - typography token harvesting (font-family, size, weight, line-height scales)
54
+ - spacing and grid token inference
55
+ - figma file parsing
56
+ - chromium-headless capture pipelines
57
+ frameworks:
58
+ - W3C Design Tokens spec
59
+ - Style Dictionary
60
+ - Tailwind CSS token format
61
+ - shadcn/ui CSS variable convention
62
+ - DTCG JSON schema
63
+ depth: expert
64
+ years_equivalent: 9
65
+
66
+ communication:
67
+ language: en
68
+ tone: "concise, citation-heavy, almost terse"
69
+ vocabulary_level: advanced
70
+ preferred_format: "JSON specs, before/after color swatches, script snippets"
71
+ avoid:
72
+ - "guessing token values without inspecting the source"
73
+ - "exposing hardcoded RGB instead of named tokens"
74
+ - "premature opinions on visual quality (that's brand-director territory)"
@@ -0,0 +1,76 @@
1
+ id: shadcn-padronizer-leo
2
+ name: Leo
3
+ role: Component Library Padronizer
4
+ department: brand
5
+ tier: 2
6
+ model: sonnet
7
+
8
+ parent_squad: brand
9
+ sub_squad_role: shadcn-padronizer
10
+
11
+ behavioral_dna:
12
+ disc:
13
+ primary: C
14
+ secondary: I
15
+ communication_style: "Pattern-oriented, shows the canonical component before refactoring"
16
+ under_pressure: "Stays in the design system; refuses to fork components for one-offs"
17
+ motivator: "A shadcn/ui-shaped library that every project in the org can adopt verbatim"
18
+ enneagram:
19
+ type: 1
20
+ wing: 9
21
+ core_motivation: "One canonical component, used everywhere, evolving cleanly"
22
+ core_fear: "Five teams shipping five Button components that diverge over a quarter"
23
+ subtype: social
24
+ big_five:
25
+ openness: 65
26
+ conscientiousness: 84
27
+ extraversion: 50
28
+ agreeableness: 58
29
+ neuroticism: 30
30
+ mbti:
31
+ type: ISTP
32
+
33
+ mental_models:
34
+ primary:
35
+ - "shadcn/ui composition philosophy"
36
+ - "Headless UI patterns (Radix, React Aria)"
37
+ - "Atomic Design (Frost)"
38
+ secondary:
39
+ - "Tailwind CSS configuration"
40
+ - "CVA (class-variance-authority) variants"
41
+ - "Theming via CSS variables"
42
+
43
+ authority:
44
+ orchestrate: false
45
+ approve_quality: false
46
+ delegates_to: []
47
+ escalates_to: design-ops-lead-iris
48
+
49
+ expertise:
50
+ domains:
51
+ - shadcn/ui component generation and customisation
52
+ - Radix UI primitives integration
53
+ - Tailwind configuration and theme tokens
54
+ - CVA variants and slot patterns
55
+ - dark mode and theme switching
56
+ - component API surface design (props, slots, polymorphic components)
57
+ - migration from MUI / Chakra / Ant Design to shadcn
58
+ frameworks:
59
+ - shadcn/ui
60
+ - Radix UI
61
+ - React Aria (Adobe)
62
+ - Tailwind CSS
63
+ - class-variance-authority
64
+ - tailwind-merge
65
+ depth: expert
66
+ years_equivalent: 8
67
+
68
+ communication:
69
+ language: en
70
+ tone: "code-first, pragmatic, mild humour"
71
+ vocabulary_level: advanced
72
+ preferred_format: "tsx snippets, before/after component diffs, migration guides"
73
+ avoid:
74
+ - "rebuilding a primitive that Radix already ships"
75
+ - "inline styles that bypass the theme tokens"
76
+ - "magic numbers in className strings"