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,117 @@
1
+ ---
2
+ name: arka-research
3
+ description: >
4
+ Fan-out research workflow. Spawns 5 parallel subagents — Perplexity,
5
+ Exa AI, Context7, Firecrawl, XMCP — synthesises their findings into
6
+ a single report, and writes a Knowledge Base note to the Obsidian
7
+ vault. Inspired by the multi-source research pattern surfaced in the
8
+ 2026-05-13 Orgo podcast (Nick Saraev): "I tell Claude Code, hey,
9
+ spawn five sub-agents — one for Perplexity, one for Exa, one for
10
+ Context7, one for Firecrawl, one for XMCP — and we get best practices."
11
+ allowed-tools: [Agent, Read, Write, mcp__obsidian__search_notes]
12
+ ---
13
+
14
+ # /arka research — one prompt, five parallel sources
15
+
16
+ > Companion to `/arka bootstrap-agent`. Where bootstrap-agent generates
17
+ > capability, this skill generates *knowledge*.
18
+
19
+ ## Usage
20
+
21
+ ```
22
+ /arka research <topic>
23
+ ```
24
+
25
+ `<topic>` is a free-form research question. Examples:
26
+
27
+ - `/arka research "Hermes agent setup with Telegram gateway"`
28
+ - `/arka research "Mistral Medium 3.5 cost vs Sonnet 4.6"`
29
+ - `/arka research "AIOX Squad de Saúde framework"`
30
+
31
+ ## Sources fanned out
32
+
33
+ | Subagent | MCP / tool | Strength |
34
+ | --- | --- | --- |
35
+ | Perplexity | `mcp__perplexity__ask` | Real-time web with citations |
36
+ | Exa AI | `mcp__exa__search` | Semantic vector search across the web |
37
+ | Context7 | `mcp__context7__query-docs` | Up-to-date official library docs |
38
+ | Firecrawl | `mcp__firecrawl__firecrawl_scrape` | Site-specific deep scraping |
39
+ | XMCP | `mcp__x__search` | X / Twitter conversations and threads |
40
+
41
+ If any MCP is not registered in `.mcp.json`, that subagent is skipped
42
+ with a `[arka:source-skipped]` note in the report. KB-first protocol
43
+ still applies — Obsidian search runs before any external call.
44
+
45
+ ## Workflow
46
+
47
+ ```
48
+ 1. KB-first: search Obsidian vault for prior notes on the topic.
49
+ If high-confidence matches exist, the report cites them first
50
+ and asks the user whether external research is still needed.
51
+
52
+ 2. Fan out 5 subagents in parallel via the Agent tool. Each gets
53
+ the same topic, returns a focused short brief (≤500 words).
54
+
55
+ 3. Critic synthesis (Tier 0 reviewer, opus): collapses overlap,
56
+ surfaces contradictions, ranks sources by weight (official docs >
57
+ recent community threads > older articles).
58
+
59
+ 4. Synthesis report saved to:
60
+ ${VAULT_PATH}/Knowledge Base/Research/<YYYY-MM-DD>-<slug>.md
61
+ with full citations and a "where to go next" section.
62
+
63
+ 5. Returns a compact summary to the user (the full report links to
64
+ the Obsidian note).
65
+ ```
66
+
67
+ ## Output shape
68
+
69
+ ```markdown
70
+ ---
71
+ title: <topic>
72
+ date: <YYYY-MM-DD>
73
+ sources: [perplexity, exa, context7, firecrawl, xmcp]
74
+ status: synthesised
75
+ tags: [research, <topic-tag>]
76
+ ---
77
+
78
+ # <Topic>
79
+
80
+ ## TL;DR
81
+ <3-bullet summary>
82
+
83
+ ## Findings by source
84
+ ### Perplexity
85
+ ...
86
+ ### Exa AI
87
+ ...
88
+ (etc.)
89
+
90
+ ## Synthesis
91
+ <contradictions resolved, ranked by source weight>
92
+
93
+ ## Next steps
94
+ <2-3 follow-up questions or actions>
95
+ ```
96
+
97
+ ## Cost & budget
98
+
99
+ This is a heavy operation — 5 parallel LLM calls plus a synthesis call.
100
+ A typical run consumes 3-8k tokens. The `/arka costs` skill tracks the
101
+ spend and the `[arka:warn]` token-hygiene hook flags excessive use.
102
+
103
+ ## Boundaries
104
+
105
+ - Read-only: this skill never modifies code or configuration. It only
106
+ writes to the Obsidian Knowledge Base.
107
+ - KB-first: always check the vault first. Many topics already have
108
+ notes from prior Dreaming / Research sessions.
109
+ - No external research without the user asking — agents do not
110
+ proactively fan out unless `/arka research` is invoked.
111
+
112
+ ## Cross-references
113
+
114
+ - Source pattern: 2026-05-13 Orgo podcast
115
+ - Related: `/arka forge` (planning, not research)
116
+ - Related: `/kb research` (Clara, knowledge management)
117
+ - Related: `/arka bootstrap-agent` (capability-from-research)
@@ -8,7 +8,7 @@ You are ArkaOS performing your nightly Dreaming session. Your job is to review e
8
8
  - Read any file from any project
9
9
  - Read git logs and diffs
10
10
  - Search the web (WebSearch, Firecrawl)
11
- - Write to Obsidian vault at ~/Documents/Personal/Projects/WizardingCode Internal/ArkaOS/
11
+ - Write to Obsidian vault at ${VAULT_PATH}/Projects/ArkaOS/
12
12
  - Write to ~/.arkaos/ (captures, insights, logs, knowledge)
13
13
  - Use browser for research
14
14
  - Read online documentation
@@ -81,7 +81,7 @@ from core.cognition.memory.writer import DualWriter
81
81
 
82
82
  writer = DualWriter(
83
83
  obsidian_base=os.path.expanduser(
84
- "~/Documents/Personal/Projects/WizardingCode Internal/ArkaOS/Knowledge Base"
84
+ "${VAULT_PATH}/Projects/ArkaOS/Knowledge Base"
85
85
  ),
86
86
  vector_db_path=os.path.expanduser("~/.arkaos/knowledge.db"),
87
87
  )
@@ -113,7 +113,7 @@ Use `DualWriter.write()` for each KnowledgeEntry. This automatically writes to b
113
113
  ## Phase 6: Report + Evolution Metrics
114
114
 
115
115
  Write daily report to Obsidian:
116
- `~/Documents/Personal/Projects/WizardingCode Internal/ArkaOS/Dreaming/YYYY-MM-DD.md`
116
+ `${VAULT_PATH}/Projects/ArkaOS/Dreaming/YYYY-MM-DD.md`
117
117
 
118
118
  Format:
119
119
  ```markdown
@@ -8,7 +8,7 @@ You are ArkaOS performing your daily Research session. Your job is to stay curre
8
8
  - Read any file from any project
9
9
  - Read git logs
10
10
  - Search the web extensively (WebSearch, Firecrawl)
11
- - Write to Obsidian vault at ~/Documents/Personal/Projects/WizardingCode Internal/ArkaOS/
11
+ - Write to Obsidian vault at ${VAULT_PATH}/Projects/ArkaOS/
12
12
  - Write to ~/.arkaos/ (insights, logs, knowledge, profiles)
13
13
  - Use browser for deep research
14
14
  - Read online documentation, blogs, changelogs, GitHub releases
@@ -94,7 +94,7 @@ from core.cognition.memory.writer import DualWriter
94
94
 
95
95
  writer = DualWriter(
96
96
  obsidian_base=os.path.expanduser(
97
- "~/Documents/Personal/Projects/WizardingCode Internal/ArkaOS/Knowledge Base"
97
+ "${VAULT_PATH}/Projects/ArkaOS/Knowledge Base"
98
98
  ),
99
99
  vector_db_path=os.path.expanduser("~/.arkaos/knowledge.db"),
100
100
  )
@@ -114,7 +114,7 @@ writer.write(entry)
114
114
  ## Phase 5: Cross-Reference with Dreaming
115
115
 
116
116
  1. Read tonight's Dreaming report (if it exists):
117
- `~/Documents/Personal/Projects/WizardingCode Internal/ArkaOS/Dreaming/YYYY-MM-DD.md`
117
+ `${VAULT_PATH}/Projects/ArkaOS/Dreaming/YYYY-MM-DD.md`
118
118
 
119
119
  2. Read pending insights from `~/.arkaos/insights.db`:
120
120
  ```python
@@ -145,7 +145,7 @@ store.save(insight)
145
145
  ## Phase 6: Intelligence Briefing
146
146
 
147
147
  Write daily briefing to Obsidian:
148
- `~/Documents/Personal/Projects/WizardingCode Internal/ArkaOS/Research/YYYY-MM-DD.md`
148
+ `${VAULT_PATH}/Projects/ArkaOS/Research/YYYY-MM-DD.md`
149
149
 
150
150
  Format:
151
151
  ```markdown
@@ -135,6 +135,10 @@ enforcement_levels:
135
135
  rule: "All ecosystem skills must follow the standard 7-phase workflow defined in config/standards/ecosystem-workflow.md"
136
136
  enforcement: "Ecosystem SKILL.md files must reference or implement all 7 phases"
137
137
 
138
+ - id: sub-squad-hierarchy
139
+ rule: "Agents in a sub-squad MUST declare parent_squad (department slug) and sub_squad_role. Sub-squads inherit the parent department's authority chain; their lead escalates to the department squad lead, not directly to Tier 0."
140
+ enforcement: "Agent loader validates parent_squad + sub_squad_role coherence (sub_squad_role requires parent_squad). PR5 v2.27.0 introduced the pattern; AIOX Squad → Sub-Squad → Skills/Scripts is the reference architecture."
141
+
138
142
  - id: forge-persistence
139
143
  rule: "All forge plans (approved and rejected) must be persisted to Obsidian"
140
144
  enforcement: "persistence.py exports on status change; audit detects missing exports"
@@ -391,6 +391,23 @@ if not match and all_deliverables:
391
391
  fi
392
392
  fi
393
393
 
394
+ # ─── Cognitive layer capture (PR4 v2.26.0 hooks-as-retrieval) ────────────
395
+ # Backgrounded so the hook returns immediately. The retrieval helper has
396
+ # its own internal time caps (ripgrep ≤ 1s, Python fallback capped at 500
397
+ # files) so a runaway extract can never block the next user prompt. We
398
+ # disown so the child cannot zombie if the hook process exits first.
399
+ if [ -n "$SESSION_ID_PTU" ] && [ -n "$TOOL_OUTPUT" ]; then
400
+ _ARKAOS_REPO=$(cat "$HOME/.arkaos/.repo-path" 2>/dev/null || echo "")
401
+ if [ -n "$_ARKAOS_REPO" ] && [ -d "$_ARKAOS_REPO" ]; then
402
+ (
403
+ PYTHONPATH="$_ARKAOS_REPO" python3 -m core.cognition.retrieval capture "$SESSION_ID_PTU" <<EOF >/dev/null 2>&1
404
+ $TOOL_OUTPUT
405
+ EOF
406
+ ) &
407
+ disown 2>/dev/null || true
408
+ fi
409
+ fi
410
+
394
411
  # ─── Log Metrics ─────────────────────────────────────────────────────────
395
412
  _DURATION_MS=$(_hook_ms)
396
413
  METRICS_FILE="$HOME/.arkaos/hook-metrics.json"
@@ -356,9 +356,25 @@ sequential-validation, full-visibility, arka-supremacy."
356
356
  fi
357
357
  fi
358
358
 
359
+ # ─── Cognitive context injection (PR4 v2.26.0 hooks-as-retrieval) ───────
360
+ # Read the context cache populated by the previous PostToolUse turn and
361
+ # inject any KB hits as an `[arka:context]` advisory. The Python helper
362
+ # has internal TTL filtering (10 min) and returns empty when there is no
363
+ # fresh cache, so this stays a no-op until the cognitive layer has data
364
+ # to share.
365
+ _ARKA_CONTEXT_HITS=""
366
+ if [ -n "$SESSION_ID" ]; then
367
+ _ARKAOS_REPO=$(cat "$HOME/.arkaos/.repo-path" 2>/dev/null || echo "")
368
+ if [ -n "$_ARKAOS_REPO" ] && [ -d "$_ARKAOS_REPO" ]; then
369
+ _ARKA_CONTEXT_HITS=$(PYTHONPATH="$_ARKAOS_REPO" python3 -m core.cognition.retrieval inject "$SESSION_ID" 2>/dev/null)
370
+ fi
371
+ fi
372
+
359
373
  # ─── Output ──────────────────────────────────────────────────────────────
360
374
  _OUT_CONTEXT="${_ARKA_GREETING:-}${_SYNC_NOTICE:-}${_ROUTE_REMINDER}${_WORKFLOW_DIRECTIVE} $python_result"
361
375
  [ -n "$_HYGIENE" ] && _OUT_CONTEXT="$_OUT_CONTEXT $_HYGIENE"
376
+ [ -n "$_ARKA_CONTEXT_HITS" ] && _OUT_CONTEXT="$_OUT_CONTEXT
377
+ $_ARKA_CONTEXT_HITS"
362
378
  # Escape for JSON
363
379
  _OUT_JSON=$(python3 -c "import json,sys; print(json.dumps(sys.stdin.read()))" <<< "$_OUT_CONTEXT" 2>/dev/null)
364
380
  if [ -n "$_OUT_JSON" ]; then
@@ -368,7 +384,12 @@ else
368
384
  fi
369
385
 
370
386
  # ─── Metrics ─────────────────────────────────────────────────────────────
387
+ # Count @-mentions in the prompt for at_mention_frequency telemetry. Mirrors
388
+ # the claude_code.at_mention OpenTelemetry event introduced in Claude Code
389
+ # 2.1.122, but works on any version because we count from the same input
390
+ # the hook already receives.
391
+ at_mentions=$(printf '%s' "$user_input" | grep -oE '(^|[[:space:]])@[A-Za-z0-9_./-]+' | wc -l | tr -d ' ')
371
392
  elapsed=$(_hook_ms)
372
393
  if [ "$elapsed" -gt 0 ] 2>/dev/null; then
373
- echo "{\"hook\":\"user-prompt-submit-v2\",\"ms\":$elapsed}" >> "$CACHE_DIR/hook-metrics.jsonl" 2>/dev/null
394
+ echo "{\"hook\":\"user-prompt-submit-v2\",\"ms\":$elapsed,\"at_mentions\":${at_mentions:-0}}" >> "$CACHE_DIR/hook-metrics.jsonl" 2>/dev/null
374
395
  fi
@@ -60,7 +60,10 @@ def load_all_agents(
60
60
  for agents_dir in search_dirs:
61
61
  if not agents_dir.is_dir():
62
62
  continue
63
- for yaml_file in sorted(agents_dir.glob("*.yaml")):
63
+ # Recursive rglob picks up sub-squad subdirectories (e.g.
64
+ # departments/brand/agents/design-ops/*.yaml) per the v2.27.0
65
+ # Sub-Squad pattern. Sorted output keeps load order stable.
66
+ for yaml_file in sorted(agents_dir.rglob("*.yaml")):
64
67
  try:
65
68
  agent = load_agent(yaml_file)
66
69
  agents.append(agent)
@@ -273,6 +273,35 @@ class Agent(BaseModel):
273
273
  description="Claude model override for dispatch. Falls back to tier default when None.",
274
274
  )
275
275
 
276
+ parent_squad: Optional[str] = Field(
277
+ default=None,
278
+ description=(
279
+ "Slug of the parent squad when this agent belongs to a sub-squad. "
280
+ "Sub-squads are operational specialisations inside a department "
281
+ "(e.g. brand → design-ops). Optional and backwards-compatible: "
282
+ "agents without a parent_squad belong directly to their department."
283
+ ),
284
+ )
285
+
286
+ sub_squad_role: Optional[str] = Field(
287
+ default=None,
288
+ description=(
289
+ "Role within the sub-squad when parent_squad is set "
290
+ "(e.g. 'lead', 'extraction-script-writer', 'wcag-auditor'). "
291
+ "Inspired by the AIOX Squad → Sub-Squad pattern (KB note "
292
+ "AIOX Squads, April 30 2026 live)."
293
+ ),
294
+ )
295
+
296
+ @model_validator(mode="after")
297
+ def validate_sub_squad_coherence(self) -> "Agent":
298
+ """sub_squad_role only makes sense when parent_squad is set."""
299
+ if self.sub_squad_role and not self.parent_squad:
300
+ raise ValueError(
301
+ "sub_squad_role requires parent_squad to be set"
302
+ )
303
+ return self
304
+
276
305
  @model_validator(mode="after")
277
306
  def auto_fill_memory_path(self) -> "Agent":
278
307
  if not self.memory_path:
@@ -7,13 +7,20 @@ from datetime import datetime, timezone
7
7
 
8
8
  from core.cognition.capture.store import CaptureStore
9
9
  from core.cognition.memory.schemas import RawCapture
10
+ from core.runtime.path_resolver import ProfileMissingError, project_root_regex
11
+
12
+ _FALLBACK_REGEX = re.compile(
13
+ r"((?:/Users|/home)/\S+/(?:Herd|Work|AIProjects|code|repos))[/\\]([^\s/\\]+)"
14
+ )
10
15
 
11
16
 
12
17
  def _detect_project(digest: str) -> tuple[str, str]:
13
18
  """Try to detect project name and path from digest content."""
14
- path_match = re.search(
15
- r"(/Users/\S+/(?:Herd|Work|AIProjects)/([^\s/]+))", digest
16
- )
19
+ try:
20
+ regex = project_root_regex()
21
+ except ProfileMissingError:
22
+ regex = _FALLBACK_REGEX
23
+ path_match = regex.search(digest)
17
24
  if path_match:
18
25
  return path_match.group(2).rstrip("/"), path_match.group(1).rstrip("/")
19
26
  return "unknown", os.getcwd()