公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-24 11:31 UTC

andmarios / google-workspace-skill

Claude Code skill for Google Workspace management (drive, docs, sheets, slides, gmail, calendar, contacts)

PythonMIT★ 5 星标⑂ 2 复刻始于 2025年12月在 GitHub 上查看 ↗

andmarios/google-workspace-skill 的健康指数为 100 分中的 43 分,处于「存在风险」区间。 其得分最高的类别是Vitality(67/100),最低的是Security(29/100)。 最近一次更新在今天。 近期的大部分工作由 1 位贡献者完成。

43
总分 / 100
存在风险

软件健康指数

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

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

评分画像

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

所有权

40 关注者36 个公开仓库始于 2011年12月@lensesio

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布标签
PyPIgws-cli1.4.03,69660 天前calendarclidocsdrivegmailgooglesheetsslidesworkspace

按类别列示的指标

活力

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

67中等 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 0 天前
7.6/36提交节奏 — 52 周中有 11 周有提交
17.2/18提交量 — 最近一年 81 次提交
2/10OpenSSF Scorecard:Maintained — 3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
所用输入
commits_last_year81
human_commit_share1
days_since_last_push0
active_weeks_last_year11

发布纪律

72良好
评分方式
16.2/27有发布版本 — 1 个版本标签(无 GitHub 发布版本)
36/36发布时效 — 最近一次发布版本于 2 天前
12.6/27发布节奏 — 节奏未知(仅一次发布)
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count1
latest_release_tagv1.4.0
releases_from_tags
days_since_latest_release2
mean_days_between_releases
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

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

36存在风险 · 占总体的 18%
评分方式
9.8/60星标 — 5 个星标
0/25复刻 — 2 个复刻
0/15关注者 — 0 位关注者
所用输入
forks2
stars5
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
评分方式
47.6/80月度下载量 — pypi 合计每月 3,696 次下载
0/20注册表被依赖数 — 该生态系统不报告此项
所用输入
packagesgws-cli
dependents
ecosystemspypi
total_downloads
monthly_downloads3,696
已排除计分(无数据或不适用):注册表被依赖数。 其余权重已重新归一化。

可持续性与治理

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

38存在风险 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0/22.5提交分布 — 头号贡献者编写了 100% 的提交
1.4/13.5贡献者广度 — 1 位贡献者
3/10OpenSSF Scorecard:Contributors — project has 1 contributing companies or organizations -- score normalized to 3
所用输入
bus_factor1
contributors_sampled1
top_contributor_share1
评分方式
0/46.8议题解决 — 没有议题或无数据
0/38.3PR 接受 — 没有已裁定的拉取请求或无数据
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
已排除计分(无数据或不适用):议题解决, PR 接受。 其余权重已重新归一化。
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
11.6/25所有者影响力 — andmarios 有 40 位关注者
23.4/25既往记录 — 36 个公开仓库,账户约 14 年
所用输入
followers40
owner_typeUser
is_verified
owner_loginandmarios
public_repos36
account_age_days5,345
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — pypi 上有 1 个软件包
35/35发布时效 — 最近一次发布于 0 天前
20/20版本历史 — 6 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagesgws-cli
ecosystemspypi
any_deprecated
min_days_since_publish0

工程质量

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

38存在风险 · 占总体的 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。 其余权重已重新归一化。

文档

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

安全

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

29危急 · 占总体的 16%

安全态势

29危急
评分方式
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.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
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
1.5/7.5Maintained — 3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
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 — 无数据
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate2.9
已排除计分(无数据或不适用):ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions。 其余权重已重新归一化。

AI 就绪度

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

56中等 · 占总体的 0%
评分方式
45/45代理指令 — CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 81 次人类提交中有 81 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes9,249
评分方式
0/18一条命令的引导启动
22/22自动化测试
0/11Lint / 格式化配置
0/11静态类型检查
0/10可复现环境
10/10已体现的代理实践 — 最近 81 次提交中有 81 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — 无数据
所用输入
has_nix
has_tests
lockfiles
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share1
toolchain_manifests
dependency_bot_commit_share0
已排除计分(无数据或不适用):OpenSSF Scorecard:Pinned-Dependencies。 其余权重已重新归一化。
评分方式
0/45可类型检查的代码 — Python,未配置类型检查
49.9/55可控的文件大小 — 采样的 54 个源文件中有 5 个超过 60KB
所用输入
primary_languagePython
largest_source_bytes132,665
source_files_sampled54
oversized_source_files5

关键数据

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

数据采集警告

  • 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 pypi:gws-cli@1.4.0; advisories assessed against the repository dependency graph instead

更多细节

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

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

111222212026-012026-022026-04
OpenSSF Scorecard 2.9 / 10
2.9综合

来自开源项目 OpenSSF Scorecard 的独立、工具无关的安全评估。每项检查奖励的是安全实践本身,而非特定供应商的工具。Scorecard 无法判定的检查项标记为 不适用,并从安全评分中剔除(绝不按零分计)。Scorecard v5.5.0 · 2026-07-24 11:31 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
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
不适用Dangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
2Maintained3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
不适用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
10Vulnerabilities0 existing vulnerabilities detected
直接依赖 8
注册表软件包版本约束清单文件
PyPItyper>=0.9.0pyproject.toml
PyPIrich>=13.0.0pyproject.toml
PyPIgoogle-api-python-client>=2.100.0pyproject.toml
PyPIgoogle-auth>=2.23.0pyproject.toml
PyPIgoogle-auth-oauthlib>=1.1.0pyproject.toml
PyPIhttpx>=0.25.0pyproject.toml
PyPIprompt-security-utils>=1.3.0pyproject.toml
PyPIcryptography>=46.0.4pyproject.toml
全部依赖 未采集

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1278,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Python": 1149025
      },
      "pushed_at": "2026-07-24T11:30:27Z",
      "created_at": "2025-12-30T21:52:11Z",
      "owner_type": "User",
      "updated_at": "2026-07-21T19:52:28Z",
      "description": "Claude Code skill for Google Workspace management (drive, docs, sheets, slides, gmail, calendar, contacts)",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Python",
      "significant_languages": [
        "Python"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Marios Andreopoulos",
      "type": "User",
      "login": "andmarios",
      "company": "@lensesio ",
      "location": "Greece",
      "followers": 40,
      "avatar_url": "https://avatars.githubusercontent.com/u/1239679?v=4",
      "created_at": "2011-12-04T13:06:02Z",
      "is_verified": null,
      "public_repos": 36,
      "account_age_days": 5345
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.4.0",
          "kind": "minor",
          "published_at": "2026-07-21T15:00:35Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "f553af056ed88773cd71213f05b1bd38ed89c588",
          "body": "- SKILL.md: add an \"Auth modes: local vs server\" section explaining that\n  bare `gws-cli auth` logs in via the configured mode, how `auth status` /\n  `account list` surface it, and how to switch with `config set-mode`.\n- Note upstream token revoke on logout in the auth command list.\n- Sync version to 1.4.0 across pyproject.toml (was 1.3.1) and\n  gws/__init__.py (was 1.3.0) — they had drifted apart.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: document local vs server auth modes; bump version to 1.4.0",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-07-21T15:00:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b9407640f8c34a1ec5e805f9c752a51ec12bd8ca",
          "body": "Move the auth, account, and config Typer command groups out of the\nmonolithic cli.py into src/gws/commands/{auth,account,config}.py, matching\nthe existing convention used for the service command modules. cli.py becomes\na thin 69-line assembler that defines the root app and registers every group.\n\nPu\n[…]\ng,\nruff clean, no new mypy errors, and every command group (auth/account/config\nplus all 8 service groups) loads via the real CLI.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(cli): split 1124-line cli.py into per-group command modules",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-06-26T11:50:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2bb0590ce4595a53d9e1b613c50a2e35f556af46",
          "body": "Bug fixes (each with a regression test):\n- H1: `config set-mode server` with no --url no longer wipes the inherited\n  global server_url/server_provider (mirror the per-account conditional write);\n  the effective server URL is now reported in the output.\n- H2: deriving the encryption key on a per-acc\n[…]\nhe bare command logs in via the configured mode\n\nCleanup:\n- remove dead Config.is_service_enabled\n\nTest suite: 254 -> 274 passing.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(auth): fix 3 data-integrity bugs, harden security, surface auth mode",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-06-26T11:44:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a8882c208b03b9b0576ae5d3dffae3859f25bc64",
          "body": "Gmail's batch HTTP API caps at 100 requests per batch. list_messages()\nand list_drafts() previously stuffed all refs into a single batch,\ncausing failures when --max exceeded 100. Now chunks in groups of 100.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: chunk Gmail batch requests to respect 100-request API limit",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-04-07T18:35:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8744a42fad0deddb20c8995e257ad90d3bb3dea1",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: document download security gate, bump version to 1.3.0",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T18:00:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b2b23f75f0fe683bd7cb8463cc738719312945dc",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: add integration tests for download security gate",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T17:56:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8abb465fba95061fc9168a789d5078500a99bf49",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add download security gate to docs export",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T17:47:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1fa6963381a7722bd420095e0769aa8f084f02f1",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add download security gate to gmail download-attachment",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T17:41:15Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c24dd5e57e47eeabf8c8b1d2821f23734bb20ada",
          "body": "Integrate screen_download() into DriveService.download() and\nDriveService.export() methods. Add --force CLI flag to both commands\nto allow bypassing security screening when needed.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add download security gate to drive download/export",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T17:36:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b8c5ffb884589d6b9c96412d85337e1ef413411e",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add screen_download() helper for download security gate",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T17:23:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f526424d11e933dabfba2882b8a05bc8ecd2445d",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: simplify output_external_content using library skip_wrapping",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T17:16:01Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4bf27db3495ed1a745171258b6246ddb3caa2200",
          "body": "Add wrap_external_data and read_and_wrap_file to security utility exports.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump prompt-security-utils to >=1.3.0, add new exports",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T17:11:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "35fcc5ee7c3ff78dcb7b275e49555975330c7806",
          "body": "Previously only 5 operations (docs.read, sheets.read, slides.read,\ngmail.read, gmail.get_draft) used output_external_content() with\nsecurity markers. ~30 other operations output user-authored content\nfrom Google APIs via raw output_success(), bypassing all security\nlayers (session markers, regex det\n[…]\ntacts (3 ops).\n\nAlso adds calendar/contact source types to allowlist routing and\nfixes a pre-existing test assertion for session marker kwargs.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Security: wrap all external content with prompt-security-utils pipeline",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-07T15:02:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "db5b17cccf66d9d1cecfd84a2091982deac19038",
          "body": "Keep the file locally but stop tracking it in version control.\nAdded to .gitignore to prevent future commits.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: remove docker-compose-kroki.yml from git tracking",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-06T10:44:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "503a57c85e1985e7ff2dae2499c352956c692f1d",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.1.0",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T17:15:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7778d8ce6ca6f4c422b0ca7c16576029b118981b",
          "body": "Providers that don't set token expiry return expires_in=0 from the\nrelay. The CLI used this value directly, making the token immediately\nexpired and triggering re-auth on every request. Now defaults to 1h.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix expires_in=0 causing immediate token expiry in server auth",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T16:00:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3c8716eadcea93a723e1807992edd402dc1d61a4",
          "body": "Markers are now generated once at module load and passed through to\noutput_external_content() rather than being generated per-call inside\nthe library. Aligns with the trusted-channel architecture where markers\nreach the LLM via the system prompt before any untrusted content.\n\nChanges:\n- output.py: m\n[…]\nia generate_markers();\n  pass markers to _output_external_content()\n- utils/security.py: re-export generate_markers and security_instructions\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Use session-scoped security markers (prompt-security-utils v1.2.0)",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T15:02:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e108f01f50f90e4c3b6940281a95689e8439a9a7",
          "body": "- Set pretty_exceptions_show_locals=False to prevent credential leaks\n  in Rich tracebacks (client_secret, encryption key, salt were exposed)\n- Rename PyPI package from gws to gws-cli\n- Improve README with usage examples and AI assistant integration guide\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Security: disable locals in tracebacks, improve README, bump 1.0.2",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T11:56:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "53ac84634e8afe0cde206dc074531c50d9b02c96",
          "body": "- Rename title to reflect CLI + Claude Code skill\n- Add Quick Start with uvx gws-cli usage\n- Add usage examples for all services\n- Add \"Using with AI Assistants\" section (Claude Code + other agents)\n- Replace placeholder URLs with actual repo links\n- Simplify security docs, link to prompt-security-utils\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Improve README and bump to 1.0.1",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T09:12:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "888d4701a24623a408b68e5d542f88f611f65e24",
          "body": "- Switch prompt-security-utils dependency from Git to PyPI (>=1.0.0)\n- SKILL.md: use self-describing markers from response instead of config file\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Prepare 1.0.0 release for PyPI",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T09:05:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9bc0dadcd2d507294435cba3bba1967703c4f284",
          "body": "- Replace `uv run gws-cli` with `uvx gws-cli` across all docs and references\n- Fix incorrect flags: --anyone → --type anyone, --count → RRULE COUNT, config → config list\n- Trim SKILL.md from 861 to 434 lines (progressive disclosure: move details to reference files)\n- Remove hardcoded security marker\n[…]\n Add Read permission for prompt-security config so markers can be discovered\n- Fix leaked 'google-lenses' in CLI help text → 'google-workspace'\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Update SKILL.md: uvx migration, flag fixes, trim to 434 lines",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "663864e726441a3a398217ffc84e83b26c7a3325",
          "body": "When switching from local to server mode (or vice versa), the old token\nremains on disk and gets reused — the new auth mode never triggers.\nNow deletes the account's Google token on mode switch so the next API\ncall re-authenticates through the correct provider.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix: clear Google token when switching auth mode via config set-mode",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "39d23285f4c3ce8c05ee9f2b0e5a32578e76f0f7",
          "body": "Read-only scopes: when an account is set to read-only, request .readonly\nOAuth scopes (e.g. gmail.readonly, drive.readonly) so the token itself\nenforces least-privilege. Token is cleared on mode switch to force re-auth.\n\nBug fixes:\n- set-readonly/unset-readonly now use delete_encrypted() to clear bo\n[…]\n not\n  gws.auth.provider (where it's defined) to fix test isolation hang when\n  test_account_commands runs before test_docs or test_gmail_mime.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix 3 bugs, add read-only OAuth scopes, fix test isolation",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e97f3256006c42ab0ecbae34da44d08387fdb04d",
          "body": "All secret files (OAuth tokens, client credentials) are now encrypted\nat rest using Fernet symmetric encryption. The key is derived at runtime\nfrom machine-specific identifiers (machine-id + username) via HKDF-SHA256\nand never stored on disk.\n\n- Add crypto.py module (Fernet encrypt/decrypt, HKDF key\n[…]\ncredentials' CLI command for importing client_secret.json\n- Add 17 crypto module tests\n- Set GWS_ENCRYPTION=none to disable encryption entirely\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: encrypt secrets at rest using Fernet with machine-derived key",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d8248f49de7ea24522d3df300e823e7971f22d38",
          "body": "…cement, gmail MIME\n\nAdd 76 new tests (208 total) covering highest-risk untested code:\n- test_output.py: output_external_content security wrapping (15 tests)\n- test_server_auth.py: ServerAuthProvider token load/save/permissions (27 tests)\n- test_auth_provider.py: resolve_auth_provider factory + URL \n[…]\n_enforcement.py: account_callback allowed_operations (5 tests)\n- test_gmail_mime.py: MIME construction, CC/BCC, attachments, helpers (18 tests)\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: security wrapping, server auth, provider factory, account enfor…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "937bfc57e877652b3b518147c960660c9d0cb18a",
          "body": "… fixtures\n\n- HYG-1: Add .claude/ and *.png to .gitignore\n- HYG-2: Replace real name with 'testuser' in LIVE_TESTING.md\n- HYG-3: Remove 7 unused fixtures and MockHttpError from conftest.py\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: gitignore .claude/ and *.png, anonymize test data, remove dead…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1e98e3c7e4ff16f2d647cd4618d5c51f8c149973",
          "body": "…onvert.py cleanup\n\n- ARCH-1: Add TOKEN_PATH and account_name properties to AuthProvider protocol;\n  remove 9 hasattr() checks in cli.py, use direct property access instead\n- ARCH-2: convert.py md_to_slides: raise e → bare raise, wrap cleanup delete\n  in try/except (HttpError, OSError) for best-effort behavior\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: add token_path/account_name to AuthProvider protocol, fix c…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5c30af5f4c6e48c1eecf1ec219ae524a8cb5a352",
          "body": "…notations\n\n- CLI-1/2: Replace 6 typer.echo + Exit(1) with output_error + ExitCode.INVALID_ARGS\n  in docs.py (append, insert-markdown) and gmail.py (send, reply, create-draft)\n- CLI-3: Widen output_error details param to Any, use 'is not None' check\n- CLI-4: read_json_stdin: sys.exit(4) → raise SystemExit(ExitCode.INVALID_ARGS)\n- CLI-5: docs.py set_table_column_widths: SystemExit → typer.Exit\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: replace typer.echo with output_error, fix exit codes and type an…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6387eeb3b6392ec86eac0cce0bd2c3787f7201ab",
          "body": "…ation, reminder parsing, JSON validation, diagram warnings\n\n- BUG-1: Gmail batch callback now collects errors and reports failed_ids\n- BUG-2: Replace 4 raw .execute() with self.execute() in sheets/slides create\n- BUG-3: Rewrite list_drafts to use batch requests (fix N+1 queries)\n- BUG-4: Add 3-char\n[…]\nndar reminders\n- BUG-6: Wrap json.loads in try/except for sheets write/append commands\n- BUG-8: Add stderr warning for failed diagram rendering\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: gmail batch errors, self.execute(), drafts batching, color valid…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3931f8b1e80f2ed0b8ec4c0c8c47cd6e1cea3426",
          "body": "- ERR-1a/1b: oauth.py — narrow token load/refresh excepts to specific types\n- ERR-1c/1d: server.py — narrow refresh/logout excepts to specific types\n- ERR-1e: gmail.py — document intentional best-effort get_profile behavior\n- ERR-2a/2b: config.py — warn on corrupt config/account config files\n- ERR-2c/2d: server.py — warn on corrupt server/google token files\n- BUG-7: server.py — replace deprecated datetime.utcnow()\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: narrow bare excepts, add stderr warnings for silent fallbacks",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "29d713546532a702b4d8cc4ce02980bf726f4994",
          "body": "…nt, validate account names, validate server URL\n\n- SEC-1: Introduce _write_secure_file() helper with atomic 0o600 permissions.\n  Used in all 5 locations that write tokens or config files.\n- SEC-2: Read-only account enforcement now defaults to deny when a service\n  is not listed in allowed_operation\n[…]\n-account flag\n  and GWS_ACCOUNT env var to prevent path traversal.\n- SEC-4: Server URLs are validated to require HTTPS for non-localhost hosts.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "security: enforce 0o600 on token/config files, default-deny enforceme…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0100af0b827d3afd6cabe7fc88a9b7fbba214d90",
          "body": "…ate server auth\n\n- Rename CLI entry point from `gws` to `gws-cli` (pyproject.toml + Typer app)\n- Move config directory from ~/.claude/.google-workspace/ to ~/.config/gws-cli/\n- Auto-migrate existing config on first run (copy, not move)\n- Update server auth provider with auto-login, improved banners\n[…]\n config set-mode\n- Update auth provider resolution to support server mode\n- Update all docs and references to use new CLI name and config paths\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: rename CLI to gws-cli, migrate config to ~/.config/gws-cli, upd…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2d641ba7d95d212b36e2f3651d2d746fc86cb661",
          "body": "Remove _scopes_to_names() — the relay server is scope-agnostic and\nexpects full scope URLs from clients. The CLI now sends scope URLs\n(e.g., \"https://www.googleapis.com/auth/documents\") directly instead\nof converting them to short names first.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: send full scope URLs to relay server",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a5faf184f1e5ab6ea05623e53417ec15cb9741c9",
          "body": "Introduce AuthProvider protocol with pluggable backends:\n- LocalAuthProvider (renamed from AuthManager, alias kept)\n- ServerAuthProvider (delegates to oauth-token-relay server)\n\nBaseService now uses resolve_auth_provider() factory that routes\nbased on GWS_SERVER_URL env var or config.server_url.\n\nNe\n[…]\nfig gains mode and server_url fields.\n\nNote: ServerAuthProvider is not yet testable — requires the\noauth-token-relay server (Phase 3) to exist.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add auth provider abstraction and server mode scaffolding",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-03-05T08:42:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a6b35d37b000cee96f871ddeebac8345b2c55918",
          "body": "…t service\n\n- Add `gws docs export` with friendly format names (markdown, pdf, docx, txt,\n  html, rtf, epub, odt) that map to MIME types, defaulting to markdown\n- Preprocess markdown line breaks before Google Docs import: add trailing\n  double-spaces for hard breaks since Google follows strict Commo\n[…]\n table, and examples\n- Update reference/drive.md with expanded export examples and cross-reference\n- Add export to docs READ_ONLY_OPS in config\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add docs export command, fix markdown line breaks and clean up conver…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-11T18:43:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "df76f9b6b57cac4d16548ff00a87ab07829da92f",
          "body": "…erations\n\nBug fixes across 4 services:\n- Drive: remove invalid supportsAllDrives from revisions, fix resolve-comment API method\n- Docs: fix tabId placement in rename/reorder-tab, add missing padding to paragraph-border\n- Slides: handle empty notes in set-speaker-notes, default scaleY to 1.0 in tran\n[…]\nve header lookup, use format=full for reply\n\nAlso updates LIVE_TESTING.md with full test results and adds live testing\nguidelines to CLAUDE.md.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix 12 bugs found during comprehensive live testing of all 217 CLI op…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-06T10:33:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8e042577fc4c0eb2a9fc0a07dd486afa45bfc574",
          "body": "Add ~350 lines of Google API documentation covering:\n- Fields parameter and partial responses\n- PATCH vs PUT semantics\n- Service-specific tips (Docs, Sheets, Slides, Drive, Gmail, Calendar, Contacts)\n- Error handling with HTTP status codes and 403 reason fields\n- Exponential backoff strategy with fo\n[…]\nula\n- Rate limits reference tables for all services\n- Expanded anti-patterns section\n\nSources from official Google Workspace API documentation.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Expand SKILL-advanced.md with comprehensive API best practices",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:57:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9d82a5b15c729bdf978deb340faecb3e0556f894",
          "body": "Ruff fixes:\n- gmail.py: Add missing imports for attachment support (MIMEMultipart,\n  MIMEBase, encoders, os, mimetypes)\n- commands/gmail.py: Rename ambiguous variable 'l' to 'label'\n- docs.py: Remove unused variable assignments in suggestion methods\n- cli.py: Add noqa comment for intentional late im\n[…]\nation between md_to_doc and md_to_pdf\n- sheets.py: Remove redundant parse_hex_color imports inside methods\n  (already imported at module level)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix ruff lint errors and simplify code",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:14:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "09c74986113781b89372d1bdcc9411c967e16156",
          "body": "- Docs: Add named ranges to capabilities\n- Sheets: Add move/copy data, charts, conditional formatting\n- Slides: Add transforms, grouping, Sheets chart embedding\n- Drive: Add replies, shared drives, change tracking\n- Gmail: Add history sync, batch label operations, label management\n- Calendar: Add manage calendars, move events, color definitions, subscriptions\n- Contacts: Add directory search (Workspace), batch operations\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Update README capabilities table with new endpoints",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:08:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9b4328ee3fbab35fdf993462c95ff99079914ae8",
          "body": "Update Purpose section and key_capabilities to reflect all new\nfunctionality added across services.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Update SKILL.md with new endpoint capabilities",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:06:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "97c3246abd38368ae0adcc96c6ca1f495c004f62",
          "body": "Update reference docs:\n- drive.md: Replies, Changes API, Shared Drives, generate-ids, update-revision\n- calendar.md: Calendar management, move-event, subscriptions, colors\n- gmail.md: untrash, label management, batch-modify, delete-thread, history\n- sheets.md: Data manipulation (move, copy-paste, au\n[…]\neplace-image, delete-positioned-object\n\nCreate new reference doc:\n- contacts.md: Full contacts service documentation including directory search\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add documentation for all new endpoints",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:06:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a40a3563fa6c336b471d709f94fdbb811bb7d1fb",
          "body": "Document all endpoints tested against real Google Workspace account\non 2026-02-05, including test commands, results, and bugs found.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add live testing documentation",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:01:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e9c228840d269bef9cd635b798c259b9b676cedf",
          "body": "The Google Drive API comments() and replies() endpoints don't accept\nthe supportsAllDrives parameter in the Python client library. This\nwas incorrectly added during Phase 2.\n\nAffected methods: list_comments, create_comment, resolve_comment,\ndelete_comment, reply_to_comment, list_replies, get_reply,\nupdate_reply, delete_reply.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix: Remove supportsAllDrives from comments/replies API",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:01:38Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6bf47b09df38b6c92f42544013fab272781da58b",
          "body": "Expose the historyId field from the API response, enabling users to\ntrack mailbox changes via the history endpoint.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Include history_id in Gmail read output",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:01:38Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e6c1bcdb8bd3992c810639cf415e478336e3c750",
          "body": "Fix pre-existing omission where colorId was fetched from API but\ndropped during output formatting. Events with custom colors now\ninclude color_id field.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Include colorId in calendar event list output",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:01:38Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cad6838ec9283bfb2b51bf2ff71c426c41b9a86e",
          "body": "- Fix existing bugs: remove non-existent get-tab from docs, add\n  missing document-mode to docs list\n- Gmail: add get-label, history\n- Drive: add list-replies, get-reply, changes-token, list-changes,\n  list-shared-drives, get-shared-drive, generate-ids\n- Calendar: add colors\n- Contacts: add search-directory, list-directory, batch-get\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Update READ_ONLY_OPS for new endpoints",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T10:01:38Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "dd7c48dcba6baa67962f6c62c99cfe5042923f1c",
          "body": "B6: Add 3 new Docs endpoints:\n- replace-named-range: Replace content in named ranges\n- replace-image: Replace existing image with new one\n- delete-positioned-object: Delete floating images/drawings\n\nB7: Add 3 new Contacts endpoints:\n- search-directory: Search Google Workspace directory\n- list-direct\n[…]\nt all people in directory\n- batch-get: Get multiple contacts in one request\n\nAdd directory.readonly scope to contacts for directory operations.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add 3 Docs and 3 Contacts endpoints plus directory scope",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T08:07:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a46a3302fd12ac3fae20de40e7d0cbd68d9272c8",
          "body": "B1: Add 7 new Slides endpoints:\n- Transforms: transform-element (scale, translate, rotate)\n- Images: update-image (transparency, outline)\n- Grouping: group, ungroup (combine/split elements)\n- Replacement: replace-shapes-with-image (batch image placeholder fill)\n- Accessibility: set-alt-text (screen reader descriptions)\n- Embedding: insert-sheets-chart (embed linked/static Sheets charts)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add 7 new Slides endpoints for transforms and embedding",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T08:04:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "82d2faa4671f6bb10fb92efc75a406ee709c3924",
          "body": "A4: Fix list_calendars() to use fields parameter instead of fetching\nall calendar properties. Now uses 'items(id,summary,primary,accessRole,\nbackgroundColor),nextPageToken'.\n\nB3: Add 7 new Calendar endpoints:\n- Calendar management: create-calendar, delete-calendar, clear-calendar\n- Events: move-even\n[…]\nbetween calendars)\n- Colors: colors (get color definitions for calendars/events)\n- Subscriptions: subscribe, unsubscribe (manage calendar list)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add fields param to Calendar list and 7 new endpoints",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T08:02:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ef09284073fca6b2544de95f4dcb595b7b008922",
          "body": "A6: Fix list_messages N+1 problem by using batch HTTP requests instead\nof individual .get() calls. Listing 10 messages now uses 2 API calls\n(1 list + 1 batch get) instead of 11 (1 list + 10 individual gets).\n\nB5: Add 6 new Gmail endpoints:\n- Messages: untrash (restore from trash), batch-modify (bulk\n[…]\nlabel, update-label (name, visibility, colors)\n- Threads: delete-thread (permanent deletion)\n- History: history (list mailbox changes for sync)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix Gmail N+1 query and add 6 new endpoints",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T08:00:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "835cc1bb47510edc5e344ad417312fbd8d8e1514",
          "body": "A3: Fix metadata() and read() to use fields parameter instead of\nfetching entire spreadsheet data. metadata() now uses\n'spreadsheetId,properties,sheets(properties)' and read()'s fallback\nuses 'sheets(properties(title))'.\n\nB2: Add 8 new Sheets endpoints:\n- Charts: update-chart (title, type, legend po\n[…]\n update-filter-view\n\nAlso fixes pre-existing bug where add_banding used undefined hex_to_rgb\nby adding module-level import for parse_hex_color.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add fields param to Sheets metadata and 8 new endpoints",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T07:58:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a83e203ea77c20e03ba75539f7aa596d878e2d3e",
          "body": "A2: Add supportsAllDrives=True to all Drive operations so files on\nShared Drives are accessible. Also add includeItemsFromAllDrives=True\nto list and search operations.\n\nB4: Add 12 new Drive endpoints:\n- Replies: list-replies, get-reply, update-reply, delete-reply\n- Revisions: update-revision (keep f\n[…]\nred-drives, get-shared-drive, create-shared-drive,\n  delete-shared-drive\n- File IDs: generate-ids (pre-generate file IDs for create operations)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add Shared Drive support and 12 new Drive endpoints",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-05T07:52:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5cc8b4a2b170345dbaa26de57bf4c159d075954f",
          "body": "Add BaseService.execute() helper wrapping execute_with_retry() so all\nservices inherit automatic retry on transient errors (429, 500, 502, 503).\nReplace ~290 bare .execute() calls across all 8 service files with\nself.execute(). Add random jitter to exponential backoff in retry utility\nto prevent thundering-herd retries.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add retry logic to all API calls and jitter to backoff",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-04T22:43:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "59ba82d3520e2c01248edac40962108d3f6ae93c",
          "body": "Core infrastructure:\n- Add context.py for runtime active account state (avoids circular imports)\n- Extend config.py with AccountEntry, AccountsRegistry dataclasses\n- Add account CRUD methods: add, remove, update, list, set-default\n- Add account name validation (regex) to prevent path traversal\n- Add\n[…]\n-account config,\n  read-only mode, OAuth browser requirement notes\n- Update README.md with multi-account section and updated credential storage\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add multi-account support with per-account config and read-only mode",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-04T20:50:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bbf7f297f45311e6be7f140268c8e439d5dc8edd",
          "body": "Document skill-level settings (allowlists, toggles) in gws_config.json\nand shared settings (markers, detection, LLM screening) from\nprompt-security-utils. Restructure configuration section for clarity.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Rewrite README with two-tier security config documentation",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T23:05:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "938537722a16654a41f2422da5f34d54c11746c5",
          "body": "- Remove unused imports from services and commands\n- Update prompt-security-utils to 54ed84d\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Remove unused imports and update prompt-security-utils",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T22:35:01Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d892aeb110958fe754b1745a42a7c048d72cecdb",
          "body": "Move security allowlists from prompt-security-utils to GWS config:\n- Add allowlisted_documents, allowlisted_emails to Config\n- Add disabled_security_services, disabled_security_operations\n- Add is_allowlisted() and is_security_enabled_for_operation() methods\n- Add CLI commands: allowlist-add, allowlist-remove, allowlist-list\n- Update output_external_content() to check GWS allowlist before wrapping\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add service-specific security allowlists and CLI commands",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T22:21:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8129806a8616478c9ede674e6022bd4dba4da38d",
          "body": "- Add security_enabled config option (default: true, opt-out model)\n- Update output_external_content() to respect security setting\n- Add comprehensive security documentation to README\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add prompt injection protection with prompt-security-utils",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T21:54:07Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e0bf697a0ae81fb6631e7fcb5e4eff6a3c0877eb",
          "body": "…ping fix\n\nDocumentation improvements for undocumented features:\n- Add stdin/heredoc examples for docs append and docs insert-markdown\n- Add stdin examples for sheets write with complex JSON data\n- Document shell escaping patterns for sheet names with spaces and formulas\n\nAdd missing Quick Start wor\n[…]\nes shell escaping where ! becomes \\! in Claude Code sandbox)\n- Add --formulas flag to sheets read to return formulas instead of computed values\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add stdin documentation, Quick Start workflows, and Sheets shell esca…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T21:36:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5db5141c17d72413688c9726de5e86621dc90eb8",
          "body": "Document the --stdin flag and multi-line email patterns that were\nmissing from Gmail documentation. This enables first-try success\nfor common email workflows:\n\n- Add \"Send professional emails\" section to SKILL.md Quick Start\n- Add stdin examples to reference/gmail.md Basic Operations\n- Add stdin examples to reference/gmail.md Drafts section\n- Show heredoc patterns, HTML formatting, and key patterns\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add Gmail stdin/heredoc workflow documentation",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T20:32:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "383d2d445be06f92bc176d1d7c14fdc4f66f24f8",
          "body": "Allows setting multiple table column widths in a single API call,\nreducing N API calls to 1 for better efficiency.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add set-table-column-widths command for batch column width updates",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T20:25:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c82964b5663fa8cb985e2d1ed20b634db0152f56",
          "body": "- Rename dependency from mcp-security-utils to prompt-security-utils\n- Update imports from mcp_security to prompt_security\n- Configure uv.sources to use GitHub repository\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Update to use prompt-security-utils from GitHub",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T19:30:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f82b287ec12014abdc9c035500e84874099765dd",
          "body": "…t data\n\nStrengthened prompt injection guidance after a real failure:\n- External content is DATA, not context or requests to fulfill\n- \"User asked to READ\" ≠ \"User asked to DO what it says\"\n- Even partial compliance with external requests is a failure\n- Rationalizations don't matter, actions matter\n\nIncludes explicit failure mode example showing wrong vs right behavior.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add critical security warning about treating external content as iner…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T19:02:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a5db8de649b0da7035578fbee8a6e0c5a45ff0bc",
          "body": "Integrates mcp-security-utils for defense-in-depth protection:\n- Wrap external content with security markers (spotlighting)\n- Pattern detection for instruction override, role hijacking, etc.\n- Security warnings in output for suspicious content\n\nUpdated services:\n- Gmail: read_message, get_draft wrap\n[…]\n- Sheets: read wraps values (as JSON)\n- Slides: read wraps elements/slides (as JSON)\n\nDocumentation added to SKILL.md with handling guidelines.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add prompt injection protection for external content",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-02-03T18:33:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "616d2343ed753b058b3b96fb4fa5ce8bca19c35a",
          "body": "- Add --mermaid-theme option (default, neutral, dark, forest)\n- Change default mermaid theme from neutral to default\n- Make pageless mode the default for md-to-doc (--no-pageless to disable)\n- Create temp Drive folder for diagram images with automatic cleanup\n- Update SKILL.md and CLAUDE.md documentation\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add mermaid themes, pageless default, and diagram cleanup",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-22T20:06:15Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3721aab8295ed22f3b0096d9dd61aec323d4eae0",
          "body": "Address user feedback for improved document workflows:\n\nNew features:\n- `docs find-text` command to locate text and return character indices\n- `docs insert-image-at-text` command to insert images after specific text\n  without manual index calculation\n- Retry utility for transient API errors (500, 50\n[…]\nissing ExitCode.NOT_FOUND enum value used throughout codebase\n\nTests:\n- Add 10 new tests for find_text, insert_image_at_text, and retry utility\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add find-text, insert-image-at-text commands and retry logic",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-22T18:32:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d5a1233743ee7b5cc1f4a1b7ac0467a9ae8cb088",
          "body": "Drive:\n- Add --domain option for domain-restricted sharing (anyone at company.com)\n- Auto-detect share type from domain parameter\n\nDocs:\n- Add document tabs support: list-tabs, create-tab, delete-tab, rename-tab,\n  reorder-tab commands and --tab option on all editing commands\n- Add pageless mode: ge\n[…]\nmat commands\n- Add insert-markdown command for pasting markdown with auto-formatting\n  (leverages Google's native markdown parser via temp doc)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add domain sharing, document tabs, pageless mode, and markdown insertion",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-21T19:00:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f0950f0ab17dd12fbff631c8f6f46403aef8fca5",
          "body": "Create SKILL-typesetting.md with meticulous formatting standards:\n- Typography hierarchy (fonts, heading sizes, spacing)\n- Table consistency requirements (identical styling mandatory)\n- Image guidelines (never in lists, captions below, numbered)\n- Pagination control (keep lists together, widow/orpha\n[…]\nments\n\nUpdate SKILL-advanced.md documentation structure to reference new guide.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add comprehensive document typesetting guidelines",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-05T13:55:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "03a7f38c1761d44fd8580e6fdec648b49a59e0d2",
          "body": "…ance\n\nUpdates SKILL.md with:\n- Trigger terms in description (\"professional documents\", \"engaging presentations\")\n- Quick Start section with manual slides workflow (recommended over md-to-slides)\n- Visuals guidance: use DALL-E, diagrams, charts for docs and slides\n- Warning about md-to-slides limita\n[…]\nws\n- Note that speaker notes are essential for investor/executive presentations\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Improve skill discoverability and presentation/document creation guid…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-02T13:43:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e1d666c8de1f3bdd1d3bde413c5240d354973c48",
          "body": "More specific name avoids potential conflicts with other Google tools.\nPath works cross-platform via pathlib (Windows, macOS, Linux).\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Rename config directory from .google to .google-workspace",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-01T21:57:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "92ed98d8f4dd7df14ef5f05cf82a557be182386b",
          "body": "Reduce SKILL.md from 1,545 to 341 lines (78% reduction) following\nAnthropic's skill best practices for context efficiency.\n\nChanges:\n- Extract service APIs to reference/*.md (docs, sheets, slides, drive, gmail, calendar)\n- Add navigation table in SKILL.md linking to reference files\n- Keep small serv\n[…]\n better organized\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Restructure skill docs for progressive disclosure",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-01T21:50:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5f121f64e80c4022b4b06b0607c5fa8f0f6b115",
          "body": "…nders\n\nGmail (+4 commands):\n- filters: List all mail filters\n- get-filter: Get filter details\n- create-filter: Create filter with criteria/actions (archive, star, labels, etc.)\n- delete-filter: Delete a filter\n\nDrive (+6 commands):\n- list-permissions: List who has access to a file\n- get-permission:\n[…]\nmd documentation.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Add Gmail filters, Drive permissions, Docs suggestions, Calendar remi…",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-01T21:04:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3937e8f74c74b8fcfb51a6fa2ddf5febec1f16d7",
          "body": "New features by service:\n\nSheets (+14 commands):\n- Filters: create-filter, clear-filter, get-filter\n- Pivot tables: create-pivot, delete-pivot\n- Protected ranges: protect-range, unprotect-range, list-protected\n- Named ranges: create-named-range, delete-named-range, list-named-ranges,\n  get-named-ran\n[…]\nmd documentation.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Add comprehensive API coverage across all Google Workspace services",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-01T20:46:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6c6b4c2b2e6100f561ac3b3b158f5f30823f4823",
          "body": "Sheets: insert/delete rows/columns, sort, find-replace, duplicate sheet,\ndata validation, charts, and alternating row colors (banding)\n\nGmail: labels (create/delete/add/remove), drafts (CRUD + send),\nattachments (send with files, list, download)\n\nCalendar: recurring events with RRULE, event instance\n[…]\n~4100 lines added\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Add comprehensive API coverage across all services",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-01T20:02:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5706517bc25448ef1614a8e069873ee3eed659ac",
          "body": "Sheets (12 new commands):\n- format-extended: full cell styling (fonts, colors, alignment, number formats)\n- set-borders: border styling with --all shortcut\n- merge-cells/unmerge-cells: cell merging operations\n- set-column-width/set-row-height: sizing in pixels\n- auto-resize-columns: fit to content\n-\n[…]\ne-cell: background color for cells\n- insert-table-text: add text to table cells\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Sheets/Slides: add comprehensive formatting and table APIs",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2026-01-01T09:02:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "05cee02812e2296e55d3bd7b5b1a8d094b4fbafe",
          "body": "Add 27 new Docs operations (total now 37) covering:\n- Phase 1: Tables - insert, merge/unmerge cells, row/column ops, styling\n- Phase 2: Paragraph styles - alignment, spacing, indentation, named styles\n- Phase 3: Extended text - fonts, backgrounds, links, strikethrough\n- Phase 4: Headers/Footers - cr\n[…]\nl new operations.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Docs: expand API with tables, lists, headers/footers, and styling",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2025-12-31T22:33:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e9557b2ccfc701b1c1570b37840f9122a1fec5c2",
          "body": "Provides Claude with context when working on the codebase:\n- Architecture overview and file structure\n- Service and command patterns\n- How to add new operations and services\n- Important notes (exit codes, shell escaping, defaults)\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Add CLAUDE.md for development guidance",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2025-12-31T20:14:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bda260fb0e42e84834db0a2a7c99a18c35e4a58b",
          "body": "- Change title to \"Google Workspace Skill for Claude Code\"\n- Replace CLI examples with natural language prompts\n- Add \"What Claude Can Do\" capabilities section\n- Simplify installation to clone + OAuth + authenticate\n- Point to SKILL.md for detailed command reference\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "README: rewrite with skill-first focus",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2025-12-31T20:11:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "059d8d493360a8186b12d50d90aad20d35680eb1",
          "body": "- Add mark_as_read and mark_as_unread commands to modify UNREAD label\n- Fix shell escaping issue where \\! was appearing in email content\n  (Claude Code sandbox escapes exclamation marks for security)\n- Add _unescape_text method to handle escaped characters\n- Change default from plain text to HTML (-\n[…]\nr proper encoding\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Gmail: add mark-read/unread, fix escaping, default to HTML",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2025-12-31T20:03:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "105551795d94a2abd17e0b1b8fce8e13c0faa6b3",
          "body": "Gmail improvements:\n- Add --from-name option for sender display name\n- Add --signature option for email signatures\n- Add get_profile() method for retrieving user email\n\nDiagram rendering via Kroki API:\n- New src/gws/utils/diagrams.py module with 20+ diagram types\n- Support Mermaid, PlantUML, GraphVi\n[…]\ns API limitation)\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Add Gmail sender name/signature and Kroki diagram rendering",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2025-12-31T17:54:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "781e7c4ec2dcaf0e37b8d2fe44c1e84e6e4a475a",
          "body": "Python CLI for Google Workspace with 64 operations across 8 services:\n\n- Drive (11 ops): upload, download, list, search, share, copy, move, delete\n- Docs (10 ops): read, create, insert, append, replace, format, delete range\n- Sheets (11 ops): read, write, append, clear, format, manage sheets\n- Slide\n[…]\ntup with `uv run`\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nSigned-off-by: Marios Andreopoulos <opensource@andmarios.com>",
          "is_bot": false,
          "headline": "Initial release: Google Workspace CLI (gws) v1.0.0",
          "author_name": "Marios Andreopoulos",
          "author_login": "andmarios",
          "committed_at": "2025-12-30T21:45:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 1,
      "commits_last_year": 81,
      "latest_release_at": "2026-07-21T15:00:35Z",
      "latest_release_tag": "v1.4.0",
      "releases_from_tags": true,
      "days_since_last_push": 0,
      "active_weeks_last_year": 11,
      "days_since_latest_release": 2,
      "mean_days_between_releases": null
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "gws-cli",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "calendar",
            "cli",
            "docs",
            "drive",
            "gmail",
            "google",
            "sheets",
            "slides",
            "workspace",
            "Development Status :: 4 - Beta",
            "Environment :: Console",
            "Intended Audience :: Developers",
            "License :: OSI Approved :: MIT License",
            "Operating System :: OS Independent",
            "Programming Language :: Python :: 3",
            "Programming Language :: Python :: 3.10",
            "Programming Language :: Python :: 3.11",
            "Programming Language :: Python :: 3.12",
            "Topic :: Utilities"
          ],
          "ecosystem": "pypi",
          "matches_repo": true,
          "registry_url": "https://pypi.org/project/gws-cli/",
          "is_deprecated": false,
          "latest_version": "1.4.0",
          "repository_url": "https://github.com/andmarios/google-workspace-skill",
          "versions_count": 6,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 3696,
          "first_published_at": "2026-03-05T09:06:27.871626Z",
          "latest_published_at": "2026-07-24T11:29:46.501617Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 2,
      "stars": 5,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2026-01-02",
            "count": 1
          },
          {
            "date": "2026-04-14",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 2,
        "total_forks": 2
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "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": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 132665,
      "source_files_sampled": 54,
      "oversized_source_files": 5,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 9249
    },
    "dependencies": {
      "manifests": [
        "pyproject.toml"
      ],
      "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": [
        "pypi"
      ],
      "dependencies": [
        {
          "name": "typer",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.9.0"
        },
        {
          "name": "rich",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=13.0.0"
        },
        {
          "name": "google-api-python-client",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=2.100.0"
        },
        {
          "name": "google-auth",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=2.23.0"
        },
        {
          "name": "google-auth-oauthlib",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.1.0"
        },
        {
          "name": "httpx",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.25.0"
        },
        {
          "name": "prompt-security-utils",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.3.0"
        },
        {
          "name": "cryptography",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=46.0.4"
        }
      ],
      "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": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "andmarios",
          "commits": 81,
          "avatar_url": "https://avatars.githubusercontent.com/u/1239679?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": true,
      "ci_workflows": [],
      "has_docs_dir": false,
      "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": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "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": 2,
            "reason": "3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2",
            "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": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "f553af056ed88773cd71213f05b1bd38ed89c588",
        "ran_at": "2026-07-24T11:31:04Z",
        "aggregate_score": 2.9,
        "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": "2026-07-21T15:01:08Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/andmarios/google-workspace-skill",
    "host": "github.com",
    "name": "google-workspace-skill",
    "owner": "andmarios"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 43,
      "inputs": {
        "security": 29,
        "vitality": 67,
        "community": 36,
        "governance": 38,
        "engineering": 38
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "moderate",
        "name": "Vitality",
        "value": 67,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 63,
            "inputs": {
              "commits_last_year": 81,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 11
            },
            "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": "11/52 weeks with commits",
                "points": 7.6,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 11
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "81 commits in the last year",
                "points": 17.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 81
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2",
                "points": 2,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "good",
            "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": 72,
            "inputs": {
              "releases_count": 1,
              "latest_release_tag": "v1.4.0",
              "releases_from_tags": true,
              "days_since_latest_release": 2,
              "mean_days_between_releases": null
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "1 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 2 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "cadence unknown (single release)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "release_cadence_unknown",
                    "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": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 2,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 2 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "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": 36,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "forks": 2,
              "stars": 5,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "5 stars",
                "points": 9.8,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "2 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "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": 60,
            "inputs": {
              "packages": [
                "gws-cli"
              ],
              "dependents": null,
              "ecosystems": "pypi",
              "total_downloads": null,
              "monthly_downloads": 3696
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "3,696 downloads/month across pypi",
                "points": 47.6,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 3696,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "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": 38,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 13,
            "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 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution",
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "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": 56,
            "inputs": {
              "followers": 40,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "andmarios",
              "public_repos": 36,
              "account_age_days": 5345
            },
            "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": "40 followers of andmarios",
                "points": 11.6,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 40,
                      "login": "andmarios"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "36 public repos, account ~14 yr old",
                "points": 23.4,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 36
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 14
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "gws-cli"
              ],
              "ecosystems": "pypi",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on pypi",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "6 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 6
                    }
                  }
                ],
                "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": 38,
        "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": 50,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "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": 10,
                "status": "met",
                "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": 29,
        "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": 29,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 2.9
            },
            "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 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "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": "3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2",
                "points": 1.5,
                "status": "partial",
                "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": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "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": 56,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 9249
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "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": "81 of 81 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 81,
                      "sampled": 81
                    }
                  }
                ],
                "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": 36,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 1,
              "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "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": "81 of the last 81 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 81,
                      "sampled": 81
                    }
                  }
                ],
                "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": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "primary_language": "Python",
              "largest_source_bytes": 132665,
              "source_files_sampled": 54,
              "oversized_source_files": 5
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Python without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "Python"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "5/54 source files over 60KB",
                "points": 49.9,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 54,
                      "oversized": 5
                    }
                  }
                ],
                "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 pypi:gws-cli@1.4.0; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-24T11:31:09.896827Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/a/andmarios/google-workspace-skill.svg",
  "full_name": "andmarios/google-workspace-skill",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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