公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-23 03:20 UTC

AlexParamonov / pi-subagents-lite

TypeScriptMIT★ 14 星标⑂ 5 复刻始于 2026年5月在 GitHub 上查看 ↗

AlexParamonov/pi-subagents-lite 的健康指数为 100 分中的 39 分,处于「存在风险」区间。 其得分最高的类别是AI Readiness(55/100),最低的是Security(24/100)。 最近一次更新在今天。 近期的大部分工作由 1 位贡献者完成。

39
总分 / 100
存在风险

软件健康指数

指标归入加权类别,统一采用 1–100 量表。总体分先取类别加权平均;当公开证据触发高风险司法辖区政策时,评级会按政策调整,并设置 49(有风险)的上限。AI 就绪度不计入总体分。

39
优秀85-100堪称典范;基本满足所有检验标准
良好70-84健康;仅有轻微不足
中等50-69可接受,但存在明显不足;建议进行审查
存在风险30-49存在重大薄弱环节;采用时应保持审慎
危急1-29问题严重(项目被弃置、仅有单一维护者、缺乏基本工程规范)
活力社区与采用可持续性与治理工程质量安全AI 就绪度

评分画像

每条轴代表一个类别。形状比平均值更重要——健康的对象会填满整个图形,而“一峰一谷”式画像意味着某一维度的优势正掩盖另一维度的风险。

所有权

19 关注者58 个公开仓库始于 2010年8月

该仓库由个人账户拥有。相较于组织支持的项目,单一所有者项目的延续性风险更高。

软件包生态系统

注册表软件包版本月下载量版本数最近发布标签
npmpi-subagents-lite1.4.102,122225 天前pi-packagepipi-agentpi-coding-agentpi-extensionsubagentsaiagents

按类别列示的指标

活力

项目是否仍有生命——是否仍在编写代码,是否仍在发布版本?

36存在风险 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 0 天前
6.2/36提交节奏 — 52 周中有 9 周有提交
18/18提交量 — 最近一年 493 次提交
0/10OpenSSF Scorecard:Maintained — project was created within the last 90 days. Please review its contents carefully
所用输入
commits_last_year493
human_commit_share1
days_since_last_push0
active_weeks_last_year9
评分方式
0/27有发布版本 — 未发布任何发布版本
0/36发布时效 — 没有发布版本
0/27发布节奏 — 没有发布版本
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count0
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

项目是否拥有用户、下载量与关注度,并具备欢迎贡献者参与的配置?

41存在风险 · 占总体的 18%
评分方式
18.1/60星标 — 14 个星标
5/25复刻 — 5 个复刻
0/15关注者 — 0 位关注者
所用输入
forks5
stars14
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

50中等
评分方式
22.5/22.5README
22.5/22.5许可证 — 可识别的许可证(MIT)
0/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template
评分方式
44.4/80月度下载量 — npm 合计每月 2,122 次下载
0/20注册表被依赖数 — 该生态系统不报告此项
所用输入
packagespi-subagents-lite
dependents
ecosystemsnpm
total_downloads
monthly_downloads2,122
已排除计分(无数据或不适用):注册表被依赖数。 其余权重已重新归一化。

可持续性与治理

项目能否在其成员之外延续——巴士系数、响应能力、由谁支持,以及软件包的维护状况?

47存在风险 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0/22.5提交分布 — 头号贡献者编写了 100% 的提交
1.4/13.5贡献者广度 — 1 位贡献者
0/10OpenSSF Scorecard:Contributors — project has 0 contributing companies or organizations -- score normalized to 0
所用输入
bus_factor1
contributors_sampled1
top_contributor_share1
评分方式
40.1/46.8议题解决 — 86% 的议题已关闭
0/38.3PR 接受 — 已裁定的 PR 中 0/1 已合并
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs0
open_issues1
closed_issues6
issue_closed_ratio0.857
closed_unmerged_prs1
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
9.4/25所有者影响力 — AlexParamonov 有 19 位关注者
24.9/25既往记录 — 58 个公开仓库,账户约 15 年
所用输入
followers19
owner_typeUser
is_verified
owner_loginAlexParamonov
public_repos58
account_age_days5,833
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — npm 上有 1 个软件包
35/35发布时效 — 最近一次发布于 5 天前
20/20版本历史 — 22 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagespi-subagents-lite
ecosystemsnpm
any_deprecated
min_days_since_publish5

工程质量

基础的工程与文档实践是否到位?

44存在风险 · 占总体的 20%

工程实践

30存在风险
评分方式
0/24CI 工作流
24/24存在测试
0/16Linter 配置
0/9.6Pre-commit 钩子
0/6.4.editorconfig
0/20OpenSSF Scorecard:CI-Tests — 无数据
所用输入
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_config
已排除计分(无数据或不适用):OpenSSF Scorecard:CI-Tests。 其余权重已重新归一化。

文档

65中等
评分方式
30/30README
25/25文档目录
0/15文档 / 主页站点
0/10仓库描述
0/10主题标签
10/10Wiki
所用输入
topics
has_wiki
homepage
has_readme
has_docs_dir
has_description

安全

可见的安全与供应链实践是否稳固,且不存在未解决的高风险司法辖区暴露?

24危急 · 占总体的 16%

安全态势

24危急
评分方式
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 — 无数据
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 — 无数据
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — 无数据
0/5Pinned-Dependencies — 无数据
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — 无数据
0/7.5Token-Permissions — 无数据
6/7.5Vulnerabilities — 2 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate2.4
已排除计分(无数据或不适用):ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions。 其余权重已重新归一化。

AI 就绪度

该仓库在多大程度上具备与 AI 编码代理协同开发与维护的条件?这是一枚独立的实验性徽章——权重为 0.0,因此单独呈现,不影响总体健康评分。

55中等 · 占总体的 0%
评分方式
18/45代理指令 — AGENTS.md(占位文件)
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 83 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.83
agent_instruction_filesAGENTS.md
agent_instruction_max_bytes195
评分方式
0/18一条命令的引导启动
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — tsconfig.json
0/10可复现环境
0/10已体现的代理实践 — 最近 100 次提交中没有代理编写的提交
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — 无数据
所用输入
has_nix
has_tests
lockfiles
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configstsconfig.json
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
已排除计分(无数据或不适用):OpenSSF Scorecard:Pinned-Dependencies。 其余权重已重新归一化。
评分方式
45/45可类型检查的代码 — TypeScript(静态类型)
54.4/55可控的文件大小 — 采样的 93 个源文件中有 1 个超过 60KB
所用输入
primary_languageTypeScript
largest_source_bytes65,026
source_files_sampled93
oversized_source_files1

关键数据

14GitHub 星标
1贡献者
493最近 12 个月提交数
0距最近推送天数
0发布版本数
1巴士系数(bus factor)
1开放议题
npm软件包生态系统数

数据采集警告

  • 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

更多细节

Star 与 Fork 历史 0 ★ / 5 ⇿
0Star
5Fork

每颗 star 和每个 fork 的添加时间,来自 GitHub 并按天汇总。累计增长位于其构成来源——每日新增——的正上方,二者可相互对照:稳定的自然增长与短暂的突增形态截然不同。当这一差别可被衡量时,它会作为增长真实性予以报告。

1223344422026-072026-072026-07
OpenSSF Scorecard 2.4 / 10
2.4综合

来自开源项目 OpenSSF Scorecard 的独立、工具无关的安全评估。每项检查奖励的是安全实践本身,而非特定供应商的工具。Scorecard 无法判定的检查项标记为 不适用,并从安全评分中剔除(绝不按零分计)。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
不适用CI-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
不适用Dangerous-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
不适用Packagingpackaging workflow not detected
不适用Pinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
不适用Token-PermissionsNo tokens found
8Vulnerabilities2 existing vulnerabilities detected
直接依赖 2
注册表软件包版本约束清单文件
npm@earendil-works/pi-agent-core^0.80.10package.json
npm@sinclair/typebox^0.34.49package.json
全部依赖 未采集

本报告未能采集到解析后的依赖集合:GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

原始 JSON 报告 机器可读
{
  "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"
}

评分是信号,而非担保。 评分反映的是 GitHub 上公开可见的实践——不是代码审计,也不是安全保证。

缺失数据将被剔除并重新归一化权重,绝不按零分计。方法论已版本化并公开:指标 v1.13.0、模式 v0.27.0—— 完整方法论 · 指标知识库.

单项结果在整体记录中的位置: 汇总统计npm.