Звіт у форматі 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"
}