arkaos 4.8.0 → 4.10.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 (46) hide show
  1. package/VERSION +1 -1
  2. package/arka/skills/research/SKILL.md +6 -6
  3. package/bin/arka +5 -1
  4. package/bin/arkaos +2 -2
  5. package/config/disc-team-validator.sh +7 -7
  6. package/config/evals/dev.yaml +28 -0
  7. package/config/evals/finance.yaml +28 -0
  8. package/config/evals/kb.yaml +26 -0
  9. package/config/evals/marketing.yaml +28 -0
  10. package/config/evals/strategy.yaml +26 -0
  11. package/core/agents/__pycache__/registry_gen.cpython-313.pyc +0 -0
  12. package/core/agents/registry_gen.py +6 -4
  13. package/core/evals/__init__.py +19 -0
  14. package/core/evals/__pycache__/__init__.cpython-313.pyc +0 -0
  15. package/core/evals/__pycache__/schema.cpython-313.pyc +0 -0
  16. package/core/evals/__pycache__/verdict_labels.cpython-313.pyc +0 -0
  17. package/core/evals/schema.py +54 -0
  18. package/core/evals/verdict_labels.py +72 -0
  19. package/core/registry/__pycache__/__init__.cpython-312.pyc +0 -0
  20. package/core/registry/__pycache__/generator.cpython-312.pyc +0 -0
  21. package/core/registry/__pycache__/generator.cpython-313.pyc +0 -0
  22. package/core/registry/generator.py +138 -110
  23. package/core/runtime/__pycache__/llm_cost_telemetry.cpython-313.pyc +0 -0
  24. package/core/runtime/__pycache__/llm_cost_telemetry.cpython-314.pyc +0 -0
  25. package/core/runtime/llm_cost_telemetry.py +13 -1
  26. package/core/synapse/__pycache__/engine.cpython-313.pyc +0 -0
  27. package/core/synapse/__pycache__/engine.cpython-314.pyc +0 -0
  28. package/core/synapse/__pycache__/layers.cpython-313.pyc +0 -0
  29. package/core/synapse/__pycache__/layers.cpython-314.pyc +0 -0
  30. package/core/synapse/engine.py +6 -0
  31. package/core/synapse/layers.py +17 -0
  32. package/departments/dev/skills/research/SKILL.md +3 -2
  33. package/departments/dev/skills/scaffold/SKILL.md +3 -3
  34. package/knowledge/commands-registry.json +4194 -2627
  35. package/knowledge/commands-registry.json.bak +4194 -2627
  36. package/package.json +1 -1
  37. package/pyproject.toml +1 -1
  38. package/scripts/__pycache__/dashboard-api.cpython-313.pyc +0 -0
  39. package/scripts/__pycache__/synapse-bridge.cpython-313.pyc +0 -0
  40. package/scripts/__pycache__/synapse-bridge.cpython-314.pyc +0 -0
  41. package/scripts/dashboard-api.py +2 -2
  42. package/scripts/synapse-bridge.py +1 -1
  43. package/scripts/tools/__pycache__/prompt_surface_benchmark.cpython-313.pyc +0 -0
  44. package/scripts/tools/prompt_surface_benchmark.py +144 -0
  45. package/knowledge/agents-registry.json +0 -254
  46. package/knowledge/commands-registry-v2.json +0 -3827
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.8.0
1
+ 4.10.0
@@ -6,13 +6,13 @@ description: >
6
6
  single cited report, and writes a Knowledge Base note to the Obsidian
7
7
  vault. KB-first: Obsidian is searched before any external call.
8
8
  TRIGGER: "/arka research", "pesquisa sobre", "investiga",
9
- "faz research", "research <topic>", "best practices for", "state of
10
- the art", "o que se sabe sobre" — general, market, tooling, or KB
11
- topics whose deliverable is a synthesised KB note.
9
+ "faz research", "research <topic>", "best practices for" non-code
10
+ topics, "state of the art", "o que se sabe sobre" — general, market,
11
+ tooling, or KB topics whose deliverable is a synthesised KB note.
12
12
  SKIP: dev-scoped technical research — library or framework evaluation,
13
- "que lib uso", "which library/framework"
14
- /dev research (Lucas) wins; planning a task — arka-forge wins (Forge
15
- plans, this skill informs).
13
+ "que lib uso", "which library/framework", best-practice questions
14
+ about implementation choices — dev/research (Lucas) wins; planning a
15
+ task arka-forge wins.
16
16
  allowed-tools: [Agent, Read, Write, mcp__obsidian__search_notes]
17
17
  ---
18
18
 
package/bin/arka CHANGED
@@ -137,7 +137,11 @@ case "${1:-}" in
137
137
  REGISTRY="$REPO_DIR/knowledge/commands-registry.json"
138
138
  case "${1:-}" in
139
139
  rebuild)
140
- bash "$REPO_DIR/bin/arka-registry-gen"
140
+ # Shared resolver (venv-first) with plain python3 fallback —
141
+ # the generator is stdlib-only.
142
+ _ARKA_LIB="$REPO_DIR/config/hooks/_lib/arka_python.sh"
143
+ if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
144
+ (cd "$REPO_DIR" && "$ARKA_PY" -m core.registry.generator)
141
145
  echo "Registry rebuilt: $(jq '._meta.total_commands' "$REGISTRY") commands."
142
146
  ;;
143
147
  --json)
package/bin/arkaos CHANGED
@@ -65,8 +65,8 @@ case "${1:-}" in
65
65
  agents=$(jq -r '._meta.total_agents // 0' "$REPO_ROOT/knowledge/agents-registry-v2.json")
66
66
  echo " Agents: ${agents}"
67
67
  fi
68
- if [ -n "$REPO_ROOT" ] && [ -f "$REPO_ROOT/knowledge/commands-registry-v2.json" ] && command -v jq &>/dev/null; then
69
- commands=$(jq -r '._meta.total_commands // 0' "$REPO_ROOT/knowledge/commands-registry-v2.json")
68
+ if [ -n "$REPO_ROOT" ] && [ -f "$REPO_ROOT/knowledge/commands-registry.json" ] && command -v jq &>/dev/null; then
69
+ commands=$(jq -r '._meta.total_commands // 0' "$REPO_ROOT/knowledge/commands-registry.json")
70
70
  echo " Commands: ${commands}"
71
71
  fi
72
72
  echo ""
@@ -1,26 +1,26 @@
1
1
  #!/usr/bin/env bash
2
2
  # ============================================================================
3
3
  # ARKA OS — DISC Team Balance Validator
4
- # Reads agents-registry.json and validates team DISC distribution
4
+ # Reads agents-registry-v2.json and validates team DISC distribution
5
5
  # ============================================================================
6
6
  set -e
7
7
 
8
8
  ARKA_OS="${ARKA_OS:-$HOME/.claude/skills/arka}"
9
9
  REPO_DIR="${REPO_DIR:-$(cat "$ARKA_OS/.repo-path" 2>/dev/null || echo "")}"
10
- REGISTRY="${REGISTRY:-$REPO_DIR/knowledge/agents-registry.json}"
10
+ REGISTRY="${REGISTRY:-$REPO_DIR/knowledge/agents-registry-v2.json}"
11
11
 
12
12
  if [ ! -f "$REGISTRY" ]; then
13
- echo "Error: agents-registry.json not found at $REGISTRY"
13
+ echo "Error: agents-registry-v2.json not found at $REGISTRY"
14
14
  exit 1
15
15
  fi
16
16
 
17
17
  command -v jq &>/dev/null || { echo "Error: jq is required."; exit 1; }
18
18
 
19
19
  # Read counts from registry
20
- D_COUNT=$(jq '.team_composition.by_disc_primary.D' "$REGISTRY")
21
- I_COUNT=$(jq '.team_composition.by_disc_primary.I' "$REGISTRY")
22
- S_COUNT=$(jq '.team_composition.by_disc_primary.S' "$REGISTRY")
23
- C_COUNT=$(jq '.team_composition.by_disc_primary.C' "$REGISTRY")
20
+ D_COUNT=$(jq '._meta.disc_distribution.D' "$REGISTRY")
21
+ I_COUNT=$(jq '._meta.disc_distribution.I' "$REGISTRY")
22
+ S_COUNT=$(jq '._meta.disc_distribution.S' "$REGISTRY")
23
+ C_COUNT=$(jq '._meta.disc_distribution.C' "$REGISTRY")
24
24
  TOTAL=$(( D_COUNT + I_COUNT + S_COUNT + C_COUNT ))
25
25
 
26
26
  # Calculate percentages
@@ -0,0 +1,28 @@
1
+ # Dev department reference eval tasks (seed set).
2
+ # Judged against expected_properties + QG verdict; see core/evals/schema.py.
3
+ - id: dev-feature-auth-endpoint
4
+ department: dev
5
+ prompt: >
6
+ Implementa um endpoint de autenticação por token (login + refresh)
7
+ num serviço Laravel existente, com testes.
8
+ expected_properties:
9
+ - FormRequest valida credenciais (nunca validação inline no controller)
10
+ - Lógica em Service/Repository, controller fino
11
+ - Feature tests cobrem sucesso, credenciais inválidas e refresh expirado
12
+ - Nenhum segredo hardcoded; usa config/env
13
+ rubric: >
14
+ Rejeitar se os testes não correram (exit code em registo) ou se o
15
+ fluxo de refresh não invalida o token antigo.
16
+ tags: [backend, laravel, security-adjacent]
17
+
18
+ - id: dev-refactor-n-plus-one
19
+ department: dev
20
+ prompt: >
21
+ Este listing de encomendas faz N+1 queries; corrige sem alterar o
22
+ contrato JSON da API.
23
+ expected_properties:
24
+ - Eager loading ou query única substitui o loop de queries
25
+ - Contrato de resposta byte-idêntico (teste de regressão prova-o)
26
+ - Query count coberto por teste (assertQueryCount ou equivalente)
27
+ rubric: Rejeitar qualquer alteração de schema de resposta.
28
+ tags: [backend, performance]
@@ -0,0 +1,28 @@
1
+ # Finance department reference eval tasks (seed set).
2
+ - id: fin-unit-economics-saas
3
+ department: finance
4
+ prompt: >
5
+ Calcula os unit economics de um SaaS com MRR 8000 EUR, 120 clientes,
6
+ churn mensal 3%, CAC 250 EUR e margem bruta 80%.
7
+ expected_properties:
8
+ - LTV derivado com fórmula explícita (ARPU, churn, margem)
9
+ - Rácio LTV/CAC calculado e interpretado contra o benchmark 3x
10
+ - Payback period em meses
11
+ - Aritmética verificável (números batem certo)
12
+ rubric: >
13
+ Rejeitar qualquer erro aritmético — o arkaos-not-yes-man aplica-se a
14
+ matemática impossível do próprio input.
15
+ tags: [unit-economics, saas]
16
+
17
+ - id: fin-cashflow-13-weeks
18
+ department: finance
19
+ prompt: >
20
+ Constrói um forecast de cash flow a 13 semanas para uma agência com
21
+ 3 clientes em retainer e folha salarial fixa.
22
+ expected_properties:
23
+ - Entradas por cliente com datas de recebimento realistas
24
+ - Saídas fixas e variáveis separadas
25
+ - Saldo semanal acumulado com semana crítica identificada
26
+ - Cenário pessimista (cliente atrasa 30 dias) incluído
27
+ rubric: Rejeitar forecast sem cenário de stress.
28
+ tags: [cashflow, forecast]
@@ -0,0 +1,26 @@
1
+ # Knowledge department reference eval tasks (seed set).
2
+ - id: kb-research-note-synthesis
3
+ department: kb
4
+ prompt: >
5
+ Pesquisa "estratégias de retry para APIs rate-limited" e produz uma
6
+ nota KB sintetizada com fontes.
7
+ expected_properties:
8
+ - KB consultada primeiro (citação [[wikilink]] ou gap declarado)
9
+ - Fontes externas citadas com claims atribuídos
10
+ - Nota com frontmatter YAML + wikilinks + estrutura Zettelkasten
11
+ - Síntese própria, não colagem de excertos
12
+ rubric: Rejeitar claims sem fonte ou nota sem ligações ao grafo.
13
+ tags: [research, zettelkasten]
14
+
15
+ - id: kb-moc-reorganize
16
+ department: kb
17
+ prompt: >
18
+ Organiza 15 notas soltas sobre "pricing" num MOC (Map of Content)
19
+ coerente no vault.
20
+ expected_properties:
21
+ - MOC com agrupamento temático justificado
22
+ - Todas as 15 notas ligadas (nenhuma órfã)
23
+ - Hierarquia máxima de 2 níveis
24
+ - Notas duplicadas identificadas para merge
25
+ rubric: Rejeitar agrupamento alfabético ou sem lógica temática.
26
+ tags: [moc, organization]
@@ -0,0 +1,28 @@
1
+ # Marketing department reference eval tasks (seed set).
2
+ - id: mkt-launch-campaign-plan
3
+ department: marketing
4
+ prompt: >
5
+ Desenha o plano de campanha de lançamento (4 semanas) para um
6
+ micro-SaaS B2B de gestão de inventário, orçamento 2000 EUR.
7
+ expected_properties:
8
+ - Estrutura AARRR explícita com métrica alvo por etapa
9
+ - Canais escolhidos justificados contra o ICP (não lista genérica)
10
+ - Orçamento alocado por canal soma 2000 EUR
11
+ - Calendário semanal com owners
12
+ rubric: >
13
+ Rejeitar clichés de AI copy e canais sem justificação de fit; o
14
+ framework citado tem de ser aplicado, não só nomeado.
15
+ tags: [gtm, aarrr, budget]
16
+
17
+ - id: mkt-seo-content-brief
18
+ department: marketing
19
+ prompt: >
20
+ Cria um brief SEO para um artigo pilar sobre "supplier sync para
21
+ Shopify" com intenção de pesquisa comercial.
22
+ expected_properties:
23
+ - Keyword primária + secundárias com intenção classificada
24
+ - Outline H2/H3 cobre as perguntas do SERP
25
+ - Internal links e CTA definidos
26
+ - Meta title/description dentro dos limites de caracteres
27
+ rubric: Rejeitar keyword stuffing ou outline sem lógica de funil.
28
+ tags: [seo, content]
@@ -0,0 +1,26 @@
1
+ # Strategy department reference eval tasks (seed set).
2
+ - id: strat-five-forces-entry
3
+ department: strategy
4
+ prompt: >
5
+ Avalia com Porter's Five Forces a entrada de um novo player no
6
+ mercado de ferramentas de orquestração de agentes AI.
7
+ expected_properties:
8
+ - As 5 forças analisadas com evidência específica do mercado, não genérica
9
+ - Intensidade classificada por força com justificação
10
+ - Conclusão acionável (entrar/não entrar/entrar com que moat)
11
+ rubric: >
12
+ Rejeitar análise que apenas define as forças sem as aplicar ao
13
+ mercado concreto.
14
+ tags: [porter, market-entry]
15
+
16
+ - id: strat-moat-audit
17
+ department: strategy
18
+ prompt: >
19
+ Audita os moats de um produto dev-tools open-source com dashboard
20
+ pago, usando 7 Powers.
21
+ expected_properties:
22
+ - Cada power avaliada como presente/ausente/construível
23
+ - Pelo menos um trade-off identificado (ex. open-source vs counter-positioning)
24
+ - Recomendação priorizada de qual power investir primeiro
25
+ rubric: Rejeitar se citar 7 Powers sem mapear ao produto.
26
+ tags: [7-powers, moat]
@@ -1,7 +1,9 @@
1
- """Generate agents-registry.json from all agent YAML files.
1
+ """Generate agents-registry-v2.json from all agent YAML files.
2
2
 
3
- Scans departments/*/agents/*.yaml and produces a machine-readable
4
- registry with all agent metadata including behavioral DNA.
3
+ Scans departments/*/agents/*.yaml and produces the single canonical
4
+ machine-readable registry with all agent metadata including behavioral
5
+ DNA. The legacy knowledge/agents-registry.json (v1) was removed —
6
+ tests/python/test_registry_gen.py guards against its resurrection.
5
7
  """
6
8
 
7
9
  import json
@@ -12,7 +14,7 @@ from core.agents.loader import load_agent
12
14
 
13
15
 
14
16
  def generate_registry(departments_dir: str | Path, output_path: str | Path) -> dict:
15
- """Generate agents-registry.json from YAML agent files.
17
+ """Generate agents-registry-v2.json from YAML agent files.
16
18
 
17
19
  Args:
18
20
  departments_dir: Path to departments/ directory.
@@ -0,0 +1,19 @@
1
+ """Eval harness foundation (E2E audit v4.3.6 P2).
2
+
3
+ Reference eval tasks per department (config/evals/*.yaml) plus the
4
+ QG-verdict label log — the free labeled dataset every future eval run
5
+ or local-model distillation consumes.
6
+ """
7
+
8
+ from core.evals.schema import EvalTask, load_eval_tasks
9
+ from core.evals.verdict_labels import (
10
+ load_verdict_labels,
11
+ record_verdict_label,
12
+ )
13
+
14
+ __all__ = [
15
+ "EvalTask",
16
+ "load_eval_tasks",
17
+ "load_verdict_labels",
18
+ "record_verdict_label",
19
+ ]
@@ -0,0 +1,54 @@
1
+ """Eval task schema and loader.
2
+
3
+ Reference tasks live in ``config/evals/<department>.yaml`` — one YAML
4
+ list per department, versioned with the repo so evals evolve with the
5
+ agents they measure. See ADR 2026-07-09-evals-and-distillation.md.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pathlib import Path
11
+
12
+ import yaml
13
+ from pydantic import BaseModel, Field
14
+
15
+ DEFAULT_EVALS_DIR = (
16
+ Path(__file__).resolve().parent.parent.parent / "config" / "evals"
17
+ )
18
+
19
+
20
+ class EvalTask(BaseModel):
21
+ """One reference task an agent/department run is judged against."""
22
+
23
+ id: str = Field(pattern=r"^[a-z0-9][a-z0-9-]*$")
24
+ department: str
25
+ prompt: str = Field(min_length=10)
26
+ expected_properties: list[str] = Field(
27
+ min_length=1,
28
+ description="Verifiable properties the deliverable must exhibit",
29
+ )
30
+ rubric: str = Field(
31
+ default="",
32
+ description="Free-text judging guidance beyond the properties",
33
+ )
34
+ tags: list[str] = Field(default_factory=list)
35
+
36
+
37
+ def load_eval_tasks(evals_dir: Path | None = None) -> list[EvalTask]:
38
+ """Load every task from config/evals/*.yaml, validated.
39
+
40
+ Raises on schema violations or duplicate ids — a broken eval set
41
+ must fail loudly, not skew results silently.
42
+ """
43
+ base = evals_dir or DEFAULT_EVALS_DIR
44
+ tasks: list[EvalTask] = []
45
+ seen: set[str] = set()
46
+ for path in sorted(base.glob("*.yaml")):
47
+ raw = yaml.safe_load(path.read_text(encoding="utf-8")) or []
48
+ for item in raw:
49
+ task = EvalTask.model_validate(item)
50
+ if task.id in seen:
51
+ raise ValueError(f"duplicate eval task id: {task.id}")
52
+ seen.add(task.id)
53
+ tasks.append(task)
54
+ return tasks
@@ -0,0 +1,72 @@
1
+ """QG verdicts as free eval labels.
2
+
3
+ Every Quality Gate review already produces a structured ``QGVerdict``
4
+ (APPROVED/REJECTED + blockers + evidence summary). Persisting them turns
5
+ each review into a labeled example — the training/eval signal the E2E
6
+ audit called "labels gratuitos". Append-only JSONL, same conventions as
7
+ the other ``~/.arkaos/telemetry`` writers: never raises, fcntl advisory
8
+ lock via ``llm_cost_telemetry._locked_append`` (QG reviews run as
9
+ parallel subagents and verdict lines far exceed atomic-write sizes, so
10
+ unlocked appends could interleave and corrupt the label corpus),
11
+ ``ARKA_QG_LABELS_PATH`` override for tests.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import os
18
+ from datetime import datetime, timezone
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ from core.governance.qg_verdict import QGVerdict
23
+ from core.runtime.llm_cost_telemetry import _locked_append
24
+
25
+ DEFAULT_LABELS_PATH = (
26
+ Path.home() / ".arkaos" / "telemetry" / "qg-verdicts.jsonl"
27
+ )
28
+
29
+
30
+ def _labels_path() -> Path:
31
+ override = os.environ.get("ARKA_QG_LABELS_PATH", "").strip()
32
+ return Path(override) if override else DEFAULT_LABELS_PATH
33
+
34
+
35
+ def record_verdict_label(
36
+ verdict: QGVerdict,
37
+ deliverable: str = "",
38
+ department: str = "",
39
+ eval_task_id: str = "",
40
+ session_id: str = "",
41
+ ) -> None:
42
+ """Append one labeled QG example. Never raises (telemetry contract)."""
43
+ try:
44
+ entry: dict[str, Any] = {
45
+ "ts": datetime.now(timezone.utc).isoformat(),
46
+ "deliverable": str(deliverable or ""),
47
+ "department": str(department or ""),
48
+ "eval_task_id": str(eval_task_id or ""),
49
+ "session_id": str(session_id or ""),
50
+ **verdict.model_dump(),
51
+ }
52
+ with _locked_append(_labels_path()) as fh:
53
+ fh.write(json.dumps(entry, ensure_ascii=False) + "\n")
54
+ except Exception: # noqa: BLE001 — telemetry must never raise
55
+ return
56
+
57
+
58
+ def load_verdict_labels(path: Path | None = None) -> list[dict[str, Any]]:
59
+ """Read all labeled examples; malformed lines are skipped."""
60
+ target = path or _labels_path()
61
+ if not target.exists():
62
+ return []
63
+ out: list[dict[str, Any]] = []
64
+ for line in target.read_text(encoding="utf-8").splitlines():
65
+ line = line.strip()
66
+ if not line:
67
+ continue
68
+ try:
69
+ out.append(json.loads(line))
70
+ except json.JSONDecodeError:
71
+ continue
72
+ return out