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
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  npx arkaos install
9
9
  ```
10
10
 
11
- [![npm](https://img.shields.io/npm/v/arkaos)](https://www.npmjs.com/package/arkaos) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Tests](https://img.shields.io/badge/tests-1993%20passing-brightgreen)]()
11
+ [![npm](https://img.shields.io/npm/v/arkaos)](https://www.npmjs.com/package/arkaos) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Tests](https://img.shields.io/badge/tests-3025%20passing-brightgreen)]()
12
12
 
13
13
  ---
14
14
 
@@ -228,6 +228,84 @@ arkaos scheduler logs # View logs
228
228
 
229
229
  ---
230
230
 
231
+ ## Intelligence Loop (v2.21.0+)
232
+
233
+ Three-layer system that makes ArkaOS consult its brain before going external, and write every session's learnings back to the vault automatically. The system compounds daily — tomorrow's ArkaOS is smarter than today's.
234
+
235
+ ### Synapse L2.5 — KB Context Injection (v2.21.0)
236
+
237
+ On every user prompt, ArkaOS runs semantic search against the Obsidian vault and injects the top relevant notes (with wikilinks and excerpts) as context **before the model starts planning**. The agent sees what the vault already knows, naturally — no hard gate, no friction.
238
+
239
+ - Top 3–5 notes by similarity
240
+ - Jaccard fallback when vector store absent
241
+ - Feature flag `synapse.l25KbContext` default `true`
242
+ - Kill switch `ARKA_BYPASS_L25=1`
243
+
244
+ ### Research Gate — Natural Nudge (v2.21.0)
245
+
246
+ When an agent tries `Context7`, `WebSearch`, `WebFetch`, or `Firecrawl` without consulting Obsidian first:
247
+
248
+ - **First attempt** → natural PT-PT nudge listing top 3 vault hits. Allows the call.
249
+ - **Second attempt in same turn** → deny. The nudge wasn't enough.
250
+
251
+ Feature flag `hooks.kbFirst` default `false` in v2.21.0 — dormant until operator flips. Kill switch `ARKA_BYPASS_KB_FIRST=1` (audited).
252
+
253
+ ### Auto-Documentor + Cataloger + Relator (v2.21.0)
254
+
255
+ After every approved session, an async worker writes the learnings back to the vault:
256
+
257
+ 1. **Extract** — parses the transcript for sources consulted, decisions made, deliverables produced
258
+ 2. **Classify** — cataloger chooses the right taxonomic home (code pattern, persona, client strategy, marketing test, ADR, research finding, framework, or session fallback)
259
+ 3. **Write** — creates the note at the correct vault path with frontmatter + tags
260
+ 4. **Relate** — relator finds semantically similar existing notes, creates bidirectional `[[wikilinks]]`, updates MOCs
261
+
262
+ The vault becomes a relational graph that grows with every session.
263
+
264
+ ### LLM Agnostic Auto-Documentor (v2.22.0)
265
+
266
+ The synthesis LLM call is runtime-agnostic. **Zero model hardcoding.** Whatever runtime you have configured decides the model:
267
+
268
+ | Provider | Default | Model decided by |
269
+ |---|---|---|
270
+ | `subagent` | ✅ | Active runtime's headless CLI (`claude -p`, `gemini -p …`) |
271
+ | `anthropic-direct` | — | `ANTHROPIC_MODEL` env var; no code default |
272
+ | `stub` | tests | Template fallback |
273
+
274
+ Fallback chain `subagent → anthropic-direct → stub` never raises. Prompt caching ON by default (5-min TTL `cache_control: ephemeral` on system block).
275
+
276
+ ### Budget Telemetry + `/arka costs` (v2.22.0)
277
+
278
+ Every LLM call appends to `~/.arkaos/telemetry/llm-cost.jsonl` with tokens, cache hits, and estimated cost. Per [ADR-011](docs/adr/), this is **visibility only — never blocks**.
279
+
280
+ ```bash
281
+ /arka costs # today (default)
282
+ /arka costs week # last 7 days
283
+ /arka costs month # last 30 days
284
+ /arka costs sessions # top 10 expensive sessions
285
+ ```
286
+
287
+ Soft advisory when a single session exceeds $5 equivalent. No hard caps.
288
+
289
+ ### Flow Marker v2 (v2.21.0)
290
+
291
+ The constitutional 13-phase flow enforcement (binding in v2.20) got a turn-scoped marker cache, eliminating the cross-turn false positives that triggered on subagent dispatch and short user continuations. ADR-compliant: cache accelerates ALLOW decisions only; the transcript remains authoritative for DENY.
292
+
293
+ ### Polish & Consolidation (v2.22.1)
294
+
295
+ - `core/shared/safe_session_id.py` — single source of truth for the path-traversal / injection allowlist, deduped across 6 modules (100% coverage, 33 security-contract tests)
296
+ - Gemini CLI headless live (`gemini -p "…" --output-format json`)
297
+ - `_MAX_FALLBACK_NOTES = 2000` bound on Synapse L2.5 degraded-mode scan
298
+ - Auto-documentor coverage lifted 93% → 98%
299
+ - Template synthesiser now mirrors LLM prompt structure (Key Facts → Decisions → Sources)
300
+
301
+ ### ADRs
302
+
303
+ - [`2026-04-20-flow-marker-v2.md`](docs/adr/2026-04-20-flow-marker-v2.md) — turn-scoped cache amendment
304
+ - [`2026-04-20-kb-first-intelligence.md`](docs/adr/2026-04-20-kb-first-intelligence.md) — Synapse L2.5 + gate + auto-documentor
305
+ - [`2026-04-20-llm-agnostic.md`](docs/adr/2026-04-20-llm-agnostic.md) — runtime-agnostic LLM wiring
306
+
307
+ ---
308
+
231
309
  ## Ecosystem Management
232
310
 
233
311
  ArkaOS manages client projects as **ecosystems** — groups of related projects with dedicated squads.
@@ -370,21 +448,39 @@ Full documentation is available on the **[GitHub Wiki](https://github.com/andrea
370
448
 
371
449
  ## CLI Reference
372
450
 
451
+ **Installer (terminal):**
452
+
373
453
  ```bash
374
- npx arkaos install # Fresh install (auto-detects runtime)
375
- npx arkaos update # Update to latest version
376
- npx arkaos migrate # Migrate from v1
377
- npx arkaos doctor # Health check
378
- npx arkaos dashboard # Start monitoring dashboard
379
- npx arkaos keys # Manage API keys
380
- npx arkaos uninstall # Remove ArkaOS
454
+ npx arkaos install # Fresh install (auto-detects runtime)
455
+ npx arkaos@latest update # Update core + hooks to latest version
456
+ npx arkaos migrate # Migrate from v1
457
+ npx arkaos doctor # Health check
458
+ npx arkaos dashboard # Start monitoring dashboard
459
+ npx arkaos keys # Manage API keys
460
+ npx arkaos uninstall # Remove ArkaOS
381
461
  ```
382
462
 
463
+ **In-session commands (inside Claude Code / Codex / Gemini / Cursor):**
464
+
465
+ ```
466
+ /arka update # Sync all project configs after core update
467
+ /arka status # System health + LLM costs (24h)
468
+ /arka costs [today|week|month|all|sessions] # LLM cost visibility
469
+ /arka index # (Re)index Obsidian vault into vector store
470
+ /arka search <query> # Semantic search in knowledge base
471
+ /arka standup # Daily standup (projects, blockers, updates)
472
+ /arka onboard <path> # Onboard an existing project
473
+ /arka conclave # Personal AI advisory board
474
+ /do <description> # Universal routing — natural language to department
475
+ ```
476
+
477
+ Department commands: `/dev`, `/mkt`, `/brand`, `/fin`, `/strat`, `/ecom`, `/kb`, `/ops`, `/pm`, `/saas`, `/landing`, `/content`, `/community`, `/sales`, `/lead`, `/org`.
478
+
383
479
  ---
384
480
 
385
481
  ## Contributing
386
482
 
387
- See [CONTRIBUTING.md](.github/CONTRIBUTING.md). PRs welcome — all changes require passing the full test suite (1,993 tests) and Quality Gate review.
483
+ See [CONTRIBUTING.md](.github/CONTRIBUTING.md). PRs welcome — all changes require passing the full test suite (3,025 tests) and Quality Gate review.
388
484
 
389
485
  ## License
390
486
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.22.1
1
+ 2.28.0
package/arka/SKILL.md CHANGED
@@ -122,6 +122,7 @@ violation (squad-routing, arka-supremacy, spec-driven, mandatory-qa).
122
122
  | `/arka search <query>` | Semantic search in knowledge base |
123
123
  | `/arka keys` | Manage API keys (OpenAI, Google, fal.ai) |
124
124
  | `/arka personas` | Manage AI personas (create, clone to agent) |
125
+ | `/arka resume <PR_URL>` | Re-enter the Claude Code session that produced a PR (GitHub / GitLab / Bitbucket). Wraps the native `/resume` from Claude Code 2.1.122+. Useful with `arka-spec` and `arka-release` archaeology. |
125
126
  | `/do <description>` | Universal routing — natural language to department command |
126
127
 
127
128
  ## Universal Orchestrator (/do)
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: arka-bootstrap-agent
3
+ description: >
4
+ Formalises the "agents set up agents" pattern surfaced in the 2026-05-13
5
+ Nick Saraev × Greg Isenberg podcast on the Orgo agent business. When the
6
+ user asks to spin up a new specialist or an integration that requires
7
+ research-heavy setup, this skill orchestrates The Forge to dispatch
8
+ research subagents (Perplexity / Exa / Context7 / Firecrawl / XMCP),
9
+ synthesises the findings, and produces a ready-to-use agent YAML or
10
+ installation guide.
11
+ allowed-tools: [Agent, Read, Write, Bash]
12
+ ---
13
+
14
+ # /arka bootstrap-agent — agents that set up agents
15
+
16
+ > Pattern source: Nick Saraev (Orgo) interview, 2026-05-13. ArkaOS already
17
+ > has The Forge for complexity-based planning; this skill is the explicit
18
+ > entry point users invoke when they want a new specialist or a setup
19
+ > playbook rather than a feature.
20
+
21
+ ## Subcommands
22
+
23
+ | Command | What it does |
24
+ | --- | --- |
25
+ | `/arka bootstrap-agent specialist <slug>` | Generates a new Tier 2 agent YAML for a domain you describe. Dispatches research subagents to gather domain frameworks, conventions, and common pitfalls. Produces `departments/<dept>/agents/<slug>.yaml` with full 4-framework DNA. |
26
+ | `/arka bootstrap-agent integration <tool>` | Installation playbook for an external tool (e.g. Hermes, Composio, Agent Mail). Researches official docs + community recipes, outputs a step-by-step setup guide and any required MCP config. |
27
+ | `/arka bootstrap-agent persona <name>` | Builds an AI persona profile (DISC + Enneagram + OCEAN + MBTI) from learned content. Delegates to `/kb` (Clara) for source ingestion. |
28
+
29
+ ## How it works
30
+
31
+ ```
32
+ User: /arka bootstrap-agent specialist "design-tokens-engineer"
33
+
34
+
35
+ 1. The Forge classifies request complexity (usually "medium" — single
36
+ specialist, multiple research dimensions).
37
+ 2. Spawns 3-5 research subagents in parallel:
38
+ - Perplexity MCP → real-time framework discovery
39
+ - Exa AI → semantic search for prior art
40
+ - Context7 → official documentation pulls
41
+ - Firecrawl → scrape competitor / canonical sources
42
+ - XMCP → Twitter / X conversations for community wisdom
43
+ 3. Critic synthesis: a Tier 0 reviewer collapses overlap, surfaces
44
+ contradictions, prioritises by source weight.
45
+ 4. Generates the deliverable (YAML / playbook / persona) and saves to
46
+ the canonical path.
47
+ 5. Quality Gate (Marta + Eduardo + Francisca) approves before output
48
+ reaches the user.
49
+ ```
50
+
51
+ ## Why this exists
52
+
53
+ Per the Orgo interview, the recurring pattern in successful one-person
54
+ agent businesses is "use agents to set up agents". ArkaOS already had
55
+ the primitives — The Forge for planning, the Agent tool for subagent
56
+ dispatch, KB-first research — but no single entry point that made the
57
+ pattern *the* way to add capability. This skill is that entry.
58
+
59
+ ## Boundaries
60
+
61
+ - This skill **generates**. It does not modify production code.
62
+ - The generated YAML lands in `departments/<dept>/agents/` for review;
63
+ it is **not** auto-registered until the user commits and the next
64
+ loader pass picks it up.
65
+ - Personas built via this skill go through `/kb` for the actual
66
+ content ingestion (YouTube / PDFs / articles). This skill orchestrates,
67
+ it does not bypass the knowledge pipeline.
68
+
69
+ ## Cross-references
70
+
71
+ - Source pattern: 2026-05-13 Orgo podcast (Nick Saraev × Greg Isenberg)
72
+ - Related: `/arka forge` (planning engine, lower level)
73
+ - Related: `/kb persona` (content-driven persona builder)
74
+ - Related: `/arka research` (the same research-fan-out pattern for
75
+ one-off knowledge tasks rather than agent generation)
76
+ - Memory: [[project_next_level_conclave]]
@@ -19,8 +19,8 @@ Full-spectrum AI media production platform. From ComfyUI node engineering to Hol
19
19
 
20
20
  | Project | Type | Stack | Path |
21
21
  |---------|------|-------|------|
22
- | **purz-comfyui-workflows** | Workflow Collection | ComfyUI JSON (7 workflows, 110+ nodes) | `/Users/andreagroferreira/AIProjects/purz-comfyui-workflows` |
23
- | **lora_tester** | CLI Tool + Gallery | Python 3.8+ (stdlib) + Vanilla HTML/JS | `/Users/andreagroferreira/AIProjects/lora_tester` |
22
+ | **purz-comfyui-workflows** | Workflow Collection | ComfyUI JSON (7 workflows, 110+ nodes) | `${ARKA_OS_REPOS}/purz-comfyui-workflows` |
23
+ | **lora_tester** | CLI Tool + Gallery | Python 3.8+ (stdlib) + Vanilla HTML/JS | `${ARKA_OS_REPOS}/lora_tester` |
24
24
 
25
25
  ## Squads
26
26
 
@@ -7,8 +7,8 @@ Referenced from SKILL.md. Read only when needed.
7
7
  For EVERY `/comfyui` request, follow this workflow:
8
8
 
9
9
  ### Phase 1 — Context Loading
10
- 1. Read ComfyUI skill reference: `/Users/andreagroferreira/AIProjects/lora_tester/.claude/skills/comfy_local/skill.md`
11
- 2. Check available workflows: `ls /Users/andreagroferreira/AIProjects/purz-comfyui-workflows/`
10
+ 1. Read ComfyUI skill reference: `${ARKA_OS_REPOS}/lora_tester/.claude/skills/comfy_local/skill.md`
11
+ 2. Check available workflows: `ls ${ARKA_OS_REPOS}/purz-comfyui-workflows/`
12
12
  3. Check ComfyUI server: `curl -s http://localhost:8188/system_stats 2>/dev/null`
13
13
  4. Load project context for affected repos
14
14
  5. Identify which squad(s) the request needs
@@ -320,8 +320,8 @@ while pending:
320
320
  curl -s http://localhost:8188/system_stats 2>/dev/null
321
321
 
322
322
  # Project status
323
- cd /Users/andreagroferreira/AIProjects/purz-comfyui-workflows && git log --oneline -5
324
- cd /Users/andreagroferreira/AIProjects/lora_tester && git log --oneline -5
323
+ cd ${ARKA_OS_REPOS}/purz-comfyui-workflows && git log --oneline -5
324
+ cd ${ARKA_OS_REPOS}/lora_tester && git log --oneline -5
325
325
  ```
326
326
 
327
327
  Present as:
@@ -403,10 +403,10 @@ When Iris (Node Researcher) investigates custom nodes:
403
403
 
404
404
  ## Obsidian Output
405
405
 
406
- All documentation: `/Users/andreagroferreira/Documents/Personal/Projects/WizardingCode Internal/ComfyUI/`
406
+ All documentation: `${VAULT_PATH}/Projects/ComfyUI/`
407
407
 
408
408
  ```
409
- WizardingCode Internal/ComfyUI/
409
+ Projects/ComfyUI/
410
410
  ├── Home.md <- Ecosystem overview
411
411
  ├── Workflows/
412
412
  │ ├── LTX-2 T2V.md
@@ -55,6 +55,17 @@ Source:
55
55
  One JSONL line per LLM call, written by every provider adapter.
56
56
  Malformed lines are skipped and counted, never raised.
57
57
 
58
+ ## Cost-tuning levers
59
+
60
+ Outside this skill's scope but worth surfacing alongside the summary:
61
+
62
+ | Lever | Where | Effect |
63
+ | --- | --- | --- |
64
+ | `ARKAOS_LLM_PROVIDER` | env | Switch between Anthropic, OpenAI, Gemini adapters per the multi-LLM router. |
65
+ | `ANTHROPIC_BEDROCK_SERVICE_TIER` | env (Claude Code 2.1.122+) | `default` / `flex` / `priority`. Only relevant when routing through AWS Bedrock — `flex` cuts cost ~50 % on non-urgent workloads at the price of higher tail latency. |
66
+ | Agent `model:` field | `departments/*/agents/*.yaml` | Per-agent override per the model-routing matrix in CLAUDE.md. Mechanical roles default to haiku, C-suite to opus. |
67
+ | Quality Gate model | constitution rule (NON-NEGOTIABLE) | Marta / Eduardo / Francisca always run on opus regardless of the cost ceiling. |
68
+
58
69
  ## Non-negotiables
59
70
 
60
71
  1. Read-only. This skill never edits state.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: arka-design-ops
3
+ description: >
4
+ Brand Design Ops sub-squad orchestrator. Routes design-system extraction,
5
+ WCAG audit, and shadcn padronisation work to Iris (lead) + Nia
6
+ (extraction) + Oren (WCAG) + Leo (shadcn). Inspired by the AIOX Squad
7
+ → Sub-Squad pattern documented in the 2026-04-30 KB live and unblocked
8
+ for ArkaOS by the v2.27.0 Conclave roadmap.
9
+ allowed-tools: [Read, Write, Bash, Edit]
10
+ ---
11
+
12
+ # /brand design-ops — Design Ops sub-squad
13
+
14
+ > Sub-squad of `/brand` (Valentina). Operational specialists for the
15
+ > production rails of design systems: tokens, audits, components.
16
+
17
+ ## Squad
18
+
19
+ | Agent | Role | Tier | Owns |
20
+ | --- | --- | --- | --- |
21
+ | **Iris** (`design-ops-lead`) | Lead | 1 | governance, escalation to Valentina |
22
+ | **Nia** (`extraction-script-writer`) | Specialist | 2 | reverse-engineer tokens from sites / figma |
23
+ | **Oren** (`wcag-auditor`) | Specialist | 2 | WCAG 2.2 AA conformance + reports |
24
+ | **Leo** (`shadcn-padronizer`) | Specialist | 2 | shadcn/ui canonical components |
25
+
26
+ ## Subcommands
27
+
28
+ | Command | Owner | What it does |
29
+ | --- | --- | --- |
30
+ | `/brand design-ops extract <url>` | Nia | Extract color, typography, spacing tokens from a live URL or figma file. Writes JSON to `~/.arkaos/design-ops/<slug>/tokens.json`. |
31
+ | `/brand design-ops wcag <url\|path>` | Oren | Run WCAG 2.2 AA audit. Outputs issue table (severity / criterion / location / fix) + conformance score. |
32
+ | `/brand design-ops shadcn <component>` | Leo | Generate or refactor a component to the shadcn/ui canonical form (CVA variants, Radix primitives, theme tokens). |
33
+ | `/brand design-ops audit <project>` | Iris | Orchestrate full audit: tokens drift, WCAG conformance, component-library variance. Produces a single report. |
34
+
35
+ ## Scripts (under `scripts/`)
36
+
37
+ The scripts library is intentionally small at v2.27.0 — three reference
38
+ implementations to anchor the pattern. Nia / Oren / Leo extend it as
39
+ ArkaOS evolves; AIOX's reference set is ~30 scripts and ArkaOS will
40
+ catch up incrementally.
41
+
42
+ | Script | Owner | Input | Output |
43
+ | --- | --- | --- | --- |
44
+ | `scripts/extract-colors.py` | Nia | URL or local HTML | `colors.json` (DTCG-compliant token list) |
45
+ | `scripts/wcag-contrast.py` | Oren | hex pairs OR CSS file | Issue list with contrast ratios + AA / AAA verdict |
46
+ | `scripts/shadcn-tokens.py` | Leo | tokens.json | shadcn CSS variables block + Tailwind config snippet |
47
+
48
+ Run any script with `python3 scripts/<name>.py --help` for usage.
49
+
50
+ ## Output
51
+
52
+ All design-ops output writes to:
53
+ - `~/.arkaos/design-ops/<slug>/` — generated artefacts (JSON, CSS, reports)
54
+ - `${VAULT_PATH}/Projects/Design Ops/<slug>.md` — human-readable summary (Obsidian)
55
+
56
+ ## Boundaries
57
+
58
+ - Strategy and visual direction stay with **Valentina** (`/brand`).
59
+ - Iris escalates anything that requires brand-level taste calls.
60
+ - Design-ops never opens PRs or pushes code; it produces specs, tokens,
61
+ audits. Implementation goes back to `/dev` via Paulo.
62
+
63
+ ## Cross-references
64
+
65
+ - Pattern source: KB note `🧠 Knowledge Base/Frameworks/AIOX Squads` (2026-04-30 live)
66
+ - ADR: this skill is the v2.27.0 Conclave instantiation of the sub-squad pattern
67
+ - Parent: `/brand` (Valentina)
68
+ - Stack origin: v2.27.0 (PR5 of 6 from the 2026-05-13 Conclave roadmap)
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env python3
2
+ """Extract colour tokens from CSS / HTML / JSON (Nia's reference script).
3
+
4
+ Scans the input for hex colours and named CSS variables, normalises to
5
+ lower-case 6-digit hex, deduplicates, and emits a DTCG-compliant
6
+ ``colors.json`` token list.
7
+
8
+ Usage:
9
+ python3 extract-colors.py path/to/styles.css
10
+ python3 extract-colors.py --stdin < styles.css
11
+ cat styles.css | python3 extract-colors.py --stdin
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import json
18
+ import re
19
+ import sys
20
+ from pathlib import Path
21
+
22
+ HEX = re.compile(r"#([0-9a-fA-F]{3,8})\b")
23
+ RGB = re.compile(r"rgb(?:a)?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)")
24
+
25
+
26
+ def normalise(hex_value: str) -> str | None:
27
+ h = hex_value.lower()
28
+ if len(h) == 3:
29
+ h = "".join(c * 2 for c in h)
30
+ elif len(h) == 4:
31
+ h = "".join(c * 2 for c in h[:3])
32
+ elif len(h) == 8:
33
+ h = h[:6]
34
+ if len(h) != 6:
35
+ return None
36
+ return f"#{h}"
37
+
38
+
39
+ def rgb_to_hex(r: int, g: int, b: int) -> str:
40
+ return f"#{r:02x}{g:02x}{b:02x}"
41
+
42
+
43
+ def extract(text: str) -> list[str]:
44
+ seen: set[str] = set()
45
+ out: list[str] = []
46
+ for m in HEX.finditer(text):
47
+ norm = normalise(m.group(1))
48
+ if norm and norm not in seen:
49
+ seen.add(norm)
50
+ out.append(norm)
51
+ for r, g, b in RGB.findall(text):
52
+ norm = rgb_to_hex(int(r), int(g), int(b))
53
+ if norm not in seen:
54
+ seen.add(norm)
55
+ out.append(norm)
56
+ return out
57
+
58
+
59
+ def to_dtcg(colors: list[str]) -> dict:
60
+ tokens = {}
61
+ for i, c in enumerate(colors):
62
+ slug = f"color-{i:03d}"
63
+ tokens[slug] = {"$value": c, "$type": "color"}
64
+ return {"$schema": "https://design-tokens.org/draft", "colors": tokens}
65
+
66
+
67
+ def main(argv: list[str]) -> int:
68
+ parser = argparse.ArgumentParser(description=__doc__)
69
+ parser.add_argument("source", nargs="?", help="path to CSS / HTML file")
70
+ parser.add_argument("--stdin", action="store_true", help="read from stdin")
71
+ args = parser.parse_args(argv)
72
+
73
+ if args.stdin or args.source == "-":
74
+ text = sys.stdin.read()
75
+ elif args.source:
76
+ text = Path(args.source).read_text(encoding="utf-8")
77
+ else:
78
+ parser.error("provide a source path or use --stdin")
79
+
80
+ colors = extract(text)
81
+ print(json.dumps(to_dtcg(colors), indent=2))
82
+ return 0
83
+
84
+
85
+ if __name__ == "__main__":
86
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env python3
2
+ """Convert DTCG colour tokens into shadcn/ui CSS variables (Leo's script).
3
+
4
+ Reads a DTCG-style ``colors.json`` (as produced by ``extract-colors.py``)
5
+ and emits the canonical shadcn/ui CSS variable block plus a matching
6
+ ``tailwind.config.js`` ``theme.extend.colors`` snippet.
7
+
8
+ Usage:
9
+ python3 shadcn-tokens.py colors.json
10
+ python3 shadcn-tokens.py colors.json --prefix brand-
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import json
17
+ import sys
18
+ from pathlib import Path
19
+
20
+
21
+ def to_css_var(slug: str, value: str, prefix: str) -> str:
22
+ return f" --{prefix}{slug}: {value};"
23
+
24
+
25
+ def to_tailwind_entry(slug: str, prefix: str) -> str:
26
+ key = slug.replace("color-", "")
27
+ return f' "{prefix}{slug}": "var(--{prefix}{slug})",'
28
+
29
+
30
+ def main(argv: list[str]) -> int:
31
+ parser = argparse.ArgumentParser(description=__doc__)
32
+ parser.add_argument("source", help="path to DTCG colors.json")
33
+ parser.add_argument("--prefix", default="", help="CSS variable prefix (e.g. 'brand-')")
34
+ args = parser.parse_args(argv)
35
+
36
+ data = json.loads(Path(args.source).read_text(encoding="utf-8"))
37
+ tokens = data.get("colors", {})
38
+ if not tokens:
39
+ print("no colours found in source", file=sys.stderr)
40
+ return 1
41
+
42
+ css_vars = [to_css_var(slug, t["$value"], args.prefix) for slug, t in tokens.items()]
43
+ tailwind = [to_tailwind_entry(slug, args.prefix) for slug in tokens]
44
+
45
+ print(":root {")
46
+ print("\n".join(css_vars))
47
+ print("}\n")
48
+
49
+ print("// tailwind.config.js — theme.extend.colors")
50
+ print("{")
51
+ print(' theme: { extend: { colors: {')
52
+ print("\n".join(tailwind))
53
+ print(" } } }")
54
+ print("}")
55
+ return 0
56
+
57
+
58
+ if __name__ == "__main__":
59
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+ """WCAG 2.2 contrast ratio checker (Oren's reference script).
3
+
4
+ Compares foreground / background colours and reports whether the pair
5
+ passes WCAG 2.2 Level AA (4.5 : 1 normal text, 3 : 1 large text and UI
6
+ components) and AAA (7 : 1 normal, 4.5 : 1 large).
7
+
8
+ Usage:
9
+ python3 wcag-contrast.py "#1a1a1a" "#ffffff"
10
+ python3 wcag-contrast.py --json "#0f172a" "#ffffff" "#3b82f6" "#ffffff"
11
+
12
+ Outputs a single-line verdict or, with --json, a structured report.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import json
19
+ import sys
20
+
21
+
22
+ def relative_luminance(rgb: tuple[int, int, int]) -> float:
23
+ """WCAG relative luminance formula."""
24
+ def channel(c: int) -> float:
25
+ s = c / 255
26
+ return s / 12.92 if s <= 0.03928 else ((s + 0.055) / 1.055) ** 2.4
27
+
28
+ r, g, b = (channel(c) for c in rgb)
29
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b
30
+
31
+
32
+ def contrast_ratio(fg: tuple[int, int, int], bg: tuple[int, int, int]) -> float:
33
+ lf, lb = relative_luminance(fg), relative_luminance(bg)
34
+ lighter, darker = max(lf, lb), min(lf, lb)
35
+ return (lighter + 0.05) / (darker + 0.05)
36
+
37
+
38
+ def hex_to_rgb(hex_color: str) -> tuple[int, int, int]:
39
+ s = hex_color.lstrip("#")
40
+ if len(s) == 3:
41
+ s = "".join(c * 2 for c in s)
42
+ if len(s) != 6:
43
+ raise ValueError(f"Invalid hex colour: {hex_color}")
44
+ return int(s[0:2], 16), int(s[2:4], 16), int(s[4:6], 16)
45
+
46
+
47
+ def verdict(ratio: float) -> dict[str, bool]:
48
+ return {
49
+ "AA_normal": ratio >= 4.5,
50
+ "AA_large": ratio >= 3.0,
51
+ "AAA_normal": ratio >= 7.0,
52
+ "AAA_large": ratio >= 4.5,
53
+ }
54
+
55
+
56
+ def check_pair(fg_hex: str, bg_hex: str) -> dict[str, object]:
57
+ fg = hex_to_rgb(fg_hex)
58
+ bg = hex_to_rgb(bg_hex)
59
+ ratio = round(contrast_ratio(fg, bg), 2)
60
+ return {
61
+ "fg": fg_hex,
62
+ "bg": bg_hex,
63
+ "ratio": ratio,
64
+ **verdict(ratio),
65
+ }
66
+
67
+
68
+ def main(argv: list[str]) -> int:
69
+ parser = argparse.ArgumentParser(description=__doc__)
70
+ parser.add_argument("colors", nargs="*", help="alternating fg bg pairs")
71
+ parser.add_argument("--json", action="store_true", help="emit JSON report")
72
+ args = parser.parse_args(argv)
73
+
74
+ if len(args.colors) < 2 or len(args.colors) % 2 != 0:
75
+ parser.error("provide pairs of hex colours: <fg> <bg> [<fg> <bg> ...]")
76
+
77
+ pairs = list(zip(args.colors[::2], args.colors[1::2]))
78
+ results = [check_pair(fg, bg) for fg, bg in pairs]
79
+
80
+ if args.json:
81
+ print(json.dumps({"results": results}, indent=2))
82
+ return 0
83
+
84
+ for r in results:
85
+ flags = [k for k, v in r.items() if k.startswith("AA") and v]
86
+ flag_str = "+".join(flags) if flags else "FAILS_ALL"
87
+ print(f"{r['fg']} on {r['bg']}: {r['ratio']}:1 → {flag_str}")
88
+ return 0
89
+
90
+
91
+ if __name__ == "__main__":
92
+ sys.exit(main(sys.argv[1:]))