Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-23 03:20 UTC

AlexParamonov / pi-subagents-lite

TypeScriptMIT★ 14 estrellas⑂ 5 forksdesde may 2026Ver en GitHub ↗

AlexParamonov/pi-subagents-lite tiene un índice de salud de 39 sobre 100, lo que lo sitúa en la banda En riesgo. Su puntuación más alta es AI Readiness (55/100) y la más baja, Security (24/100). Se actualizó por última vez hoy. Una sola persona concentra la mayor parte del trabajo reciente.

39
global / 100
En riesgo

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

39
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

Titularidad

Alexander ParamonovCuenta personal
19 seguidores58 repositorios públicosdesde ago 2010

Este repositorio pertenece a una cuenta personal. Un proyecto con un único propietario conlleva más riesgo de continuidad que uno respaldado por una organización.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicaciónEtiquetas
npmpi-subagents-lite1.4.10212222hace 5 díaspi-packagepipi-agentpi-coding-agentpi-extensionsubagentsaiagents

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

36En riesgo · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 0 días
6.2/36Cadencia de commits — 9/52 semanas con commits
18/18Volumen de commits — 493 commits en el último año
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Datos de entrada utilizados
commits_last_year493
human_commit_share1
days_since_last_push0
active_weeks_last_year9
Cómo se puntúa
0/27Publica versiones — sin versiones publicadas
0/36Recencia de las versiones — sin versiones
0/27Cadencia de publicación — sin versiones
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count0
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

41En riesgo · 18% del índice global
Cómo se puntúa
18.1/60Estrellas — 14 estrellas
5/25Forks — 5 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks5
stars14
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (MIT)
0/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_license
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno
Cómo se puntúa
44.4/80Descargas mensuales — 2122 descargas/mes en npm
0/20Dependientes en el registro — no lo informa este ecosistema
Datos de entrada utilizados
packagespi-subagents-lite
dependents
ecosystemsnpm
total_downloads
monthly_downloads2122
Excluidos de la puntuación (sin datos o no aplicable): Dependientes en el registro. Los pesos restantes se han renormalizado.

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

47En riesgo · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
40.1/46.8Resolución de issues — 86% de issues cerradas
0/38.3Aceptación de PR — 0/1 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs0
open_issues1
closed_issues6
issue_closed_ratio0,857
closed_unmerged_prs1
Cómo se puntúa
10/30Respaldo de la propiedad — cuenta personal (usuario)
0/20Dominio verificado — no aplicable a cuentas de usuario
9.4/25Alcance del propietario — 19 seguidores de AlexParamonov
24.9/25Trayectoria — 58 repos públicos, cuenta de ~15 años
Datos de entrada utilizados
followers19
owner_typeUser
is_verified
owner_loginAlexParamonov
public_repos58
account_age_days5833
Excluidos de la puntuación (sin datos o no aplicable): Dominio verificado. Los pesos restantes se han renormalizado.
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en npm
35/35Recencia de publicación — última publicación hace 5 días
20/20Historial de versiones — 22 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagespi-subagents-lite
ecosystemsnpm
any_deprecatedno
min_days_since_publish5

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

44En riesgo · 20% del índice global
Cómo se puntúa
0/24Flujos de trabajo de CI
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — sin datos
Datos de entrada utilizados
has_cino
has_tests
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: CI-Tests. Los pesos restantes se han renormalizado.

Documentación

65Moderado
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
0/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepage
has_readme
has_docs_dir
has_descriptionno

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

24Crítico · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — sin datos
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
0/10Dangerous-Workflow — sin datos
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — sin datos
0/5Pinned-Dependencies — sin datos
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — sin datos
6/7.5Vulnerabilities — 2 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate2,4
Excluidos de la puntuación (sin datos o no aplicable): ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Los pesos restantes se han renormalizado.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

55Moderado · 0% del índice global
Cómo se puntúa
18/45Instrucciones para agentes — AGENTS.md (esbozo)
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 83 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,83
agent_instruction_filesAGENTS.md
agent_instruction_max_bytes195
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — tsconfig.json
0/10Entorno reproducible
0/10Práctica demostrada con agentes — ningún commit con autoría de agente entre los últimos 100
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — sin datos
Datos de entrada utilizados
has_nixno
has_tests
lockfiles
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configstsconfig.json
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Pinned-Dependencies. Los pesos restantes se han renormalizado.
Cómo se puntúa
45/45Código verificable por tipos — TypeScript (tipado estático)
54.4/55Tamaños de archivo manejables — 1/93 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageTypeScript
largest_source_bytes65.026
source_files_sampled93
oversized_source_files1

Datos clave

14estrellas de GitHub
1contribuidores
493commits en los últimos 12 meses
0días desde el último push
0versiones publicadas
1factor bus
1issues abiertas
npmecosistemas de paquetes

Advertencias de recopilación de datos

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • deps.dev does not index npm:pi-subagents-lite@1.4.10; advisories assessed against the repository dependency graph instead

Más detalle

Historial de estrellas y forks 0 ★ / 5 ⇿
0Estrellas
5Forks

Cuándo se añadió cada estrella y fork, recopilado de GitHub y agrupado por día. El crecimiento acumulado se sitúa justo encima de las adiciones diarias que lo componen, de modo que ambos se leen en conjunto: la acumulación orgánica sostenida no se parece en nada a un pico abrupto y efímero. Cuando esa diferencia es medible, se informa como autenticidad del crecimiento.

1223344422026-072026-072026-07
OpenSSF Scorecard 2.4 / 10
2.4agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).Scorecard v5.5.0 · 2026-07-23 03:20 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
n/dCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
n/dDangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
n/dPackagingpackaging workflow not detected
n/dPinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
n/dToken-PermissionsNo tokens found
8Vulnerabilities2 existing vulnerabilities detected
Dependencias directas 2
RegistroPaqueteRestricción de versiónManifiesto
npm@earendil-works/pi-agent-core^0.80.10package.json
npm@sinclair/typebox^0.34.49package.json
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1042,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "TypeScript": 917283
      },
      "pushed_at": "2026-07-23T02:06:16Z",
      "created_at": "2026-05-26T13:57:21Z",
      "owner_type": "User",
      "updated_at": "2026-07-23T02:06:21Z",
      "description": null,
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Alexander Paramonov",
      "type": "User",
      "login": "AlexParamonov",
      "company": null,
      "location": null,
      "followers": 19,
      "avatar_url": "https://avatars.githubusercontent.com/u/352030?v=4",
      "created_at": "2010-08-02T19:32:15Z",
      "is_verified": null,
      "public_repos": 58,
      "account_age_days": 5833
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [],
      "recent_commits": [
        {
          "oid": "5057ae195a4928628428c1ab1196c05f9a837b99",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'issue/package-name-extension-matching'",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T01:49:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fd73949a8b42efe36d2420e145d74633b77af514",
          "body": "…gent-runner\n\nThe cache guard `if (cached !== undefined) return cached` defeated\nnegative caching: storing undefined for not-found paths was an inert\ndead store, since a subsequent .get returns undefined either way and\nthe guard falls through to recompute. Caching the negative result\nhonors the issue's 'one readFileSync per extension path, cached'\nconstraint for the common no-package.json case across subagent runs.\n\nBehavior preserved: same return values; tests + typecheck green.",
          "is_bot": false,
          "headline": "refactor: cache negative package-name lookups via presence check in a…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T01:47:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2c3b52828b26598330ca960fae64b73eb49b8d2d",
          "body": "…runner\n\nextensionPackageName interleaved cache writes with the directory climb:\npackageNameCache.set(extPath, X); return X; appeared 4 times. Split into\na memoizing wrapper + resolvePackageShortName, the pure nearest-ancestor\nclimb. Dedupes the cache writes to one site and leaves the resolver's\ncontrol flow free of caching noise. Behavior unchanged: cache miss\ncomputes then stores, hit returns cached.",
          "is_bot": false,
          "headline": "refactor: separate memoization from package-name resolution in agent-…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T01:35:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "54b57f9b6d3742373242a921646196e00ee74fa3",
          "body": "…losures",
          "is_bot": false,
          "headline": "refactor: extract filterOverride to deduplicate whitelist/blacklist c…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T01:28:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "97a0d14604cdf3758a01ce928f07a6ec84ee2fea",
          "body": null,
          "is_bot": false,
          "headline": "refactor: drop `` ?? \"\" `` sentinel in filterExtensions match expression",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T01:27:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c1dd7605735eb220543375e2bce940030a1dc06",
          "body": "- Add test for package-name matching when extension is installed\n  inside node_modules (review feedback: untested boundary case)\n- Extract shared filter logic into filterExtensions() helper,\n  eliminating duplication between whitelist and blacklist branches\n- Fix subtle bug: || operator returns first truthy operand (not\n  boolean); coerce with !! to ensure correct comparison with invert\n  flag",
          "is_bot": false,
          "headline": "test(agents): add node_modules path coverage; refactor extension filter",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T01:18:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b2b4f1ddcaa6719e1ba8a09a418bfc9b97cfb135",
          "body": "- Fix cache bug: store undefined instead of empty string for not-found\n  entries (consistent return value across cache hits and misses)\n- Export buildExtOverride for direct unit testing (eliminates runAgent\n  indirection in tests)\n- Export resetPackageNameCache for test isolation\n- Rewrite package-n\n[…]\natching tests to use buildExtOverride directly\n  (removes ~300 lines of duplicated mock setup)\n- Add malformed package.json test (graceful degradation coverage)\n- Add cache consistency and reset tests",
          "is_bot": false,
          "headline": "fix: address code review for package-name extension matching",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T00:57:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1be86f9c151219061b75572e933d05d517ca0e48",
          "body": "- Use resolved path for directory climbing in extensionPackageName\n  (latent bug: relative paths would walk from wrong base)\n- Fix createPkgDir test helper for root-level entries (no subdirectory)\n- Add test for package root entry matching\n- Update issue to clarify case-insensitive matching is new behavior",
          "is_bot": false,
          "headline": "fix: address code review feedback",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T00:43:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0a14be5e3c707507cb214a00caca5d3a6af03915",
          "body": "When matching extension names in extensions/exclude_extensions frontmatter,\nalso match against the package's unscoped short name read from package.json.\nThis makes extensions: [\"pi-subagents\"] work for a package installed as\n@scope/pi-subagents, instead of only matching the directory-derived name.\n\n\n[…]\ntensions declares the entry\n- Case-insensitive matching for both path-derived and package names\n- Warnings when requested extension names don't match any loaded extension\n\nPort from pi-subagents #143.",
          "is_bot": false,
          "headline": "feat: match extensions by package name from package.json",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-23T00:32:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "13fe7c78cdf5231eb86b44c2209de89425518f85",
          "body": null,
          "is_bot": false,
          "headline": "Bump version",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-17T19:55:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7923e61e96da2e23a41475da5b457acab0fa9880",
          "body": "Import ThinkingLevel from @earendil-works/pi-ai instead of maintaining\na local union literal. Picks up max (and future levels) automatically.\n\nCloses #8",
          "is_bot": false,
          "headline": "Merge branch 'issue/import-thinking-level-from-pi-ai'",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-17T13:46:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b42ebb0e72ce34215fa18c25202ec2cb63e4ed80",
          "body": "…ing: max\n\n- Remove VALID_THINKING_LEVELS and parseThinkingLevel tests from\n  utils.test.ts — they test a one-liner array lookup, not behavior\n- Add behavior test in agent-types-discovery.test.ts: frontmatter\n  with thinking: max produces a valid agent config with thinkingLevel: max",
          "is_bot": false,
          "headline": "test: remove implementation-detail tests, add behavior test for think…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-17T13:32:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "15ba6b0da1268463845e97b1cf14480b68733633",
          "body": "…evels\n\nThe old tests checked array contents and exact counts — implementation\ndetails that break when new levels are added. Replace with tests that\nverify actual behavior:\n\n- parseThinkingLevel accepts max (the behavioral change this PR introduces)\n- parseThinkingLevel rejects invalid/unknown strings\n- parseThinkingLevel handles undefined input gracefully\n- parseThinkingLevel accepts all known standard levels (single test)\n- VALID_THINKING_LEVELS is non-empty and contains UI-required levels",
          "is_bot": false,
          "headline": "test: replace implementation tests with behavior tests for thinking l…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-17T13:30:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "604341a9132422a4fa0c7e3e7a9d15492a19b868",
          "body": "Replace hand-maintained ThinkingLevel union with ModelThinkingLevel\nimported from @earendil-works/pi-ai. This picks up new levels\n(eg max) automatically without manual sync.\n\n- src/types.ts: import ModelThinkingLevel, alias as ThinkingLevel\n- src/utils.ts: add 'max' to VALID_THINKING_LEVELS\n- test/utils.test.ts: add tests for VALID_THINKING_LEVELS and\n  parseThinkingLevel covering all levels including max",
          "is_bot": false,
          "headline": "refactor: import ThinkingLevel from @earendil-works/pi-ai",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-17T13:16:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33ed3d613341b72b68d169760b49654dae29c917",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump version to 1.4.9",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-17T12:53:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "990e0116f85b8378d3f96257243ff9e4790a5f21",
          "body": "pi 0.80.8 replaced CreateAgentSessionOptions.modelRegistry with\nmodelRuntime. The old option is silently ignored at runtime and\ncauses a type error against 0.80.8+ types.\n\ncreateAgentSession now creates its own ModelRuntime from auth.json\nand models.json. Extensions load in the subagent session and\nregister their providers before the first API call, so custom\nproviders continue to work.",
          "is_bot": false,
          "headline": "fix: remove deprecated modelRegistry from createAgentSession",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-17T12:52:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1981c803a2f4c135fabb4a40a692e50d5cd2513a",
          "body": null,
          "is_bot": false,
          "headline": "Version bump",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-11T16:51:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2cdee4d476312647058d03323328fb5418566d00",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'issue/background-agent-cleanup-fix'",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-09T00:18:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a1a910bb7ce246f31c86e746f1155f7f744f6106",
          "body": "cleanup() evicted any terminal record older than 10 minutes regardless of\nwhether the LLM had read the result. A background agent that completed before\nits nudge fired (LLM busy, session switched mid-execution) could be wiped\nbefore the result was delivered, the same result-loss bug class v0.10.4\nad\n[…]\nhe result, and when a background nudge successfully delivers\nthe full result to the LLM. A failed nudge delivery leaves the record\nunconsumed so cleanup keeps it around rather than wiping it silently.",
          "is_bot": false,
          "headline": "fix: preserve unconsumed agent records in cleanup timer",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-09T00:03:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9d4c1ccf3eb41bf19a6387aaf912c0b575e1b90b",
          "body": "- Group terms under subheadings (Core concepts, Configuration, Worktrees, Runtime)\n- Tighten definitions: remove implementation details, keep what-is\n- Remove Example dialogue and Flagged ambiguities sections (not glossary material)",
          "is_bot": false,
          "headline": "Migrate CONTEXT.md to grill skill format",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-08T23:40:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a660f90210cf495a18d934d1ee3e5f550dd6fc49",
          "body": null,
          "is_bot": false,
          "headline": "Cleanup",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-08T23:33:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7616e4dc3baf9a9249a278b95ff0cda93e6a4c3",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump version to 1.4.7",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T23:40:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "12d4f7c76df833ed174c2296ef80c0ae753e30a1",
          "body": "Both callers built (record.result ?? \"\") + getStatusNote(record.lifecycle)\ninline. The previous commit (3025e8a) had to re-sync these two after they\ndiverged on separator handling. Hoist to a shared helper next to\nbuildAgentDetails (same two callers, same record->display shape) so the\nnullish default and separator ownership live in one place.",
          "is_bot": false,
          "headline": "refactor: extract formatResultContent shared by nudge and tool result",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T23:37:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3025e8ac454b25ca1d59f3cfb8fdb594fd94a0b6",
          "body": "spawn-coordinator interpolated ${record.result ?? \"\"} ${getStatusNote()}\nwith a literal space between operand and getStatusNote(), but\ngetStatusNote() already owns the leading separator (its output starts\nwith \" (\" for a note). The extra space produced a double space when a\nnote existed and a trailing space when none did. tool-execution already\nused the clean \"+ statusNote\" form; normalize spawn-coordinator to\nmatch so both callers delegate the separator to getStatusNote.",
          "is_bot": false,
          "headline": "refactor: drop redundant separator in subagent-result content",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T23:27:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a5fb34cc83b6e4007eaa2a77083aa0621f3044fb",
          "body": "NOTES unioned real AgentStatus keys with synthetic tokens\n'stoppedByUser'/'stoppedByAgent' and modeled stop messages as Partial\neven though both StopInitiator values have one. Split into\nSTATUS_NOTES (Partial<Record<AgentStatus,string>>) and an exhaustive\nSTOP_NOTES (Record<StopInitiator,string>), and flatten the 3-level\nnested ternary via 'stoppedBy ?? \"agent\"'. Behavior unchanged.",
          "is_bot": false,
          "headline": "refactor: separate stop-initiator notes from status notes in status-note",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T23:17:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "169f1a0f03ef6af12cd55a6ccf105fc7b138912b",
          "body": "test/status-note.test.ts passed status: \"foo\" to getStatusNote, which is\nnot a valid AgentStatus after the NOTES type tightening in 862b4b5. It\nonly escaped because tsconfig excludes test/. Use status: \"completed\"\n(a noteless but valid status) and rename the case to match what it\nactually tests. Behaviour unchanged.",
          "is_bot": false,
          "headline": "refactor: use valid AgentStatus in status-note test",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T23:08:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "862b4b52c3d840e9c75f6e57249aa3f4864789e0",
          "body": "Record<string,string> claimed NOTES[lifecycle.status] always returned a\nstring, when it is undefined for queued/running/completed/error. The\ntruthy 'note ? ... : \"\"' check existed only because of that. Use\nPartial<Record<AgentStatus | stoppedBy-variants, string>> so the value\ntype is honestly string | undefined and property-access typos are caught\nat compile time. Behavior unchanged.",
          "is_bot": false,
          "headline": "refactor: tighten NOTES record type in status-note",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T23:00:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "07db848416248bd510a17d041807cd1075828697",
          "body": "The \"user\" | \"agent\" literal union was duplicated across\nAgentLifecycle.stoppedBy and the abort/stopAgent signatures. Give it\nan exported name so the concept has one source of truth and is named\nexplicitly rather than described only in prose.",
          "is_bot": false,
          "headline": "refactor: extract StopInitiator type for stop origin",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T22:54:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "626268d760b595f84dd5f742c5c600d378633f63",
          "body": "Compute the status note directly via property access instead of\nbuilding a synthetic noteKey (mixed real statuses + 'stoppedByUser'/\n'stoppedByAgent' strings) and indexing NOTES with it. Removes the\n'let' mutation and the 'as string' cast that existed only to let\nnon-status strings share a variable with AgentStatus.",
          "is_bot": false,
          "headline": "refactor: flatten getStatusNote note lookup in status-note",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T22:47:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1e75d1a5bba7f0359ad3a122bdedfb9dcd8a40a0",
          "body": "When the agent uses StopAgent to kill a stuck subagent, the nudge\nsaid 'STOPPED BY THE USER' causing the agent to think the human\nintervened and retry unnecessarily.\n\n- Add stoppedBy field to AgentLifecycle ('user' | 'agent')\n- UI menu passes 'user', StopAgent tool passes 'agent'\n- Status note: 'STOPPED BY THE USER' for user stops,\n  'stopped before completion' for agent stops\n- Include short agent ID in nudge header so the agent can\n  match the nudge to the specific subagent it stopped",
          "is_bot": false,
          "headline": "Distinguish user vs agent stops in StopAgent",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-07T22:33:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c7a80572dd53b01bbbaf952056ece435535ebc23",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump version to 1.4.6",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-07-01T21:27:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bf620bf6b96814ad6d2d3f42145cd154639f93ee",
          "body": null,
          "is_bot": false,
          "headline": "Add delta input tests",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T23:37:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "01866e31edc5c2bad3f2b5e1131c1aae475750b4",
          "body": "The setter no longer routes through setAgentVisibility and it isn't a\nwidget stats-visibility flag, so it doesn't belong in that union.",
          "is_bot": false,
          "headline": "refactor: remove deltaInputTokens from setAgentVisibility union",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T23:36:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "81c197334246fc70c32d8647a7b1d4e2696ccc6e",
          "body": "cacheRead was extracted in agent-runner, smuggled through an\nonAssistantUsage callback typed LifetimeUsage (which omits it),\nthen recovered by cast in agent-manager. Introduce AgentUsage type,\ntype the callback with it, and drop the cast and the dead\nUsageWithCacheRead alias.",
          "is_bot": false,
          "headline": "refactor: make cacheRead first-class via AgentUsage in usage tracking",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T23:35:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6194481af2a8aa05c760a1675b54181cc1fec0b4",
          "body": "Users explicitly enable this for vLLM. Default OFF avoids incorrect\ncounts for cloud providers that legitimately have cacheRead=0.",
          "is_bot": false,
          "headline": "config: change deltaInputTokens default to false (opt-in)",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T23:11:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1dbdc64a93be4f69795fcc9e727eebdb28f4ab18",
          "body": "Adds a toggle in Widget Settings > Usage Stats to enable/disable\nthe input token delta estimation for vLLM (which doesn't report\ncache hits). Default: ON.",
          "is_bot": false,
          "headline": "widget: add deltaInputTokens toggle setting",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T23:02:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0bfa330a02733ac7957e4cb5e3d3f98b4e92d53f",
          "body": "vLLM doesn't report prompt_tokens_details.cached_tokens, so usage.input\nis always the full prompt_tokens. Estimate new tokens as delta from\nprevious message's input when cacheRead is 0.\n\nCloud models with cacheRead still show actual input tokens.",
          "is_bot": false,
          "headline": "usage: show input token delta for vLLM (no cache reporting)",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T22:58:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7338f186008271bc7cecd805ea11d56ca921b86c",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 1.4.5",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T02:01:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e5828bf36fc43f59758331555e4b0f751f27eddb",
          "body": null,
          "is_bot": false,
          "headline": "Finally fixed nudge delivery",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T02:00:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e85741a267a40334f97d10dd3c95681cd0c4f923",
          "body": "Subagent bindCore calls overwrite the shared runtime's sendMessage\nhandler. When the nudge fires, pi.sendMessage routes to a subagent's\nsession instead of the parent's, causing silent delivery failure.\n\nFix: capture ExtensionContext at spawn time and use ctx.ui.notify()\nas fallback when sendMessage fails. Shows a toast notification\ninforming the user that the agent result is available.",
          "is_bot": false,
          "headline": "fix: fallback to UI notification when nudge delivery fails",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T00:27:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "974f157ce95493765edfe774e68523b2f445ee37",
          "body": "Subagent bindCore calls overwrite the shared ExtensionRuntime's\nsendMessage handler. When a background agent completes, pi.sendMessage\nroutes to a subagent's handler instead of the parent session's,\ncausing silent nudge failure.\n\nCapture ExtensionContext at spawn time. When sendMessage fails,\nfall back to ctx.ui.notify() using the captured context, which\nbypasses the corrupted shared runtime.",
          "is_bot": false,
          "headline": "fix: fallback to UI notification when nudge sendMessage fails",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-25T00:24:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c71604507ba62d61635b337c8736976b25072ac2",
          "body": null,
          "is_bot": false,
          "headline": "bump 1.4.3",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "74e4a5b2f4e5ff1195777ff6570e58389a224648",
          "body": null,
          "is_bot": false,
          "headline": "refactor: remove unused afterEach import in spawn-coordinator test",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e159cfedba215b9853915de3f0ee1ed9ebd73602",
          "body": "- scanAndMerge is internal to agent-types.ts, no external consumers\n- warnSpy in stale-pi test was set up and restored but never asserted\n  (assertions removed in earlier commit)",
          "is_bot": false,
          "headline": "refactor: unexport scanAndMerge, remove dead warnSpy from stale-pi test",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ff600f49a1672910183206b5616ba8c74ad983c0",
          "body": null,
          "is_bot": false,
          "headline": "docs: add pi-ai deliverAs lesson to lessons.md",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7e584da9dc7e8c39834d75d908d27168b5aa26b6",
          "body": "- Check parent session state via ctx.isIdle()\n- Use followUp when idle (waits for agent to finish)\n- Use steer when running (queues during current turn)\n- Fixes nudges not rendering after getPiInstance() refactor",
          "is_bot": false,
          "headline": "fix: use correct deliverAs mode for nudge messages",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "edd9d1fdc08f3b9d118eac9d55e30acd69312404",
          "body": null,
          "is_bot": false,
          "headline": "refactor: extract findActiveConfig helper in agent-types",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f1027fbecc42bcd79f2924bcabcab23dfe5e2a48",
          "body": "…estamp per block",
          "is_bot": false,
          "headline": "fix: remove newline flush trigger for thinking buffer, use single tim…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c0f0e998b1bcd7cd9f9e12add06b0e92fc6f3415",
          "body": "…estamps",
          "is_bot": false,
          "headline": "revert: restore splitAndPrefix for thinking content with per-line tim…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5dbdbddc5fc597edbc6f4db1feae316c45224a92",
          "body": "- Replace splitAndPrefix with inline template for thinking paths\n  (thinking is a continuous buffer, single timestamp per flush is sufficient)\n- Remove newline-triggered flush, only buffer size triggers flush now\n- Flatten redundant nested conditional in thinking_delta handler\n- Update test docstring and assertions to match new behavior",
          "is_bot": false,
          "headline": "refactor: simplify thinking buffer flush in output-file",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fa704b76e37d33c1b78fbabe3efad71a13290e66",
          "body": null,
          "is_bot": false,
          "headline": "docs: refactor-7 report",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "84a590ebb7efc2b6eefdfc9da1a511cf9775111d",
          "body": "- tool-execution.ts: replace AgentDetailsOptions interface with inline\n  type annotation on buildAgentDetails (2 booleans, single use site)\n- agent-discovery.ts: remove unused _filename parameter from parseAgentFile\n  and update all call sites",
          "is_bot": false,
          "headline": "refactor: inline AgentDetailsOptions and remove unused _filename param",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T18:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2791388a41ceaa04763ed7754b55005970885181",
          "body": "SpawnCoordinator captured pi at spawn time and used it for nudges\nfiring later via setTimeout. If the session was disposed between\nspawn and nudge (session replacement, reload, crash, context\noverflow), pi.sendMessage() threw a stale context error.\n\nFix: read pi from shell at nudge time (fresh after reload) and\nswallow stale context errors silently. The nudge simply doesn't\ndeliver when the session is gone, which is correct behavior.",
          "is_bot": false,
          "headline": "fix: suppress stale ctx error on background agent nudge",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T16:06:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b63344c62c255e5b40c63e623cd5860e6712ad8d",
          "body": null,
          "is_bot": false,
          "headline": "refactor: remove dead CUSTOM_PROMPT_PATH re-export from agent-runner",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:42:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0a62800af42e995185601b61cd69785baae42e7e",
          "body": "…NFIG export\n\nloadConfig now merges loaded values over defaults so callers always get\na complete SubagentsConfig. Removes DEFAULT_CONFIG export, DEFAULT_CONFIG\nfallbacks in ConfigStore getter, and local VALID_SYSTEM_PROMPT_MODES\n(moved to config-io.ts). Adds DEFAULT_CONCURRENCY for concurrency resets.",
          "is_bot": false,
          "headline": "refactor: merge config defaults into loadConfig, eliminate DEFAULT_CO…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:41:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6326971a781973540b45f97da5dc600d0446fb82",
          "body": "Comma was removed in the refactor but is needed as a fallback split\npoint when thinking text has no periods. Without it, the entire\nbuffer flushes at once instead of splitting at the nearest pause.",
          "is_bot": false,
          "headline": "fix: restore comma in sentence boundary detection",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:29:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b7f0607105c02e237f20aa09293c088ea7c84d6d",
          "body": "Eliminates 'any' in menu-model-settings, menu-concurrency, and\nmenu-running-agents. Adds Theme import where missing.",
          "is_bot": false,
          "headline": "refactor: replace remaining 'any' theme types with Theme",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:23:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d560d9545a33f60717aed8642d6ca7023a18249f",
          "body": "The IIFE existed only to scope the 'parts' variable. A simple if-block\nwith let achieves the same thing without the indirection.",
          "is_bot": false,
          "headline": "refactor: replace IIFE with block scope in applyOverflow",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:18:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e8d8cbc661ad28f509b3a44921c883974eb014ef",
          "body": "DONE line formatting was duplicated in streamToOutputFile cleanup and\nAgentOutputLog.finalize. Single helper now owns the format string.",
          "is_bot": false,
          "headline": "refactor: extract formatDoneLine helper in output-file",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:17:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9c67ff0853a545f2d8f5ac204aa673bbc8c08ffe",
          "body": "Eliminates duplicated parts-building logic in buildFinishedBlocks and\nbuildRunningBlocks. Both callers construct the same @worktreeLabel / tail -f\ncontinuation; now shared via a single helper.",
          "is_bot": false,
          "headline": "refactor: extract buildWorktreeOutputParts helper in agent-widget",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:16:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90928ac5480f847589025264071273041b0b6112",
          "body": "- Move CUSTOM_PROMPT_PATH from agent-runner to config-io (belongs with config paths)\n- Move GIT_EXEC_TIMEOUT_MS to utils.ts (shared by agent-runner and worktree-validator)\n- Merge formatTokens and formatTokensCompact into single function with compact flag\n- Move VALID_THINKING_LEVELS to utils.ts (re\n[…]\nt, menu-spawn-wizard\n- Remove unused 'ls' from TOOL_DISPLAY\n- Remove comma from sentence boundary detection (too aggressive for thinking buffer)\n- Update test mock to include CUSTOM_PROMPT_PATH export",
          "is_bot": false,
          "headline": "refactor: consolidate constants, merge formatTokens, eliminate any types",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-24T15:15:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "779e4ddbf5ebd6a98381dfee97263cea78181289",
          "body": "- Merge redundant sections (Agent Type Enforcement → Verification, 4 stale task lessons → Config & Refactoring Patterns)\n- Fix createNumericInputSubmenu → createNumericSubmenu (actual function name)\n- Fix section separators: SettingsList supports __sep__ items via SettingsListWrapper\n- Tighten prose throughout",
          "is_bot": false,
          "headline": "docs: compact lessons.md (108→60 lines, fix 3 inaccuracies)",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-23T23:46:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "efedb8a5beb91dabaffdb621712356fb6baca77b",
          "body": null,
          "is_bot": false,
          "headline": "docs: update README and bump to 1.4.2",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-23T23:27:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e68d5dc75cb02412611bbab97b0663b3910b60f9",
          "body": "Model type was never part of the deprecated old API — it's exported from\nthe root via types.ts re-export. No createModels() migration needed for\ntype-only usage.",
          "is_bot": false,
          "headline": "import Model from pi-ai root instead of /compat",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-23T18:56:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6a4bfb2891b557a280d26e5bbca31bf89f50548b",
          "body": "- Swap Model imports from @earendil-works/pi-ai to /compat\n- Bump peer deps to ^0.80.1 (old >=0.74.0 with semver 0.x pinned to 0.75.x)\n- Add @earendil-works/pi-agent-core ^0.80.1 as direct dep\n- Fresh lockfile resolves all packages to 0.80.1",
          "is_bot": false,
          "headline": "migrate to pi-ai compat entrypoint and bump @earendil-works to 0.80.1",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-23T18:47:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2baa9b7819e56107ee5d61fe4b827f2883573c09",
          "body": null,
          "is_bot": false,
          "headline": "docs: add fix-nudge-stale-pi lesson entry",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-22T22:35:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f1f90d2d364f0b5e9bcb2de2e82cab233149a931",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'issue/fix-nudge-stale-pi'",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-22T20:24:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7bc6759c0ad38cc3755213299bb6ad9e626f73c7",
          "body": "Remove getPiInstance() singleton call from emitIndividualNudge().\nInstead, store the ExtensionAPI passed to spawn() as an instance\nfield and refresh it on each call. This prevents stale pi references\nafter session lifecycle events (compaction, reload) that cause\nsilent nudge failures.\n\n- Add private\n[…]\n ExtensionAPI | null field, set in spawn()\n- Use this.pi in emitIndividualNudge() with null guard\n- Remove getPiInstance import from shell.js\n- Update tests to verify pi storage and null-skip behavior",
          "is_bot": false,
          "headline": "fix: store pi instance on SpawnCoordinator for fresh nudge delivery",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-22T20:18:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1f6e7234aa216bdb97dd1b1aafaf2183be62b6fc",
          "body": null,
          "is_bot": false,
          "headline": "split on new line as well",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-22T13:13:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "48d9de27b956974c5ffe1b17f4df0ca5e8293594",
          "body": "Instead of breaking mid-sentence when the buffer limit is reached,\nnow flushes up to the last sentence-ending punctuation (., !, ?).\n\nAlso removes 15 theater tests that only asserted on UI labels, values,\nand item ID existence without testing any behavior.",
          "is_bot": false,
          "headline": "feat: round thinking buffer flush to nearest sentence boundary",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-22T13:04:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c9620284608c488cc8fd12fd4a5ed73c733d008",
          "body": "…ssons entry",
          "is_bot": false,
          "headline": "rename thinking buffer label to 'Log file thinking buffer' and add le…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T21:53:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8caab7997754324cf3eac393cf1a7585f9deb00f",
          "body": "…t ambiguity\n\nThe type·id separator was ambiguous — LLMs couldn't tell where the ID\nstarted. Agent tried agentId, then type·agentId, then just agentId\nsuccessfully. id (type) makes the ID unambiguous by placing it first.\n\nAgentStatus format: shortId (type) status\nStopAgent list:    shortId (type), shortId (type)",
          "is_bot": false,
          "headline": "fix: flip agent display from type·id to id (type) to resolve StopAgen…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T21:52:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b48bdcb1f2edbcaa5e2d1b8e9017595346d2ddaf",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'issue/thinking-buffer-setting'",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:53:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a4e44ec9686bee057b27024c07aafc74b1ecfb62",
          "body": "Add outputThinkingBufferSize control to the widget settings menu.\nUser can select from OFF, 80, 200, 500, 1000 chars.\n\nChanges:\n- ConfigStore: add setOutputThinkingBufferSize mutation\n- Widget settings menu: add Thinking buffer ring toggle item\n- Mock setup: wire outputThinkingBufferSize through test store\n- Tests: coverage for config mutation and menu integration",
          "is_bot": false,
          "headline": "feat: add thinking buffer ring selector to widget settings",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:30:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f0a20398d7b5c218ac12a5b72df09359ee564dc9",
          "body": null,
          "is_bot": false,
          "headline": "fix: flush worktree validation warnings via ctx.ui.notify on failure",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:25:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0ba6cd88db577d356f56132a39e8b45931ecfe54",
          "body": null,
          "is_bot": false,
          "headline": "docs: add stale pi context lesson to lessons.md",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:24:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2565eafe026929ea5618a00e4de3ca13a6836288",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'issue/fix-stale-pi-context'",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:19:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fb02e28ae09276c2cfdb8b961dc6c457f1c769fc",
          "body": "Remove cached pi reference from SpawnCoordinator which could become stale\nafter session replacement/reload, causing uncaught exceptions when the\nnudge timer fires.\n\n- Remove this.pi field and pi parameter from constructor\n- Resolve pi via getPiInstance() at nudge emission time\n- Add disposed flag to skip nudge emission after dispose\n- Wrap sendMessage in try-catch as defense-in-depth\n- Update caller in events.ts",
          "is_bot": false,
          "headline": "fix: resolve stale pi crash in SpawnCoordinator nudge emission",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:19:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7de96d164c6f2a52ba93f8adffcd4845d70cc2b9",
          "body": "Remove cached pi reference from SpawnCoordinator which could become stale\nafter session replacement/reload, causing uncaught exceptions when the\nnudge timer fires.\n\n- Remove this.pi field and pi parameter from constructor\n- Resolve pi via getPiInstance() at nudge emission time\n- Add disposed flag to skip nudge emission after dispose\n- Wrap sendMessage in try-catch as defense-in-depth\n- Update caller in events.ts",
          "is_bot": false,
          "headline": "fix: resolve stale pi crash in SpawnCoordinator nudge emission",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:14:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "30178b20f345c3f860e88e867ef5e64d5bb29025",
          "body": "- Change error returned to LLM from vague 'git error: {msg}' to\n  'git rev-parse failed: {msg}' so the LLM knows which command failed\n- Add test that validates onWarning callback is invoked and warnings\n  are flushed via ctx.ui.notify on validation failure",
          "is_bot": false,
          "headline": "refactor: improve git error message and add warning flush test",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T20:11:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "70ed9603a261862964c28ec2517b653ccbc03c68",
          "body": null,
          "is_bot": false,
          "headline": "Fix tool tooltip",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T19:41:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1feb2077b5cfa441853a79a8617c9b7ab3ef272f",
          "body": "thinking_start/delta/end are mutually exclusive assistantMessageEvent\ntypes. Chain them with else-if so the mutual exclusivity is explicit\ninstead of a standalone if followed by a separate if/else-if.",
          "is_bot": false,
          "headline": "refactor: chain thinking event branches with else-if in output-file.ts",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T19:37:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f73cff2ab0ded3611d6ed1e20b939cb8a0c9090c",
          "body": "The old name implied errors. The new name reveals intent: it counts\nthinking blocks already written to the live stream, and is passed as\nthe skip count so the final turn_end flush does not re-emit them.",
          "is_bot": false,
          "headline": "refactor: rename streamedExceptionCount to streamedThinkingBlocks",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T19:36:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "72a13bfe5833b2199b8b002411d19d4776970bd6",
          "body": "When thinking deltas accumulated below the buffer threshold and\nthinking_end arrived with the full block content, flushThinkingBuffer\nwrote the buffered tail but streamedThinkingChars was not updated.\nThe subsequent content.slice(streamedThinkingChars) then re-streamed\nfrom 0, duplicating the whole \n[…]\nength check and the duplicated accounting in\nthe delta path.\n\nThe existing 'flushes buffer on thinking_end' test hid the bug by using\nmismatched delta/end content; align the content and assert no dup.",
          "is_bot": false,
          "headline": "fix: duplicate thinking content when buffer flushes on thinking_end",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T19:35:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b322f645604dc3e3ca0967f2e49aa4b23c08f3ed",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'issue/stream-thinking-to-output'",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T14:50:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f8792e5a2c6f8f6b487e54400e5c3f4a0d1926d9",
          "body": "flushThinkingBuffer and the thinking_end handler wrote content as a\nsingle line without splitting on newlines. Multi-line thinking content\nwould produce lines missing the [THINKING] prefix, violating the\nline-based format required for tail -f compatibility.\n\nUse the existing splitAndPrefix function which handles this correctly.\nAlso adds timestamps to each line of multi-line content, improving\nlog readability.",
          "is_bot": false,
          "headline": "refactor: use splitAndPrefix for thinking buffer flush in output-file.ts",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T14:42:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d9198f21d2cacaf14a06396c03f4fcd13a7c8c6b",
          "body": "…ines when thinking_end never fires\n\n- Track thinking block state with thinkingBlockInProgress flag\n- Set flag true on thinking_start, false on thinking_end\n- At turn_end, if thinking_end never fired, increment streamedExceptionCount\n  before flush to skip already-streamed thinking content\n- Add test case for missing thinking_end scenario",
          "is_bot": false,
          "headline": "fix: add thinkingBlockInProgress flag to prevent duplicate thinking l…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T14:12:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "79358ea62ce31c80b01cd3bda5f34a408d573862",
          "body": "- thinking_end handler now flushes buffer before clearing it (was violating AC)\n- thinking_delta handler now tracks streamed chars for proper deduplication\n- deduplication test now fires thinking_end to properly test the logic",
          "is_bot": false,
          "headline": "fix: flush thinking buffer on thinking_end and fix deduplication test",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T13:58:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0dfb2497aeb58163548036b95f84b36f58218f96",
          "body": "- Add config option outputThinkingBufferSize (default 0 = disabled)\n- When > 0, thinking deltas stream during message_update events\n- Buffer flushes when reaching configured size, newline, thinking_end, or turn_end\n- No duplicate thinking content at turn_end (already-streamed content skipped)\n- All existing tests pass, new tests added for streaming behavior",
          "is_bot": false,
          "headline": "feat: stream thinking blocks to output file in real-time",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-21T13:58:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a577ad00aafabd6d1fcab6666266220005d42121",
          "body": "Extract a border() color helper and hoist the │ vertical bar and ─ horizontal\nbar out of the loop. Removes three repeated this.theme.fg('muted', ...) calls\nand a per-iteration allocation, without changing output.",
          "is_bot": false,
          "headline": "refactor: hoist border styling in ResultViewer render override",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-20T01:24:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f974be37d84decde74c5c89bd1eeae41d0d0c0c5",
          "body": "The render override rendered children at innerWidth (width-2), then wrapped\neach line with '│ ' + line + ' │'. Since real Text pads every non-empty child\nline to the width it is given, content rows came back innerWidth wide and the\nbox added 4 more columns, making content rows width+2 while the top/\n[…]\ned width and that the\nright │ survives on content rows (short, full-width, and empty lines).\n\nAlso drop a duplicate expect(markdownRender).toHaveBeenCalled() in the\n'works with markdown content' test.",
          "is_bot": false,
          "headline": "fix: align box borders in ResultViewer render override",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-20T01:23:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9017ca3aeecb49eeb10519a8a9622bce33f09928",
          "body": null,
          "is_bot": false,
          "headline": "Add back padding for result viewer",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-20T00:36:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "438b69170fa49edf38f3a150bf2c24812e6643ac",
          "body": "…ialog/SelectOption\n\nThe dialog backs every search-backed menu (provider/model/type/worktree\nselection), not just model selection. Rename the symbols and move the\nfile from src/models/ to src/ui/ to reflect that it is a generic UI\nprimitive, not model-domain logic.\n\n- ModelSelectorDialog -> Searchab\n[…]\nelOption -> SelectOption\n- currentModel param -> currentValue\n- filterModels -> filterItems\n- src/models/model-selector.ts -> src/ui/searchable-select.ts\n\nImport sites and test mocks updated to match.",
          "is_bot": false,
          "headline": "refactor: rename ModelSelectorDialog/ModelOption to SearchableSelectD…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T20:24:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eaaa149e5f6c1bdfe27e087618b6fe2c8d079287",
          "body": "…ed menus\n\nThe search addition reused ModelSelectorDialog to pick providers, agent\ntypes, and worktrees, copy-pasting the same delegator-forward-declaration\ndance four times across three files. Extract one factory in helpers.ts\nthat owns the dialog+delegator wiring; onSelect may return a Component\nt\n[…]\nl pick (worktree picker).\n\nCollapse the two near-identical addModelLimitSubmenu / addProviderLimitSubmenu\nfactories in menu-concurrency into one addPickThenValueSubmenu parameterized\nby its item list.",
          "is_bot": false,
          "headline": "refactor(menu): extract createSearchableSelect helper for search-back…",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T20:16:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d335f770a7c3f9d48dfaad31cb6c069a5a336368",
          "body": "The 'remove duplicate provider badge' fix dropped the provider field\nfrom provider/type list items, but ModelOption still required it, breaking\ntypecheck. The dialog already guards empty provider in rendering, so make\nthe field optional.",
          "is_bot": false,
          "headline": "fix(menu): make ModelOption.provider optional to match usage",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T20:14:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d856f7a6054ccc8e89c276b11c3db32f2666f91d",
          "body": null,
          "is_bot": false,
          "headline": "fix(menu): remove duplicate provider badge from provider/type lists",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T20:09:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8fdfe86a5a60fb6aff7092017a85587e81cbd5cd",
          "body": null,
          "is_bot": false,
          "headline": "fix(menu): hide empty provider badge in ModelSelectorDialog",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T20:07:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "03849d7c37d86c0b146cd09e4a954ca2a82cde8c",
          "body": null,
          "is_bot": false,
          "headline": "feat(menu): add search to type selection and worktree picker",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T20:05:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "60ffe42e64b72ec824dc2a11266c56354664a498",
          "body": null,
          "is_bot": false,
          "headline": "feat(menu): add search to provider selection in concurrency settings",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T19:57:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "faaff6c90061f5c6b2ac9755b1c604bc1758ecab",
          "body": null,
          "is_bot": false,
          "headline": "feat(menu): add search to model selection in concurrency settings",
          "author_name": "Alexander Paramonov",
          "author_login": "AlexParamonov",
          "committed_at": "2026-06-19T19:54:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 0,
      "commits_last_year": 493,
      "latest_release_at": null,
      "latest_release_tag": null,
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 9,
      "days_since_latest_release": null,
      "mean_days_between_releases": null
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": false,
      "has_contributing": false,
      "health_percentage": 28,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "pi-subagents-lite",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "pi-package",
            "pi",
            "pi-agent",
            "pi-coding-agent",
            "pi-extension",
            "subagents",
            "ai",
            "agents"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/pi-subagents-lite",
          "is_deprecated": false,
          "latest_version": "1.4.10",
          "repository_url": "https://github.com/AlexParamonov/pi-subagents-lite",
          "versions_count": 22,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 2122,
          "first_published_at": "2026-05-26T16:40:31.915000Z",
          "latest_published_at": "2026-07-17T19:56:32.030000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        }
      ]
    },
    "popularity": {
      "forks": 5,
      "stars": 14,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2026-07-07",
            "count": 1
          },
          {
            "date": "2026-07-12",
            "count": 2
          },
          {
            "date": "2026-07-20",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 4,
        "total_forks": 5
      },
      "star_history": null,
      "open_issues_and_prs": 1
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 65026,
      "source_files_sampled": 93,
      "oversized_source_files": 1,
      "agent_instruction_files": [
        "AGENTS.md"
      ],
      "agent_instruction_max_bytes": 195
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "@earendil-works/pi-agent-core",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.80.10"
        },
        {
          "name": "@sinclair/typebox",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.34.49"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 1,
        "closed_ratio": 0.857,
        "closed_issues": 6,
        "closed_unmerged_prs": 1
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "AlexParamonov",
          "commits": 491,
          "avatar_url": "https://avatars.githubusercontent.com/u/352030?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": true,
      "ci_workflows": [],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": null,
            "reason": "No tokens found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 8,
            "reason": "2 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "5057ae195a4928628428c1ab1196c05f9a837b99",
        "ran_at": "2026-07-23T03:20:28Z",
        "aggregate_score": 2.4,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": null,
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": [
        {
          "number": 4,
          "created_at": "2026-06-17T01:12:40Z",
          "last_comment_at": "2026-06-21T11:26:36Z",
          "last_comment_author": "AlexParamonov"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/AlexParamonov/pi-subagents-lite",
    "host": "github.com",
    "name": "pi-subagents-lite",
    "owner": "AlexParamonov"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 39,
      "inputs": {
        "security": 24,
        "vitality": 36,
        "community": 41,
        "governance": 47,
        "engineering": 44
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "at_risk",
        "name": "Vitality",
        "value": 36,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "commits_last_year": 493,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 9
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "9/52 weeks with commits",
                "points": 6.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 9
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "493 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 493
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "critical",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "releases_count": 0
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "no releases published",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_releases_published",
                    "params": {}
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "no releases",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_releases",
                    "params": {}
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "no releases",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_releases",
                    "params": {}
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 41,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 23,
            "inputs": {
              "forks": 5,
              "stars": 14,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "14 stars",
                "points": 18.1,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 14
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "5 forks",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 56,
            "inputs": {
              "packages": [
                "pi-subagents-lite"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 2122
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "2,122 downloads/month across npm",
                "points": 44.4,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 2122,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 47,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "at_risk",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 1,
              "closed_issues": 6,
              "issue_closed_ratio": 0.857,
              "closed_unmerged_prs": 1
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "86% of issues closed",
                "points": 40.1,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 86
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "0/1 decided PRs merged",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 0,
                      "decided": 1
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 55,
            "inputs": {
              "followers": 19,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "AlexParamonov",
              "public_repos": 58,
              "account_age_days": 5833
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "19 followers of AlexParamonov",
                "points": 9.4,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 19,
                      "login": "AlexParamonov"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "58 public repos, account ~15 yr old",
                "points": 24.9,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 58
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 15
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "pi-subagents-lite"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 5
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 5 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "22 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 22
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "at_risk",
        "name": "Engineering Quality",
        "value": 44,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "at_risk",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 30,
            "inputs": {
              "has_ci": false,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "critical",
        "name": "Security",
        "value": 24,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "critical",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 24,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 2.4
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "2 existing vulnerabilities detected",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 55,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "moderate",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 58,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.83,
              "agent_instruction_files": [
                "AGENTS.md"
              ],
              "agent_instruction_max_bytes": 195
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md (stub)",
                "points": 18,
                "status": "partial",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md"
                    }
                  },
                  {
                    "code": "agent_instructions_stub",
                    "params": {}
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "83 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 83,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 37,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "tsconfig.json"
              ],
              "agent_commit_share": 0,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 99,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 65026,
              "source_files_sampled": 93,
              "oversized_source_files": 1
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "TypeScript (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "TypeScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "1/93 source files over 60KB",
                "points": 54.4,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 93,
                      "oversized": 1
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index npm:pi-subagents-lite@1.4.10; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-23T03:20:33.461719Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/a/AlexParamonov/pi-subagents-lite.svg",
  "full_name": "AlexParamonov/pi-subagents-lite",
  "license_state": "standard",
  "license_spdx": "MIT"
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v1.13.0, esquema v0.27.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadasnpm.