@andespindola/crow-skills 0.10.1 → 0.11.1

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.
package/README.md CHANGED
@@ -2,10 +2,22 @@
2
2
 
3
3
  Skills com escopo explícito, conhecimento especializado preservado e fluxos comuns reutilizáveis.
4
4
 
5
- **Versão 0.10.1** ([mudanças](CHANGELOG.md)): o controle de recursos passa a tratar swap e CPU como eixos de pressão (swap quase cheio e carga alta reduzem agentes, jobs e workers; nenhuma recomendação cresce com a pressão), mostra a CPU% dos CLIs de agente, traz `crow-skills resources --exec-prefix` para rodar jobs pesados em prioridade baixa e as regras da crow-behaviour sob pressão (reduzir já, um job pesado por vez, não repetir verificação, validação ampla no CI); os hooks do Codex vão para o `config.toml` quando o `hooks.json` é symlink. A 0.10.0 trouxe o crow-broadcast, que compartilha, de forma passiva, o que cada sessão e cada CLI (Claude Code, Codex, Gemini CLI, Antigravity, Devin, inclusive dentro do Uniflow) está fazendo nesta máquina: repositório, clone, branch, execução crow em andamento e arquivos em edição; o prompt recebe um resumo só quando outra sessão viva está no mesmo repositório, editar um arquivo que outra sessão tocou ou trocar de branch num clone em uso gera aviso (ou bloqueio, se configurado), e `crow-skills broadcast claim` reserva áreas; a crow-behaviour consulta isso antes de planejar e reserva as áreas que delega ([crow-broadcast](docs/broadcast.md)). A 0.9.0 trouxe o controle de memória da máquina: `crow-skills resources` mede memória, pressão e os CLIs de agente em execução e recomenda quantos agentes, jobs pesados e workers rodar em paralelo; a crow-behaviour consulta essa recomendação antes de cada fan-out (sob `warn` reduz, sob `critical` segue sequencial), limita workers de builds e testes, reutiliza um dev server por projeto e encerra o que abriu, e 15 especialistas que sobem processos pesados ganharam a regra correspondente; o hook de prompt e as status lines só avisam quando a máquina está sob pressão. A 0.8.0 trouxe `crow-skills mode on|off`, que liga e desliga a crow-behaviour em todas as sessões e CLIs (Claude Code, Codex, Gemini CLI, Antigravity, Devin) a partir do próximo prompt, com `/crow on|off` dentro da sessão e o indicador `▸▸ crow on` na status line; a crow-behaviour mostra o progresso como a lista de agentes do host (`● main`, `○ dono atividade`); `crow-skills events` publica um barramento de eventos dos hooks para terminais; `crow-skills autoupdate on` atualiza o CLI e as skills gerenciadas todo dia e no login. A 0.7.1 trouxe as correções da revalidação no Codex às skills especialistas; a 0.7.0 tornou o Uniflow agente de instalação (`--agents uniflow`); a 0.6.1 passou a mostrar o progresso da crow-behaviour na própria conversa; a 0.6.0 trouxe as regras de entrega das 32 skills especialistas, a partir da [validação no Codex](docs/evaluations/2026-10-26-codex.md).
5
+ **Versão 0.11.1** ([mudanças](CHANGELOG.md)): o Codex deixa de mostrar em dobro as skills que o Uniflow já projeta em `~/.codex/skills`. A 0.11.0 trouxe `crow-skills setup --yes`, que configura de uma vez todos os CLIs de agente da máquina, e `crow-skills upgrade --yes`, que atualiza tudo numa só passada; os hooks que o crow-skills grava já saem habilitados (no Codex, aprovados pelo próprio `codex app-server`, só os do crow-skills; `--no-trust` desliga) e `status`/`doctor` mostram se cada CLI vai rodá-los; a ajuda ficou curta e organizada por tarefa. A 0.10.1 passou a tratar swap e CPU como eixos de pressão no controle de recursos (swap quase cheio e carga alta reduzem agentes, jobs e workers; nenhuma recomendação cresce com a pressão), mostrou a CPU% dos CLIs de agente, trouxe `crow-skills resources --exec-prefix` para rodar jobs pesados em prioridade baixa e as regras da crow-behaviour sob pressão (reduzir já, um job pesado por vez, não repetir verificação, validação ampla no CI); os hooks do Codex vão para o `config.toml` quando o `hooks.json` é symlink. A 0.10.0 trouxe o crow-broadcast, que compartilha, de forma passiva, o que cada sessão e cada CLI (Claude Code, Codex, Gemini CLI, Antigravity, Devin, inclusive dentro do Uniflow) está fazendo nesta máquina: repositório, clone, branch, execução crow em andamento e arquivos em edição; o prompt recebe um resumo só quando outra sessão viva está no mesmo repositório, editar um arquivo que outra sessão tocou ou trocar de branch num clone em uso gera aviso (ou bloqueio, se configurado), e `crow-skills broadcast claim` reserva áreas; a crow-behaviour consulta isso antes de planejar e reserva as áreas que delega ([crow-broadcast](docs/broadcast.md)). A 0.9.0 trouxe o controle de memória da máquina: `crow-skills resources` mede memória, pressão e os CLIs de agente em execução e recomenda quantos agentes, jobs pesados e workers rodar em paralelo; a crow-behaviour consulta essa recomendação antes de cada fan-out (sob `warn` reduz, sob `critical` segue sequencial), limita workers de builds e testes, reutiliza um dev server por projeto e encerra o que abriu, e 15 especialistas que sobem processos pesados ganharam a regra correspondente; o hook de prompt e as status lines só avisam quando a máquina está sob pressão. A 0.8.0 trouxe `crow-skills mode on|off`, que liga e desliga a crow-behaviour em todas as sessões e CLIs (Claude Code, Codex, Gemini CLI, Antigravity, Devin) a partir do próximo prompt, com `/crow on|off` dentro da sessão e o indicador `▸▸ crow on` na status line; a crow-behaviour mostra o progresso como a lista de agentes do host (`● main`, `○ dono atividade`); `crow-skills events` publica um barramento de eventos dos hooks para terminais; `crow-skills autoupdate on` atualiza o CLI e as skills gerenciadas todo dia e no login. A 0.7.1 trouxe as correções da revalidação no Codex às skills especialistas; a 0.7.0 tornou o Uniflow agente de instalação (`--agents uniflow`); a 0.6.1 passou a mostrar o progresso da crow-behaviour na própria conversa; a 0.6.0 trouxe as regras de entrega das 32 skills especialistas, a partir da [validação no Codex](docs/evaluations/2026-10-26-codex.md).
6
6
 
7
7
  **Reconstrução em andamento.** A primeira versão com 32 contratos genéricos não atende à preservação de capacidades solicitada. Não use esse número nem o mapeamento por categoria como prova de substituição das originais. A revisão passa a abranger cada definição e seus recursos, modos e dependências, sem número fixo de skills ou limite artificial de linhas. Veja [critérios e progresso](docs/reconstruction.md).
8
8
 
9
+ ## Começar
10
+
11
+ Uma linha configura todos os CLIs de agente da máquina (Claude Code, Codex, Gemini CLI, Antigravity, Devin, Uniflow e o segmento do tmux):
12
+
13
+ ```sh
14
+ brew install andersonflima/tap/crow-skills && crow-skills setup --yes
15
+ # ou, com npm:
16
+ npm install -g @andespindola/crow-skills && crow-skills setup --yes
17
+ ```
18
+
19
+ `setup` detecta cada CLI (binário no PATH ou diretório de configuração), instala todas as skills, o guia, as integrações e os hooks do modo crow já habilitados, liga o modo crow e o autoupdate, e termina com uma tabela por CLI e o doctor. `crow-skills setup --dry-run` mostra o plano sem gravar nada; rodar de novo só corrige o que mudou. Para atualizar tudo depois: `crow-skills upgrade --yes`. `crow-skills` sozinho mostra a ajuda curta e o estado atual; `crow-skills help <comando>` detalha cada comando. Detalhes em [setup, upgrade e ajuda](docs/cli.md#configurar-a-máquina-setup).
20
+
9
21
  ## Uso
10
22
 
11
23
  1. Escolha pela intenção, estado do projeto, stack e risco. Leia a descrição antes do corpo.
@@ -30,10 +42,12 @@ Exemplos:
30
42
  O pacote de cada skill é somente sua pasta em `skills/`. O [CLI crow-skills](docs/cli.md) instala cópias completas e versionadas em agentes/escopos explícitos, com preview, saída JSON, detecção de conflitos e recuperação. Requer Python 3.10+; Git para fontes em clone, Node 18+ para o launcher npm; mutações em macOS/Linux. A distribuição npm privada `@andespindola/crow-skills` inclui um snapshot completo das skills, sem clone ou hooks que as instalem automaticamente. No [Uniflow](docs/cli.md#uniflow), `--agents uniflow --global` grava as skills no store dele (`~/.config/uniflow/skills`), sem tocar no resto da configuração. Em `--global`, instalar a crow-behaviour também grava o guia aditivo do agente (claude, codex, gemini, devin) para usar as skills; `--no-guide` desliga. As integrações de interface (status lines do Claude Code, do Codex e do Antigravity, hooks do modo crow em cada CLI, comando `/crow`, segmento tmux) seguem o mesmo fluxo, preservando a configuração existente; `--no-integrations` desliga. O [barramento de eventos](docs/events.md) e a atualização automática (`crow-skills autoupdate on`) estão no [CLI](docs/cli.md).
31
43
 
32
44
  ```sh
33
- npm install -g @andespindola/crow-skills@0.10.1
45
+ npm install -g @andespindola/crow-skills@0.11.1
34
46
  crow-skills mode
35
47
  crow-skills progress
36
48
  ./bin/crow-skills list
49
+ ./bin/crow-skills groups
50
+ ./bin/crow-skills install --group essencial --agents claude,codex --global --dry-run
37
51
  ./bin/crow-skills install crow-behaviour --agents claude,codex --global --dry-run
38
52
  ./bin/crow-skills install crow-behaviour --agents claude,codex --global --yes --json
39
53
  ./bin/crow-skills related crow-backend --agents claude --global
package/catalog.json CHANGED
@@ -8,6 +8,30 @@
8
8
  }
9
9
  ]
10
10
  },
11
+ "groups": [
12
+ {"name": "essencial", "title": "Essencial", "description": "Coordenação e o que serve a quase todo projeto: arquitetura, especificação, depuração, testes e revisão de segurança",
13
+ "skills": ["crow-behaviour", "crow-architecture", "crow-spec", "crow-debug", "crow-qa", "crow-security-review"]},
14
+ {"name": "web", "title": "Web", "description": "Interfaces web: direção visual, implementação, acessibilidade, navegador e SEO",
15
+ "skills": ["crow-frontend", "crow-interface", "crow-design", "crow-accessibility", "crow-browser", "crow-seo"]},
16
+ {"name": "backend", "title": "Backend", "description": "Serviços, APIs, dados e domínio",
17
+ "skills": ["crow-backend", "crow-api-test", "crow-postgres", "crow-domain", "crow-architecture"]},
18
+ {"name": "qualidade", "title": "Qualidade", "description": "Testes, defeitos, desempenho e observabilidade",
19
+ "skills": ["crow-qa", "crow-debug", "crow-performance", "crow-observe"]},
20
+ {"name": "seguranca", "title": "Segurança", "description": "Revisão, varredura, prova, modelagem de ameaças, credenciais e apps com LLM",
21
+ "skills": ["crow-security-review", "crow-security-scan", "crow-security-test", "crow-threat-model", "crow-secrets", "crow-agent-security"]},
22
+ {"name": "infra", "title": "Infra e entrega", "description": "Infraestrutura, release e coordenação de plataforma",
23
+ "skills": ["crow-infra", "crow-release", "crow-platform"]},
24
+ {"name": "mobile", "title": "Mobile", "description": "Apps nativos e mobile",
25
+ "skills": ["crow-native-mobile"]},
26
+ {"name": "produto", "title": "Produto", "description": "Descoberta, especificação, crescimento, liderança e coordenação de plataforma",
27
+ "skills": ["crow-discovery", "crow-spec", "crow-growth", "crow-product-leadership", "crow-platform"]},
28
+ {"name": "midia-docs", "title": "Mídia e documentos", "description": "Mídia, documentos, planilhas e apresentações",
29
+ "skills": ["crow-media", "crow-documents"]},
30
+ {"name": "reverse", "title": "Engenharia reversa", "description": "Análise de código, binário ou protocolo",
31
+ "skills": ["crow-reverse"]},
32
+ {"name": "autoria", "title": "Autoria de skills", "description": "Criar ou revisar skills",
33
+ "skills": ["crow-skill-author"]}
34
+ ],
11
35
  "skills": [
12
36
  {
13
37
  "name": "crow-behaviour",
@@ -1,3 +1,3 @@
1
1
  """Portable, local-first installer for the crow-skills catalogue."""
2
2
 
3
- __version__ = "0.10.1"
3
+ __version__ = "0.11.1"
@@ -13,6 +13,10 @@ Results go to ~/.local/state/crow-skills/autoupdate/state.json (last run and
13
13
  a short history), shown by ``autoupdate status``, ``doctor`` and
14
14
  ``events snapshot``. Command output of brew/npm/git is never stored or
15
15
  printed: only exit codes and versions.
16
+
17
+ ``crow-skills upgrade`` is the same run started by hand (``trigger:
18
+ "upgrade"``); both go through :func:`run`, and ``--dry-run`` of either goes
19
+ through :func:`preview`, which runs nothing and writes nothing.
16
20
  """
17
21
  from datetime import datetime, timezone
18
22
  import json
@@ -289,8 +293,76 @@ def self_upgrade(install, git_pull):
289
293
  return {"kind": "unknown", "result": "skipped", "reason": "instalação não reconhecida (brew, npm ou checkout git)"}
290
294
 
291
295
 
292
- def skills_update(home):
293
- """update --global for every agent with managed installs; modified skills are kept and reported."""
296
+ def preview_self(install, git_pull):
297
+ """What the self step would do, without running brew/npm/git."""
298
+ if install["kind"] in ("brew", "npm"):
299
+ return {"kind": install["kind"], "result": "would_run", "command": list(install["upgrade"]), "before": __version__}
300
+ if install["kind"] == "git":
301
+ if not git_pull:
302
+ return {"kind": "git", "result": "skipped", "reason": "checkout git: atualize com git pull, ou use --git-pull"}
303
+ return {"kind": "git", "result": "would_run", "command": ["git", "-C", install["root"], "pull", "--ff-only"],
304
+ "before": __version__, "note": "só se o checkout estiver limpo em main/master"}
305
+ return {"kind": "unknown", "result": "skipped", "reason": "instalação não reconhecida (brew, npm ou checkout git)"}
306
+
307
+
308
+ def broken_projections(agent, home, store, rows):
309
+ """Uniflow links of this CLI whose store entry was edited or lost files: the CLI may not load them, so
310
+ upgrade reports them as needing the user (same as setup), with the command that restores the store."""
311
+ from .guide import broken_fix, store_broken
312
+ names = set()
313
+ if any(r["status"] == "uniflow_link" for r in rows):
314
+ bad = store_broken(home, store)
315
+ names |= {r["name"] for r in rows if r["status"] == "uniflow_link" and r["name"] in bad}
316
+ if agent == "codex":
317
+ from . import projection
318
+ names |= {n for n, kind in projection.links(home, store).items() if kind == "modified"}
319
+ return [{"name": n, "status": "uniflow_link_modified", "fix": broken_fix(n)} for n in sorted(names)]
320
+
321
+
322
+ def reinstall_behaviour(home, entry, dry_run, trust):
323
+ """Codex without a working crow-behaviour (its projection is broken, no native copy): install it natively,
324
+ as setup does, so the guide and hooks keep a coordinator to point to."""
325
+ from .cli import parser, run as cli_run
326
+ argv = ["install", "crow-behaviour", "--agents", "codex", "--global", "--json", "--home", str(home),
327
+ "--dry-run" if dry_run else "--yes"]
328
+ if not trust:
329
+ argv.append("--no-trust")
330
+ data = cli_run(parser().parse_args(argv))
331
+ if any(c["name"] == "crow-behaviour" and c["action"] != "unchanged" for c in data["changes"]):
332
+ entry["updated"].append("crow-behaviour")
333
+ entry["transaction"] = data.get("transaction")
334
+
335
+
336
+ def codex_duplicates(home, store, entry, names, dry_run):
337
+ """Codex sees Uniflow's links in ~/.codex/skills: those names are not updated natively, and intact managed
338
+ native copies of them are removed through uninstall (backup, transaction). Returns the names to update."""
339
+ from . import projection
340
+ from .cli import parser, run as cli_run
341
+ seen = projection.projected("codex", home, store)
342
+ if not seen:
343
+ return names
344
+ dupes = projection.duplicates(home, store)
345
+ entry["via_uniflow"] = sorted(set(entry["via_uniflow"]) | seen)
346
+ entry["kept"] = [k for k in entry["kept"] if k["name"] not in seen]
347
+ entry["kept"] += [{"name": n, "status": "duplicate_modified"} for n in dupes["modified"]]
348
+ entry["kept"] += [{"name": n, "status": "duplicate_shared"} for n in dupes["shared"]]
349
+ if dupes["remove"]:
350
+ argv = ["uninstall", *dupes["remove"], "--agents", "codex", "--global", "--json", "--home", str(home),
351
+ "--dry-run" if dry_run else "--yes", "--no-integrations"]
352
+ try:
353
+ data = cli_run(parser().parse_args(argv))
354
+ entry["removed"] = [{"name": c["name"], "reason": "removida: duplicava a projeção do Uniflow"}
355
+ for c in data["changes"] if c["action"] != "unchanged"]
356
+ entry["removal_transaction"] = data.get("transaction")
357
+ except CrowError as exc:
358
+ entry["error"] = {"code": exc.code, "message": str(exc)}
359
+ return [n for n in names if n not in seen]
360
+
361
+
362
+ def skills_update(home, trust=True, dry_run=False):
363
+ """update --global for every agent with managed installs; modified skills are kept and reported.
364
+
365
+ dry_run: the same per-agent plan with update --dry-run; "updated" lists what would change."""
294
366
  from . import cli
295
367
  from .cli import parser, run as cli_run
296
368
  from .storage import Store
@@ -313,8 +385,33 @@ def skills_update(home):
313
385
  except (CrowError, OSError) as exc:
314
386
  results.append({"agent": agent, "error": {"code": getattr(exc, "code", "io_error"), "message": str(exc)}})
315
387
  continue
388
+ from .guide import store_managed
389
+ store_ok = store_managed(home, store) if any(r["status"] == "uniflow_link" for r in rows) else set()
390
+ projected = sorted(r["name"] for r in rows if r["status"] == "uniflow_link" and r["name"] in store_ok)
391
+ if agent == "codex":
392
+ from . import projection
393
+ projected = sorted(set(projected) | projection.projected("codex", home, store)) # ~/.codex/skills links
394
+ broken = broken_projections(agent, home, store, rows)
316
395
  rows = [r for r in rows if r["name"] and r["revision"]]
317
396
  if not rows:
397
+ if projected or broken:
398
+ # Every crow skill here comes from Uniflow's store (updated as agent uniflow): only the guide,
399
+ # integrations and hooks of this CLI are refreshed.
400
+ from . import machine
401
+ entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": list(broken), "error": None,
402
+ "via_uniflow": projected}
403
+ if dry_run:
404
+ entry["dry_run"] = True
405
+ try:
406
+ if agent == "codex" and "crow-behaviour" in [k["name"] for k in broken]:
407
+ reinstall_behaviour(home, entry, dry_run, trust)
408
+ extras = machine.refresh_extras(agent, home, dry_run, trust)
409
+ entry["guides"] = (extras.get("guides") or {}).get("transaction")
410
+ except CrowError as exc:
411
+ entry["error"] = {"code": exc.code, "message": str(exc)}
412
+ except (OSError, ValueError, KeyError, TypeError):
413
+ entry["error"] = {"code": "io_error", "message": "Falha de leitura/gravação; nada concluído para este agente."}
414
+ results.append(entry)
318
415
  continue
319
416
  records = store.state(target["path"])["installed"]
320
417
  names, kept = [], []
@@ -325,10 +422,30 @@ def skills_update(home):
325
422
  kept.append({"name": r["name"], "status": "other_origin"}) # update --source or install switches it
326
423
  else:
327
424
  names.append(r["name"])
328
- entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": kept, "error": None}
425
+ entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": kept + list(broken),
426
+ "error": None, "via_uniflow": projected}
427
+ if dry_run:
428
+ entry["dry_run"] = True
429
+ if agent == "codex":
430
+ names = codex_duplicates(home, store, entry, names, dry_run)
431
+ if "crow-behaviour" in [k["name"] for k in broken] and "crow-behaviour" not in [r["name"] for r in rows]:
432
+ try:
433
+ reinstall_behaviour(home, entry, dry_run, trust)
434
+ except CrowError as exc:
435
+ entry["error"] = {"code": exc.code, "message": str(exc)}
436
+ if not names and not entry.get("error"):
437
+ from . import machine
438
+ try:
439
+ machine.refresh_extras(agent, home, dry_run, trust)
440
+ except CrowError as exc:
441
+ entry["error"] = {"code": exc.code, "message": str(exc)}
329
442
  if names:
330
443
  try:
331
- args = parser().parse_args(["update", *names, "--agents", agent, "--global", "--yes", "--json", "--home", str(home)])
444
+ argv = ["update", *names, "--agents", agent, "--global", "--dry-run" if dry_run else "--yes", "--json",
445
+ "--home", str(home)]
446
+ if not trust:
447
+ argv.append("--no-trust")
448
+ args = parser().parse_args(argv)
332
449
  data = cli_run(args)
333
450
  entry["updated"] = sorted({c["name"] for c in data["changes"] if c["action"] != "unchanged"})
334
451
  entry["unchanged"] = sum(c["action"] == "unchanged" for c in data["changes"])
@@ -342,7 +459,21 @@ def skills_update(home):
342
459
  return results
343
460
 
344
461
 
345
- def run(store, home, self_step=True, skills_step=True):
462
+ def preview(store, home, self_step=True, skills_step=True, trust=True, git_pull=None):
463
+ """Dry run shared by autoupdate run --dry-run and upgrade --dry-run: nothing runs, nothing is written."""
464
+ state = load_state(store)
465
+ install = detect()
466
+ result = {"install": install, "applied": False, "dry_run": True,
467
+ "would": ["atualizar o crow-skills" if self_step else None, "update --global das skills gerenciadas, por agente"]}
468
+ if self_step:
469
+ result["self"] = preview_self(install, state.get("git_pull") if git_pull is None else git_pull)
470
+ if skills_step:
471
+ result["skills"] = skills_update(home, trust=trust, dry_run=True)
472
+ return result
473
+
474
+
475
+ def run(store, home, self_step=True, skills_step=True, trust=True, git_pull=None, trigger="autoupdate"):
476
+ """One run (scheduled autoupdate or crow-skills upgrade): self-upgrade, then every agent's update."""
346
477
  try:
347
478
  import fcntl
348
479
  except ImportError as exc: # pragma: no cover
@@ -361,15 +492,18 @@ def run(store, home, self_step=True, skills_step=True):
361
492
  log.write_text("")
362
493
  state = load_state(store)
363
494
  install = detect()
364
- result = {"startedAt": now(), "version": __version__, "install": {"kind": install["kind"]}}
495
+ result = {"startedAt": now(), "version": __version__, "install": {"kind": install["kind"]}, "trigger": trigger}
365
496
  handed_off = False
366
497
  if self_step:
367
- result["self"] = self_upgrade(install, state.get("git_pull"))
498
+ result["self"] = self_upgrade(install, state.get("git_pull") if git_pull is None else git_pull)
368
499
  after = result["self"].get("after")
369
500
  if skills_step and after and after != __version__ and install["launcher"]:
370
501
  # The new version updates the skills (its own snapshot is the new source).
371
502
  try:
372
- done = subprocess.run([install["launcher"], "autoupdate", "run", "--skills-only", "--yes", "--json"],
503
+ child_args = [install["launcher"], "autoupdate", "run", "--skills-only", "--yes", "--json"]
504
+ if not trust:
505
+ child_args.append("--no-trust")
506
+ done = subprocess.run(child_args,
373
507
  capture_output=True, text=True, timeout=1200, stdin=subprocess.DEVNULL,
374
508
  env=dict(os.environ, CROW_SKILLS_AUTOUPDATE_CHILD="1"))
375
509
  child = json.loads(done.stdout)
@@ -380,7 +514,7 @@ def run(store, home, self_step=True, skills_step=True):
380
514
  result["handoff"] = {"version": after, "ok": False}
381
515
  handed_off = True
382
516
  if skills_step and not handed_off:
383
- result["skills"] = skills_update(home)
517
+ result["skills"] = skills_update(home, trust=trust)
384
518
  result["endedAt"] = now()
385
519
  result["ok"] = (result.get("self", {}).get("result") != "failed"
386
520
  and all(not s.get("error") for s in result.get("skills", []))
@@ -388,7 +522,7 @@ def run(store, home, self_step=True, skills_step=True):
388
522
  state = load_state(store)
389
523
  state["lastRun"] = result
390
524
  history = state.get("history") or []
391
- history.append({"startedAt": result["startedAt"], "ok": result["ok"],
525
+ history.append({"startedAt": result["startedAt"], "ok": result["ok"], "trigger": trigger,
392
526
  "updated": sum(len(s.get("updated") or []) for s in result.get("skills", [])),
393
527
  "self": (result.get("self") or {}).get("result")})
394
528
  state["history"] = history[-HISTORY:]