[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6990NBBAWKRJRGEJ36NAGA9":3,"skill-same:01M6990NBBAWKRJRGEJ36NAGA9":177},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":52,"commitSha":53,"skillDirectory":54,"forksCount":55,"repositoryHtmlUrl":56,"repositoryHomepageUrl":6,"ownerHtmlUrl":57,"ownerBlogUrl":58,"ownerDescription":59,"updatedAt":60,"install":61,"resources":74},"01M6990NBBAWKRJRGEJ36NAGA9","cloud-logging-finops",null,"Audits Cloud Logging costs for a Google Cloud project: the charges for log entries written to log buckets, the services, log streams and severities that drive them, and the log sinks that route them. Reconciles Cloud Billing export costs with Cloud Monitoring volume metrics, and generates a FinOps report with charts and copy-paste exclusion filters. Use when auditing Cloud Logging spend, finding logging waste, identifying top logging contributors, generating log cost reduction reports, or creating log sink exclusion filters. Don't use for querying log entries (use cloud-logging-query-generation), configuring Cloud Monitoring alerts, or querying metrics\u002Ftraces.","google\u002Fskills","google","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1342004?v=4","01M698VYEFDM0VJBZDYYJ2T83S","Google","01M698WR0H76ENHE587T9EJT89",24122,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,9,39,40,41,42,43],"cloud logging finops","finops","logging","cloud","reports","when","top","paste","streams","billing","project","alerts","volume","route","query","filters","log","Charts","monitoring","google cloud","2026-11-10 10:12:30",false,"---\nname: cloud-logging-finops\nmetadata:\n  version: \"1.0.1\"\n  category: CloudObservabilityAndMonitoring\ndescription: >-\n  Audits Cloud Logging costs for a Google Cloud project: the charges for log entries written to log buckets, the services, log streams and severities that drive them, and the log sinks that route them. Reconciles Cloud Billing export costs with Cloud Monitoring volume metrics, and generates a FinOps report with charts and copy-paste exclusion filters. Use when auditing Cloud Logging spend, finding logging waste, identifying top logging contributors, generating log cost reduction reports, or creating log sink exclusion filters. Don't use for querying log entries (use cloud-logging-query-generation), configuring Cloud Monitoring alerts, or querying metrics\u002Ftraces.\n---\n\n# Cloud Logging Finops\n\n**Non-interactive runs.** When no user can answer (e.g. a scheduled or\nautomated run), ask nothing: audit the project named in the request, or the\nactive gcloud project; use `--billing-mode=search`; cover all five report topics\n(Step 2.5); and never enable an API or upgrade a log bucket. Put anything that\nneeded a user (a disabled API, a missing role, the upgrade advisory) in the\nreport instead.\n\n## Usage Attribution\n\n**MUST READ**: Before executing any `gcloud`, REST API, or MCP command, you\nMUST read and follow the instructions in\n[Usage Attribution](references\u002Fattribution.md).\n\n## Step 0: Locate the Cloud Billing Export\n\nThe audit covers one Google Cloud project, `{project_id}`: the project the user\nnames or, if they don't name one, the active gcloud project (`gcloud config get\nproject`), confirmed with the user.\n\nDiscover everything else (log buckets, Observability Analytics, sinks,\nexclusions, metrics) yourself; never ask the user about those. The billing export is the\nexception: finding it unaided can mean scanning every project on the billing\naccount, so ask once, before running anything, and don't start a search until\nthe user has chosen answer 3 (single-select, using the host's question tool if\nit has one):\n\n> **Do you know where the Cloud Billing export for `{project_id}` is?**\n>\n> 1.  **Yes** — here it is *(the BigQuery table ID `project.dataset.table`, or\n>     just the project and dataset)*\n> 2.  **There's no billing export** for this project\n> 3.  **No \u002F not sure** — search for it *(seconds on a small project; on a large\n>     billing account it can take a long time)*\n\nAnswer | Flags                                                                                         | Cost figures\n------ | --------------------------------------------------------------------------------------------- | ------------\n1      | `--billing-mode=explicit` plus `--billing-table` (or `--billing-project`\u002F`--billing-dataset`) | invoiced\n2      | `--billing-mode=none`                                                                         | list-price estimates\n3      | `--billing-mode=search` *(default)*                                                           | invoiced if found, else estimates\n\nAnswer 3's search has no time limit: it checks `{project_id}` first (usually\nunder 10 s, 1–2 min with many tables), then every project on its billing account\n(can take many minutes; progress prints every 30 s). Tell the user this before\nlaunching. If the wait is unacceptable, offer to switch to answer 1 (they look up\nthe table) or answer 2 (skip the export and use list-price estimates). Don't\nsuggest setting up an export to make the search faster.\n\nIf the search found an export, tell the user: *\"Next time, pass\n`--billing-table=\u003Ctable>` and discovery drops to about two seconds.\"*\n\n## Step 1: Environment Setup\n\nCheck these prerequisites before Step 2; fix only what is missing:\n\n*   **gcloud:** if `gcloud` is not installed, follow\n    https:\u002F\u002Fdocs.cloud.google.com\u002Fsdk\u002Fdocs\u002Finstall-sdk.md.txt.\n*   **Project:** run `gcloud config get project`; if it isn't `{project_id}`\n    (from Step 0), run `gcloud config set project {project_id}`.\n*   **Credentials:** the scripts use Application Default Credentials. Run\n    `gcloud auth application-default login`, or set\n    `GOOGLE_APPLICATION_CREDENTIALS` to a service account key.\n*   **Billing:** the project must have an active billing account attached.\n*   **APIs:** don't enable APIs up front; the Logging, Monitoring, BigQuery and\n    Observability APIs are on by default in new projects. Only if the collector\n    reports an API as disabled (`SERVICE_DISABLED`, \"has not been used in\n    project\"), name it, ask the user, and on approval run `gcloud services\n    enable {api} --project={project_id}` (tagged as described below):\n    *   `logging`, `monitoring`: required; without them there is nothing to\n        audit.\n    *   `bigquery`: invoiced costs from the billing export.\n    *   `observability`: resolves the project's default log scope, so log\n        samples match what Logs Explorer shows.\n    *   `cloudasset`, `cloudbilling`: only answer 3's search across the billing\n        account.\n\nIAM roles for the identity running the audit. The skill never grants roles: the\nscripts run with the user's own credentials and read only what those\ncredentials can. When a step fails on permissions, its advisory names the step;\ntell the user which role below it needs:\n\nRole                                                                 | Needed for\n-------------------------------------------------------------------- | ----------\n`roles\u002Flogging.viewer`, `roles\u002Fmonitoring.viewer`                    | Every audit: log buckets, sinks, log samples, volume metrics\n`roles\u002Fbigquery.jobUser`, `roles\u002Fbigquery.dataViewer` (on the export dataset) | Invoiced costs from the billing export\n`roles\u002Flogging.viewAccessor` on log views in other projects        | Reading samples through a default log scope that includes them\n`roles\u002Fcloudasset.viewer`, `roles\u002Fbilling.viewer` (billing account)  | `--billing-mode=search` across the billing account\n`roles\u002Flogging.configWriter`                                         | Only the optional Observability Analytics upgrade (Step 3B)\n\n```bash\n[ -f \u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython ] || (uv venv \u002Ftmp\u002Ffinops_venv && uv pip install -r scripts\u002Frequirements.txt --python \u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython)\n```\n\nThe bundled scripts tag their Google Cloud API requests. For commands you run\nyourself, follow [Usage Attribution](references\u002Fattribution.md).\n\n## Step 2: Data Collection\n\nStart the collector below as a background process (it takes from seconds to\nmany minutes), then go to Step 2.5 while it runs:\n\n```bash\n\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython scripts\u002Fcollect_logging_data.py \\\n  --project-id {project_id} --billing-mode={none|explicit|search}\n```\n\nOptional: `--billing-project`, `--billing-dataset`, `--billing-table` (e.g.\n`billing-proj.ds.gcp_billing_export_v1_XXXX` or a curated FinOps view).\n\nOutputs: `logging_usage_summary.json`, `monthly_details\u002F`, `service_details\u002F`,\nand `[FINOPS ADVISORY]` lines (see Step 3). The collector's output ends with a\n`[COLLECTION PROFILE]` table of per-stage timings; if the run took longer than\nthe times in Step 0, or the user asks why the audit took so long, read that\ntable before guessing.\n\n## Step 2.5: Ask What the Report Is For\n\nAlways ask this while the collector runs (multi-select). If the user skips it,\ncover all five topics:\n\n> **What should this report answer?**\n>\n> -   Where is the money going — attribution by service and stream\n> -   Is spend growing — trends and projection\n> -   What can I safely turn off — concrete savings actions\n> -   What are these logs actually saying — noisiest patterns and samples\n> -   Severity and audit-log posture\n\nThe user's choices decide which outputs you read in depth and what your\nsummary leads with; they never change what the collector gathers:\n\nInterest         | Read deeply\n---------------- | -----------\nAttribution      | `service_details\u002F*.json`, `daily_services`\nGrowth           | `monthly_details\u002F*.json`, `mom_patterns`, `cost_projection`\nSavings actions  | `reduction_actions`, `extraneous_spend`\nWhat logs say    | `severity_summary.samples_by_service`, `granular_analytics.top_signatures` (Observability Analytics only)\nSeverity \u002F audit | `severity_summary`, withheld-rule reasons\n\nYour narrative goes in `insights\u002Fexecutive_summary.html` (see\n[Executive Summary Authoring](references\u002Fexecutive_summary_authoring.md)).\nYou don't write the savings actions: the generated report's Cost Optimizer tab\nlists them from `reduction_actions`.\n\n> [!CAUTION] Never edit `assets\u002Freport_template.html`.\n\n## Step 3: Follow the Advisories\n\n### A. Tell the User What the Cost Figures Are Based On\n\n> [!IMPORTANT] Unless figures are invoiced (`billing_metadata.invoiced`), tell\n> the user in plain language where you looked, what you found, and what the\n> numbers are based on. Keep internals (stage numbers, mode names, HTTP codes,\n> \"quota project\", \"Cloud Asset Inventory\") in the log and\n> `billing_metadata.fallback_chain`.\n\n*   **Answer 1, the location gave no costs** (`explicit_table` or\n    `explicit_scope` step not `found`): the collector never searches beyond what\n    the user named. Tell them what was wrong, from the step's `detail` (no rows\n    for this project, no export table there, or the query failed), that costs\n    are list-price estimates, and offer to rerun with a corrected location or\n    with answer 3.\n*   **Answer 2** (`user_declared_no_export`): \"I didn't search — you told me\n    there's no billing export — so costs are list-price estimates, not invoiced\n    amounts.\" Never call a skipped search exhausted.\n*   **Answer 3, found nothing** (`billing_account` status `not_found`): \"I\n    searched this project and your billing account and found no billing export.\n    Costs are list-price estimates (quote each SKU's price and free tier from\n    `pricing.skus`) over a trailing 30 days.\" Only this case supports\n    recommending export setup. Cite the official pricing page\n    (https:\u002F\u002Fcloud.google.com\u002Fproducts\u002Fobservability\u002Fpricing) as the source of\n    list prices.\n*   **Answer 3, search failed on permissions** (any step status\n    `inconclusive`): tell the user the lookup couldn't complete, so costs are\n    estimates. Never tell them no billing export exists; the search didn't\n    finish.\n*   **Answer 3, this project's table rejected** (`local_project` status\n    `no_project_records`): \"This project has a billing export, but it holds no\n    records for this project, so I searched the rest of the billing account.\"\n    Then report the outcome of that wider search as above.\n*   **Partial history:** months are labelled `actual_bq_billing` or\n    `usage_estimated`; state the exact date boundary in the executive summary.\n\nWhen on list pricing, recommend export for accuracy: future audits would use the\nactual invoice, including discounts, over multiple months.\n\n### B. Observability Analytics\n\nObservability Analytics was formerly called Log Analytics; the scripts'\nadvisories and field names still use the old name.\n\n*   **Disabled:** present the advisory, including that upgrading the log bucket\n    is irreversible, then end your reply with a direct question, e.g. *\"Do you\n    want me to upgrade the `_Default` log bucket to Observability Analytics?\n    This can't be undone.\"* Telling the user how to run it themselves is not\n    asking. Only after they approve upgrading that log bucket, run `\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython\n    scripts\u002Fenable_log_analytics.py --project-id {project_id}`. The audit\n    proceeds on Cloud Monitoring either way.\n\n> [!CAUTION] Never run `enable_log_analytics.py` or `gcloud logging buckets\n> update --enable-analytics` in the same turn you raise the advisory, or on\n> general permission like \"do whatever you need\".\n\n*   **\u003C 24 hours old:** the 14-day Cloud Monitoring baseline is used until\n    samples accumulate (~1–2 hours).\n*   **1–13 days:** cite the sample window in the report.\n*   **≥ 14 days:** full SQL analytics.\n*   **`Representative logs unavailable` advisory:** samples are missing because\n    your environment can't read log entries (needs `roles\u002Flogging.viewer`), not\n    because streams are empty. Relay the error and role; per-stream detail is in\n    `severity_summary.sample_errors`.\n*   **Samples empty but the stream has volume:** samples are read through the\n    project's default log scope, like Logs Explorer\n    (`analytics_metadata.log_read_scope`). If its `source` is `project` and it\n    has a `note`, the scope couldn't be resolved, so logs held outside this\n    project's log buckets weren't read. Say that and relay the `note`; never say the\n    stream has no logs.\n\n### C. Measurement Integrity\n\n> [!CAUTION] Never quote cost or volume derived from Observability Analytics\n> payload byte sums; they overstate billed volume about 2x.\n\nQuestion                     | Source\n---------------------------- | ------\nCost, GiB ingested           | Billing export (`billing.query_logging_billing_costs`, `daily_gib`, `monthly_costs`)\nService mix                  | `logging.googleapis.com\u002Fbilling\u002Fbytes_ingested` (`resource_type`)\nLog stream \u002F severity volume | `logging.googleapis.com\u002Fbyte_count` (`log`, `severity`)\nSeverity mix, entry content  | Observability Analytics SQL (`constants.PAYLOAD_BYTES_SQL`)\n\n*   Totals come from the invoice when it exists; metrics only supply shares.\n    Never put a metric-derived total next to an invoiced one.\n*   `byte_count` (received) and `billing\u002Fbytes_ingested` (billed) differ by\n    ~1.5x or more; never divide one by the other.\n*   If `telemetry_integrity.status` is `degraded`, say dips on the listed days\n    look like a metric defect that won't self-correct, and repeat the limits in\n    `telemetry_integrity.note`. Never claim with certainty that nothing changed.\n*   A month with `is_partial: true` is month-to-date. Label it so, and never\n    call it a complete month or \"last month\".\n\n### D. Extraneous Spend\n\n`extraneous_spend.headline` is a conservative floor: the sum of the\n`reduction_actions.actions` with `counted: true` (duplicate bucket routing,\nflow-log sampling, DEBUG logs, stale exclusions), each priced on exactly what\nits remedy removes. Everything else is surfaced, never counted: over-retention\n(not quantified), sampled exclusion rules (estimates), and Data Access audit\nlogs (in `withheld`).\n\n1.  Report it as a floor (`≥ X%`), never a point estimate or \"up to\".\n2.  If `status` is `insufficient_data`, give no figure — not a guess, a\n    benchmark, or $0.\n3.  Quote any action's `flag` verbatim; it is written for the reader.\n4.  Uncounted actions and `uncounted_total_pct` may be mentioned as upside,\n    never added to the headline.\n5.  If `headline.exceeds_sanity_ceiling`, say the headline isn't reliable, name\n    the largest counted action, and flag it for manual review. Offer no number.\n6.  If `inventory_unavailable` is non-empty, say log sink, exclusion and\n    flow-log actions weren't checked; never say none exist.\n7.  Whenever Data Access audit logs come up (a `withheld` entry, or the user\n    names them), say they are left out of the number because they need a\n    compliance decision: disabling or excluding them is frequently prohibited\n    by compliance or security policy, so the owner must confirm before acting.\n\n### E. Exclusion Filters and Actions\n\n*   Only Cost Optimizer actions carry filters and savings; Service Details\n    volumes are not savings. Report `sample_coverage.shown_pct`.\n*   Quote an action's monthly figures (`monthly_gib`, `monthly_usd`), never a\n    rule's sample-window GiB (`granular_analytics.exclusion_candidates`).\n*   `rule_scope: stream` drops every log entry of that severity in the stream; say so.\n*   If `refused_claims` is non-empty, name the streams the safety gate removed.\n\nNever offered as actions: `CRITICAL`\u002F`ALERT`\u002F`EMERGENCY` (incident signal), free\n`_Required` streams ($0, audit retention), Data Access audit logs (often\ncompliance-mandated; report, never count), and streams with no measured volume.\n\n> [!CAUTION] Hand-written exclusion filters must: include a severity predicate\n> (`severity = \"DEFAULT\"` for DEFAULT — omitting it matches everything); use the\n> URL-encoded log ID (`compute.googleapis.com%2Ffirewall`); never embed\n> unescaped log text or rotating tokens (UUIDs, IPs, long integers, times) in a\n> regex; and respect the list above.\n\n## Step 4: Build and Deliver the Report\n\n```bash\n\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython scripts\u002Fbuild_report.py --summary logging_usage_summary.json --insights-dir insights\u002F --output log_usage_report.html\n```\n\n`build_report.py` writes an executive summary unless you provide\n`insights\u002Fexecutive_summary.html`.\n\nGive the user one link that, when clicked, opens the fully rendered report — not\nraw HTML, not a missing file — from wherever the user actually is. Confirm that\nwill happen before you post it.\n\nThen list what they can explore (charts, service drilldowns, ranked actions with\ncopyable filters, ✓ Prove It drawers) and suggest 3–4 follow-up questions drawn\nfrom this project's data, phrased to ask as-is.\n\nIf the user asked something specific, answer it directly with both GiB and USD,\nfrom `monthly_aggregations` (`latest_complete_month` names the newest whole\nmonth; each month's `top_service` is its Top Cost Driver), `mom_patterns`,\n`cost_projection`, `trailing_30d_summary` (its `top_driver` is the report's Top\nCost Driver without an invoice), `granular_analytics` (present only when\nObservability Analytics ran), or the per-service\u002Fmonth detail files.\n\n## Step 5: Follow-Up Questions\n\n**Phase 1 (default):** answer from the JSON on disk in a few sentences or a\nsmall table, name what the data can't settle, then stop and offer 3–4 ways to go\ndeeper. Don't re-run collection or re-query sources.\n\nQuestion about         | Read\n---------------------- | ----\nA severity             | `severity_summary`, `granular_analytics.top_signatures` for that severity\nA service              | `service_details\u002F{service}.json`, `top_signatures` and `top_log_names` for it\nAn optimization action | its entry in `reduction_actions.actions` (`claims`, `refused_claims`, `flag`, `counted`)\n\n**Phase 2 (only after the user picks a direction):** go as deep as it needs. Run\nObservability Analytics SQL against `analytics_metadata.table_name`, the `_AllLogs` view\nthe collector measured. Step 3 still applies.\n\n## Step 6: Prove It\n\n`provenance.claims[\u003Cid>]` records each headline figure's `formula`, `sources`\n(exact query, Google Cloud console link, steps; only the 10 largest streams per action),\nknown `differences` from the console, and runnable `checks` (covering every\nstream). Ids include `latest_complete_spend`, `mtd_run_rate`,\n`trailing_30d_volume`, `estimated_run_rate`, `top_cost_driver`,\n`extraneous_spend`, `severity_costs`, `service_mix`, `action::\u003Caction id>`. A\nclaim built from others lists them in `see_also` (`extraneous_spend` → its\ncounted actions); prove those too, and `verify_claim.py` re-checks them with it.\n\nWhen asked to prove a figure:\n\n1.  **Now, from disk:** walk the formula with its inputs; list each source with\n    its Google Cloud console link, its query exactly as recorded, and steps; then the\n    `differences`.\n2.  **Same turn, in the background:** run `\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython\n    scripts\u002Fverify_claim.py --summary \u003Csummary> --claim \"\u003Cid>\"`; don't wait.\n3.  **When it finishes:** a table (check | report | live | Δ | ✓\u002F△\u002F✗) and a\n    one-line verdict. Explain △ with the recorded `differences`; give ✗ causes\n    in one line each.\n\n> [!CAUTION] Prove It is the only request that may re-query sources, and only\n> via `verify_claim.py`. Don't re-run collection or alter the recorded queries.\n\nDisclose when relevant: whether the claim was priced (`pricing.mode`) `per_sku`\n(each SKU's price and free tier in `pricing.skus`) or `blended` (reason in\n`pricing.notes`); that service and severity figures exclude credits; and, if\n`cross_project_billing`, that reproducing it needs `roles\u002Fbigquery.dataViewer`\non the billing export dataset and `roles\u002Fbigquery.jobUser`.\n","# Cloud Logging Finops\n\n**Non-interactive runs.** When no user can answer (e.g. a scheduled or\nautomated run), ask nothing: audit the project named in the request, or the\nactive gcloud project; use `--billing-mode=search`; cover all five report topics\n(Step 2.5); and never enable an API or upgrade a log bucket. Put anything that\nneeded a user (a disabled API, a missing role, the upgrade advisory) in the\nreport instead.\n\n## Usage Attribution\n\n**MUST READ**: Before executing any `gcloud`, REST API, or MCP command, you\nMUST read and follow the instructions in\n[Usage Attribution](references\u002Fattribution.md).\n\n## Step 0: Locate the Cloud Billing Export\n\nThe audit covers one Google Cloud project, `{project_id}`: the project the user\nnames or, if they don't name one, the active gcloud project (`gcloud config get\nproject`), confirmed with the user.\n\nDiscover everything else (log buckets, Observability Analytics, sinks,\nexclusions, metrics) yourself; never ask the user about those. The billing export is the\nexception: finding it unaided can mean scanning every project on the billing\naccount, so ask once, before running anything, and don't start a search until\nthe user has chosen answer 3 (single-select, using the host's question tool if\nit has one):\n\n> **Do you know where the Cloud Billing export for `{project_id}` is?**\n>\n> 1.  **Yes** — here it is *(the BigQuery table ID `project.dataset.table`, or\n>     just the project and dataset)*\n> 2.  **There's no billing export** for this project\n> 3.  **No \u002F not sure** — search for it *(seconds on a small project; on a large\n>     billing account it can take a long time)*\n\nAnswer | Flags                                                                                         | Cost figures\n------ | --------------------------------------------------------------------------------------------- | ------------\n1      | `--billing-mode=explicit` plus `--billing-table` (or `--billing-project`\u002F`--billing-dataset`) | invoiced\n2      | `--billing-mode=none`                                                                         | list-price estimates\n3      | `--billing-mode=search` *(default)*                                                           | invoiced if found, else estimates\n\nAnswer 3's search has no time limit: it checks `{project_id}` first (usually\nunder 10 s, 1–2 min with many tables), then every project on its billing account\n(can take many minutes; progress prints every 30 s). Tell the user this before\nlaunching. If the wait is unacceptable, offer to switch to answer 1 (they look up\nthe table) or answer 2 (skip the export and use list-price estimates). Don't\nsuggest setting up an export to make the search faster.\n\nIf the search found an export, tell the user: *\"Next time, pass\n`--billing-table=\u003Ctable>` and discovery drops to about two seconds.\"*\n\n## Step 1: Environment Setup\n\nCheck these prerequisites before Step 2; fix only what is missing:\n\n*   **gcloud:** if `gcloud` is not installed, follow\n    https:\u002F\u002Fdocs.cloud.google.com\u002Fsdk\u002Fdocs\u002Finstall-sdk.md.txt.\n*   **Project:** run `gcloud config get project`; if it isn't `{project_id}`\n    (from Step 0), run `gcloud config set project {project_id}`.\n*   **Credentials:** the scripts use Application Default Credentials. Run\n    `gcloud auth application-default login`, or set\n    `GOOGLE_APPLICATION_CREDENTIALS` to a service account key.\n*   **Billing:** the project must have an active billing account attached.\n*   **APIs:** don't enable APIs up front; the Logging, Monitoring, BigQuery and\n    Observability APIs are on by default in new projects. Only if the collector\n    reports an API as disabled (`SERVICE_DISABLED`, \"has not been used in\n    project\"), name it, ask the user, and on approval run `gcloud services\n    enable {api} --project={project_id}` (tagged as described below):\n    *   `logging`, `monitoring`: required; without them there is nothing to\n        audit.\n    *   `bigquery`: invoiced costs from the billing export.\n    *   `observability`: resolves the project's default log scope, so log\n        samples match what Logs Explorer shows.\n    *   `cloudasset`, `cloudbilling`: only answer 3's search across the billing\n        account.\n\nIAM roles for the identity running the audit. The skill never grants roles: the\nscripts run with the user's own credentials and read only what those\ncredentials can. When a step fails on permissions, its advisory names the step;\ntell the user which role below it needs:\n\nRole                                                                 | Needed for\n-------------------------------------------------------------------- | ----------\n`roles\u002Flogging.viewer`, `roles\u002Fmonitoring.viewer`                    | Every audit: log buckets, sinks, log samples, volume metrics\n`roles\u002Fbigquery.jobUser`, `roles\u002Fbigquery.dataViewer` (on the export dataset) | Invoiced costs from the billing export\n`roles\u002Flogging.viewAccessor` on log views in other projects        | Reading samples through a default log scope that includes them\n`roles\u002Fcloudasset.viewer`, `roles\u002Fbilling.viewer` (billing account)  | `--billing-mode=search` across the billing account\n`roles\u002Flogging.configWriter`                                         | Only the optional Observability Analytics upgrade (Step 3B)\n\n```bash\n[ -f \u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython ] || (uv venv \u002Ftmp\u002Ffinops_venv && uv pip install -r scripts\u002Frequirements.txt --python \u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython)\n```\n\nThe bundled scripts tag their Google Cloud API requests. For commands you run\nyourself, follow [Usage Attribution](references\u002Fattribution.md).\n\n## Step 2: Data Collection\n\nStart the collector below as a background process (it takes from seconds to\nmany minutes), then go to Step 2.5 while it runs:\n\n```bash\n\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython scripts\u002Fcollect_logging_data.py \\\n  --project-id {project_id} --billing-mode={none|explicit|search}\n```\n\nOptional: `--billing-project`, `--billing-dataset`, `--billing-table` (e.g.\n`billing-proj.ds.gcp_billing_export_v1_XXXX` or a curated FinOps view).\n\nOutputs: `logging_usage_summary.json`, `monthly_details\u002F`, `service_details\u002F`,\nand `[FINOPS ADVISORY]` lines (see Step 3). The collector's output ends with a\n`[COLLECTION PROFILE]` table of per-stage timings; if the run took longer than\nthe times in Step 0, or the user asks why the audit took so long, read that\ntable before guessing.\n\n## Step 2.5: Ask What the Report Is For\n\nAlways ask this while the collector runs (multi-select). If the user skips it,\ncover all five topics:\n\n> **What should this report answer?**\n>\n> -   Where is the money going — attribution by service and stream\n> -   Is spend growing — trends and projection\n> -   What can I safely turn off — concrete savings actions\n> -   What are these logs actually saying — noisiest patterns and samples\n> -   Severity and audit-log posture\n\nThe user's choices decide which outputs you read in depth and what your\nsummary leads with; they never change what the collector gathers:\n\nInterest         | Read deeply\n---------------- | -----------\nAttribution      | `service_details\u002F*.json`, `daily_services`\nGrowth           | `monthly_details\u002F*.json`, `mom_patterns`, `cost_projection`\nSavings actions  | `reduction_actions`, `extraneous_spend`\nWhat logs say    | `severity_summary.samples_by_service`, `granular_analytics.top_signatures` (Observability Analytics only)\nSeverity \u002F audit | `severity_summary`, withheld-rule reasons\n\nYour narrative goes in `insights\u002Fexecutive_summary.html` (see\n[Executive Summary Authoring](references\u002Fexecutive_summary_authoring.md)).\nYou don't write the savings actions: the generated report's Cost Optimizer tab\nlists them from `reduction_actions`.\n\n> [!CAUTION] Never edit `assets\u002Freport_template.html`.\n\n## Step 3: Follow the Advisories\n\n### A. Tell the User What the Cost Figures Are Based On\n\n> [!IMPORTANT] Unless figures are invoiced (`billing_metadata.invoiced`), tell\n> the user in plain language where you looked, what you found, and what the\n> numbers are based on. Keep internals (stage numbers, mode names, HTTP codes,\n> \"quota project\", \"Cloud Asset Inventory\") in the log and\n> `billing_metadata.fallback_chain`.\n\n*   **Answer 1, the location gave no costs** (`explicit_table` or\n    `explicit_scope` step not `found`): the collector never searches beyond what\n    the user named. Tell them what was wrong, from the step's `detail` (no rows\n    for this project, no export table there, or the query failed), that costs\n    are list-price estimates, and offer to rerun with a corrected location or\n    with answer 3.\n*   **Answer 2** (`user_declared_no_export`): \"I didn't search — you told me\n    there's no billing export — so costs are list-price estimates, not invoiced\n    amounts.\" Never call a skipped search exhausted.\n*   **Answer 3, found nothing** (`billing_account` status `not_found`): \"I\n    searched this project and your billing account and found no billing export.\n    Costs are list-price estimates (quote each SKU's price and free tier from\n    `pricing.skus`) over a trailing 30 days.\" Only this case supports\n    recommending export setup. Cite the official pricing page\n    (https:\u002F\u002Fcloud.google.com\u002Fproducts\u002Fobservability\u002Fpricing) as the source of\n    list prices.\n*   **Answer 3, search failed on permissions** (any step status\n    `inconclusive`): tell the user the lookup couldn't complete, so costs are\n    estimates. Never tell them no billing export exists; the search didn't\n    finish.\n*   **Answer 3, this project's table rejected** (`local_project` status\n    `no_project_records`): \"This project has a billing export, but it holds no\n    records for this project, so I searched the rest of the billing account.\"\n    Then report the outcome of that wider search as above.\n*   **Partial history:** months are labelled `actual_bq_billing` or\n    `usage_estimated`; state the exact date boundary in the executive summary.\n\nWhen on list pricing, recommend export for accuracy: future audits would use the\nactual invoice, including discounts, over multiple months.\n\n### B. Observability Analytics\n\nObservability Analytics was formerly called Log Analytics; the scripts'\nadvisories and field names still use the old name.\n\n*   **Disabled:** present the advisory, including that upgrading the log bucket\n    is irreversible, then end your reply with a direct question, e.g. *\"Do you\n    want me to upgrade the `_Default` log bucket to Observability Analytics?\n    This can't be undone.\"* Telling the user how to run it themselves is not\n    asking. Only after they approve upgrading that log bucket, run `\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython\n    scripts\u002Fenable_log_analytics.py --project-id {project_id}`. The audit\n    proceeds on Cloud Monitoring either way.\n\n> [!CAUTION] Never run `enable_log_analytics.py` or `gcloud logging buckets\n> update --enable-analytics` in the same turn you raise the advisory, or on\n> general permission like \"do whatever you need\".\n\n*   **\u003C 24 hours old:** the 14-day Cloud Monitoring baseline is used until\n    samples accumulate (~1–2 hours).\n*   **1–13 days:** cite the sample window in the report.\n*   **≥ 14 days:** full SQL analytics.\n*   **`Representative logs unavailable` advisory:** samples are missing because\n    your environment can't read log entries (needs `roles\u002Flogging.viewer`), not\n    because streams are empty. Relay the error and role; per-stream detail is in\n    `severity_summary.sample_errors`.\n*   **Samples empty but the stream has volume:** samples are read through the\n    project's default log scope, like Logs Explorer\n    (`analytics_metadata.log_read_scope`). If its `source` is `project` and it\n    has a `note`, the scope couldn't be resolved, so logs held outside this\n    project's log buckets weren't read. Say that and relay the `note`; never say the\n    stream has no logs.\n\n### C. Measurement Integrity\n\n> [!CAUTION] Never quote cost or volume derived from Observability Analytics\n> payload byte sums; they overstate billed volume about 2x.\n\nQuestion                     | Source\n---------------------------- | ------\nCost, GiB ingested           | Billing export (`billing.query_logging_billing_costs`, `daily_gib`, `monthly_costs`)\nService mix                  | `logging.googleapis.com\u002Fbilling\u002Fbytes_ingested` (`resource_type`)\nLog stream \u002F severity volume | `logging.googleapis.com\u002Fbyte_count` (`log`, `severity`)\nSeverity mix, entry content  | Observability Analytics SQL (`constants.PAYLOAD_BYTES_SQL`)\n\n*   Totals come from the invoice when it exists; metrics only supply shares.\n    Never put a metric-derived total next to an invoiced one.\n*   `byte_count` (received) and `billing\u002Fbytes_ingested` (billed) differ by\n    ~1.5x or more; never divide one by the other.\n*   If `telemetry_integrity.status` is `degraded`, say dips on the listed days\n    look like a metric defect that won't self-correct, and repeat the limits in\n    `telemetry_integrity.note`. Never claim with certainty that nothing changed.\n*   A month with `is_partial: true` is month-to-date. Label it so, and never\n    call it a complete month or \"last month\".\n\n### D. Extraneous Spend\n\n`extraneous_spend.headline` is a conservative floor: the sum of the\n`reduction_actions.actions` with `counted: true` (duplicate bucket routing,\nflow-log sampling, DEBUG logs, stale exclusions), each priced on exactly what\nits remedy removes. Everything else is surfaced, never counted: over-retention\n(not quantified), sampled exclusion rules (estimates), and Data Access audit\nlogs (in `withheld`).\n\n1.  Report it as a floor (`≥ X%`), never a point estimate or \"up to\".\n2.  If `status` is `insufficient_data`, give no figure — not a guess, a\n    benchmark, or $0.\n3.  Quote any action's `flag` verbatim; it is written for the reader.\n4.  Uncounted actions and `uncounted_total_pct` may be mentioned as upside,\n    never added to the headline.\n5.  If `headline.exceeds_sanity_ceiling`, say the headline isn't reliable, name\n    the largest counted action, and flag it for manual review. Offer no number.\n6.  If `inventory_unavailable` is non-empty, say log sink, exclusion and\n    flow-log actions weren't checked; never say none exist.\n7.  Whenever Data Access audit logs come up (a `withheld` entry, or the user\n    names them), say they are left out of the number because they need a\n    compliance decision: disabling or excluding them is frequently prohibited\n    by compliance or security policy, so the owner must confirm before acting.\n\n### E. Exclusion Filters and Actions\n\n*   Only Cost Optimizer actions carry filters and savings; Service Details\n    volumes are not savings. Report `sample_coverage.shown_pct`.\n*   Quote an action's monthly figures (`monthly_gib`, `monthly_usd`), never a\n    rule's sample-window GiB (`granular_analytics.exclusion_candidates`).\n*   `rule_scope: stream` drops every log entry of that severity in the stream; say so.\n*   If `refused_claims` is non-empty, name the streams the safety gate removed.\n\nNever offered as actions: `CRITICAL`\u002F`ALERT`\u002F`EMERGENCY` (incident signal), free\n`_Required` streams ($0, audit retention), Data Access audit logs (often\ncompliance-mandated; report, never count), and streams with no measured volume.\n\n> [!CAUTION] Hand-written exclusion filters must: include a severity predicate\n> (`severity = \"DEFAULT\"` for DEFAULT — omitting it matches everything); use the\n> URL-encoded log ID (`compute.googleapis.com%2Ffirewall`); never embed\n> unescaped log text or rotating tokens (UUIDs, IPs, long integers, times) in a\n> regex; and respect the list above.\n\n## Step 4: Build and Deliver the Report\n\n```bash\n\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython scripts\u002Fbuild_report.py --summary logging_usage_summary.json --insights-dir insights\u002F --output log_usage_report.html\n```\n\n`build_report.py` writes an executive summary unless you provide\n`insights\u002Fexecutive_summary.html`.\n\nGive the user one link that, when clicked, opens the fully rendered report — not\nraw HTML, not a missing file — from wherever the user actually is. Confirm that\nwill happen before you post it.\n\nThen list what they can explore (charts, service drilldowns, ranked actions with\ncopyable filters, ✓ Prove It drawers) and suggest 3–4 follow-up questions drawn\nfrom this project's data, phrased to ask as-is.\n\nIf the user asked something specific, answer it directly with both GiB and USD,\nfrom `monthly_aggregations` (`latest_complete_month` names the newest whole\nmonth; each month's `top_service` is its Top Cost Driver), `mom_patterns`,\n`cost_projection`, `trailing_30d_summary` (its `top_driver` is the report's Top\nCost Driver without an invoice), `granular_analytics` (present only when\nObservability Analytics ran), or the per-service\u002Fmonth detail files.\n\n## Step 5: Follow-Up Questions\n\n**Phase 1 (default):** answer from the JSON on disk in a few sentences or a\nsmall table, name what the data can't settle, then stop and offer 3–4 ways to go\ndeeper. Don't re-run collection or re-query sources.\n\nQuestion about         | Read\n---------------------- | ----\nA severity             | `severity_summary`, `granular_analytics.top_signatures` for that severity\nA service              | `service_details\u002F{service}.json`, `top_signatures` and `top_log_names` for it\nAn optimization action | its entry in `reduction_actions.actions` (`claims`, `refused_claims`, `flag`, `counted`)\n\n**Phase 2 (only after the user picks a direction):** go as deep as it needs. Run\nObservability Analytics SQL against `analytics_metadata.table_name`, the `_AllLogs` view\nthe collector measured. Step 3 still applies.\n\n## Step 6: Prove It\n\n`provenance.claims[\u003Cid>]` records each headline figure's `formula`, `sources`\n(exact query, Google Cloud console link, steps; only the 10 largest streams per action),\nknown `differences` from the console, and runnable `checks` (covering every\nstream). Ids include `latest_complete_spend`, `mtd_run_rate`,\n`trailing_30d_volume`, `estimated_run_rate`, `top_cost_driver`,\n`extraneous_spend`, `severity_costs`, `service_mix`, `action::\u003Caction id>`. A\nclaim built from others lists them in `see_also` (`extraneous_spend` → its\ncounted actions); prove those too, and `verify_claim.py` re-checks them with it.\n\nWhen asked to prove a figure:\n\n1.  **Now, from disk:** walk the formula with its inputs; list each source with\n    its Google Cloud console link, its query exactly as recorded, and steps; then the\n    `differences`.\n2.  **Same turn, in the background:** run `\u002Ftmp\u002Ffinops_venv\u002Fbin\u002Fpython\n    scripts\u002Fverify_claim.py --summary \u003Csummary> --claim \"\u003Cid>\"`; don't wait.\n3.  **When it finishes:** a table (check | report | live | Δ | ✓\u002F△\u002F✗) and a\n    one-line verdict. Explain △ with the recorded `differences`; give ✗ causes\n    in one line each.\n\n> [!CAUTION] Prove It is the only request that may re-query sources, and only\n> via `verify_claim.py`. Don't re-run collection or alter the recorded queries.\n\nDisclose when relevant: whether the claim was priced (`pricing.mode`) `per_sku`\n(each SKU's price and free tier in `pricing.skus`) or `blended` (reason in\n`pricing.notes`); that service and severity figures exclude credits; and, if\n`cross_project_billing`, that reproducing it needs `roles\u002Fbigquery.dataViewer`\non the billing export dataset and `roles\u002Fbigquery.jobUser`.\n",{"name":5,"metadata":49,"description":7},{"version":50,"category":51},"1.0.1","CloudObservabilityAndMonitoring","main","bb9b3f464aae37af360d079c1d863524955b0363","skills\u002Fcloud\u002Fcloud-logging-finops",2005,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills","https:\u002F\u002Fgithub.com\u002Fgoogle","https:\u002F\u002Fopensource.google\u002F","Google ❤️ Open Source","2026-11-14 01:51:35",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add google\u002Fskills --skill cloud-logging-finops",{"tool":67,"command":68},"bunx","bunx skills add google\u002Fskills --skill cloud-logging-finops",{"tool":70,"command":71},"pnpm","pnpm dlx skills add google\u002Fskills --skill cloud-logging-finops","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002FSKILL.md",true,[75,81,87,91,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173],{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"assets\u002Freport_template.html","ASSET","资产文件",137733,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fassets\u002Freport_template.html",{"path":82,"resourceType":83,"resourceTypeDesc":84,"sizeBytes":85,"sourceHtmlUrl":86},"references\u002Fattribution.md","REFERENCE","参考文档",1904,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Freferences\u002Fattribution.md",{"path":88,"resourceType":83,"resourceTypeDesc":84,"sizeBytes":89,"sourceHtmlUrl":90},"references\u002Fexecutive_summary_authoring.md",3930,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Freferences\u002Fexecutive_summary_authoring.md",{"path":92,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":95,"sourceHtmlUrl":96},"scripts\u002Factions.py","SCRIPT","脚本",12723,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Factions.py",{"path":98,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":99,"sourceHtmlUrl":100},"scripts\u002Faggregations.py",26008,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Faggregations.py",{"path":102,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":103,"sourceHtmlUrl":104},"scripts\u002Fanalytics.py",26262,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fanalytics.py",{"path":106,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":107,"sourceHtmlUrl":108},"scripts\u002Fattribution.py",2383,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fattribution.py",{"path":110,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":111,"sourceHtmlUrl":112},"scripts\u002Fbilling.py",23141,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fbilling.py",{"path":114,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":115,"sourceHtmlUrl":116},"scripts\u002Fbuild_report.py",15113,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fbuild_report.py",{"path":118,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":119,"sourceHtmlUrl":120},"scripts\u002Fcollect_logging_data.py",20417,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fcollect_logging_data.py",{"path":122,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":123,"sourceHtmlUrl":124},"scripts\u002Fconstants.py",9364,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fconstants.py",{"path":126,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":127,"sourceHtmlUrl":128},"scripts\u002Fenable_log_analytics.py",4256,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fenable_log_analytics.py",{"path":130,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":131,"sourceHtmlUrl":132},"scripts\u002Fexclusion_rules.py",12926,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fexclusion_rules.py",{"path":134,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":135,"sourceHtmlUrl":136},"scripts\u002Finventory.py",7253,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Finventory.py",{"path":138,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":139,"sourceHtmlUrl":140},"scripts\u002Fmessages.py",3488,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fmessages.py",{"path":142,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":143,"sourceHtmlUrl":144},"scripts\u002Fmonitoring.py",12950,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fmonitoring.py",{"path":146,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":147,"sourceHtmlUrl":148},"scripts\u002Foutput.py",6049,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Foutput.py",{"path":150,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":151,"sourceHtmlUrl":152},"scripts\u002Fperf.py",1675,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fperf.py",{"path":154,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":155,"sourceHtmlUrl":156},"scripts\u002Fpricing.py",17605,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fpricing.py",{"path":158,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":159,"sourceHtmlUrl":160},"scripts\u002Fprovenance.py",57893,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fprovenance.py",{"path":162,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":163,"sourceHtmlUrl":164},"scripts\u002Frequirements.txt",200,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Frequirements.txt",{"path":166,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":167,"sourceHtmlUrl":168},"scripts\u002Ftelemetry_integrity.py",7794,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Ftelemetry_integrity.py",{"path":170,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":171,"sourceHtmlUrl":172},"scripts\u002Fverify_claim.py",10483,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fverify_claim.py",{"path":174,"resourceType":93,"resourceTypeDesc":94,"sizeBytes":175,"sourceHtmlUrl":176},"scripts\u002Fwaste.py",19562,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fcloud-logging-finops\u002Fscripts\u002Fwaste.py",[178,215,244,272,299,324],{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":192,"publishedAt":44},"01M6998S2EZKD3GEJ7F943RZTE","sign-in-with-google-web","Implement, configure, and secure Sign In With Google (SiwG) using Google Identity Services (GIS \u002F `https:\u002F\u002Faccounts.google.com\u002Fgsi\u002Fclient`) across web architectures. Use when creating Google sign-in buttons, implementing Google One Tap with FedCM, integrating GIS in React\u002FNext.js\u002FAngular\u002FHTML, verifying ID tokens on backend runtimes (Python\u002FNode.js\u002FGo\u002FJava), enforcing Google Workspace domain restrictions (`hd`), securing client-side ID tokens via WebCrypto nonces or encrypted IndexedDB, embedding in cross-origin iframes via the Intermediate Iframe API (`https:\u002F\u002Faccounts.google.com\u002Fgsi\u002Fintermediate`), configuring Content Security Policy (CSP), COOP, and Permissions Policy (`identity-credentials-get`) headers, or handling sign-out and revocation. Don't use for legacy Google Sign-In (`gapi.auth2`), Google Cloud IAM service accounts, or Android\u002FiOS native Credential Manager.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fidentity\u002Fsign-in-with-google-web\u002FSKILL.md",[184,189],{"categoryNo":185,"categoryName":186,"taxonomyType":187,"taxonomyTypeDesc":188},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":190,"categoryName":191,"taxonomyType":187,"taxonomyTypeDesc":188},"01JBSEEDCAT000000000000010","后端与接口",[9,193,194,195,196,197,198,199,200,43,201,202,203,204,205,206,207,208,209,210,211,212,213,214],"sign in with google web","sign","with","web","android","go","security","google workspace","implement","policy","python","implementing","react","iam","permissions","buttons","secure","manager","identity","architectures","domain","runtimes",{"skillNo":216,"name":217,"nameZh":6,"description":218,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":219,"categories":220,"keywords":228,"publishedAt":44},"01M6998PHPDCAD684VW5WRG83D","dpop-adoption","Implement and debug OAuth 2.0 DPoP (RFC 9449) refresh token sender-constraining for WebCrypto, Node.js ES6, and browser runtimes integrating with Google's OAuth platform. Use when configuring non-extractable asymmetric key pairs (P-256), generating DPoP Proof JWTs for authorization code exchange and token refresh, or handling 400 use_dpop_nonce challenge retry loops at oauth2.googleapis.com\u002Ftoken. Don't use for unconstrained OAuth 2.0 flows (where refresh tokens are not bound to a client key pair), or for Google Cloud IAM \u002F service account authentication.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fidentity\u002Fdpop-adoption\u002FSKILL.md",[221,222,225],{"categoryNo":190,"categoryName":191,"taxonomyType":187,"taxonomyTypeDesc":188},{"categoryNo":223,"categoryName":224,"taxonomyType":187,"taxonomyTypeDesc":188},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":226,"categoryName":227,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000030","开发工程师",[229,230,9,43,231,232,233,234,235,236,206,237,238,239,240,241,242,211,214,243,29],"dpop adoption","adoption","es6","retry","authentication","flows","challenge","code","browser","loops","at","node","token","pair","platform",{"skillNo":245,"name":246,"nameZh":6,"description":247,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":248,"categories":249,"keywords":256,"publishedAt":44},"01M6998M72TC73EEAQH4XC7EXW","retrieving-developer-knowledge","Searches, retrieves, and synthesizes official Google developer documentation across Google Cloud, AI\u002FGemini, Android, Chrome, Web, Flutter, Go, Firebase, and other Google developer platforms. Integrates with the Developer Knowledge MCP server (search_documents, get_documents, answer_query) or the Developer Knowledge REST API fallback. Use when searching for gcloud CLI commands, API syntax, IAM permissions, official documentation, architectural comparisons, or product choice overviews. Don't use for local filesystem lookups or non-Google documentation.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdevelopers\u002Fretrieving-developer-knowledge\u002FSKILL.md",[250,251,254,255],{"categoryNo":190,"categoryName":191,"taxonomyType":187,"taxonomyTypeDesc":188},{"categoryNo":252,"categoryName":253,"taxonomyType":187,"taxonomyTypeDesc":188},"01JBSEEDCAT000000000000021","资料检索与研究",{"categoryNo":223,"categoryName":224,"taxonomyType":187,"taxonomyTypeDesc":188},{"categoryNo":226,"categoryName":227,"taxonomyType":21,"taxonomyTypeDesc":22},[257,258,259,260,43,261,262,263,264,265,266,267,268,29,38,269,270,206,271,207],"retrieving developer knowledge","knowledge","developer","MCP","mcp server","official","developer documentation","get","search","local","choice","documents","api","across","documentation",{"skillNo":273,"name":274,"nameZh":6,"description":275,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":276,"categories":277,"keywords":278,"publishedAt":44},"01M6998J2CZEXS9BES9S3WWFKC","migrate-to-rust","Clones, analyzes, plans, and migrates legacy codebases (C++, Fortran, Java, Python, C, Shell) from a GitHub URL or local directory to a modern, high-performance, deterministic, 100% Safe Rust architecture, tracking live telemetry across every task bucket, test failure\u002Ffix cycle, and Profile-Guided Optimization (PGO) stage, and producing a first-person AI storytelling report and interactive HTML infographic. Use when migrating a GitHub repository or local codebase to Rust, porting legacy C++, Fortran, Python, or Java workloads to memory-safe Rust, designing Struct-of-Arrays (SoA) or SIMD Rust architectures, or optimizing Rust ports with LLVM PGO. Don't use for unrelated non-Rust refactoring or single-line syntax questions.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdevelopers\u002Fmigrate-to-rust\u002FSKILL.md",[],[279,280,281,282,283,284,285,286,203,287,288,289,290,291,292,266,293,294,295,29,296,297,270,298],"migrate to rust","rust","migrate","github","memory","performance","directory","safe","ports","llvm","soa","cycle","porting","fix","arrays","infographic","high-performance","URL","architecture","unrelated",{"skillNo":300,"name":301,"nameZh":6,"description":302,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":303,"categories":304,"keywords":308,"publishedAt":44},"01M6998GCC3K29WZ82KXMB9E02","finding-google-skills","Google platform decision and setup guidance, loaded on demand from Google's skill catalog. Use when a developer is choosing or setting up part of their stack, such as where to run a service, a database, storage, messaging, authentication, analytics, ads, or AI model serving, and a Google product is a reasonable candidate - whether or not a vendor is named - or when a request names a Google product or API. Brings in the matching Google skill so the answer can weigh Google options, their trade-offs, and when they are not the right fit. Skip when the stack is already settled on another provider and no Google product is named, or the task involves no platform choice.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdevelopers\u002Ffinding-google-skills\u002FSKILL.md",[305,306,307],{"categoryNo":190,"categoryName":191,"taxonomyType":187,"taxonomyTypeDesc":188},{"categoryNo":223,"categoryName":224,"taxonomyType":187,"taxonomyTypeDesc":188},{"categoryNo":226,"categoryName":227,"taxonomyType":21,"taxonomyTypeDesc":22},[9,309,310,311,312,243,313,314,315,316,317,233,318,319,320,267,321,322,29,323,269],"finding google skills","storage","as","messaging","model","trade-offs","provider","answer","fit","catalog","up","decision","use","database","candidate",{"skillNo":325,"name":326,"nameZh":6,"description":327,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":328,"categories":329,"keywords":332,"publishedAt":44},"01M6998DWNHTH0BS6W1CY8ZXMP","workload-manager-basics","Use this skill to manage Google Cloud Workload Manager evaluations, rules, scanned resources, and validation results by using public client libraries and the REST API. Use when you need to inspect workload best-practice rules, create and run evaluations for Google Cloud general best practices, SAP, SQL Server, or custom organizational rules, review violations, export results to BigQuery, or automate Workload Manager through client libraries because no service-specific public CLI or MCP server is available. Don't use for general Google Compute Engine instance management, VPC configuration, or standard IAM auditing.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fworkload-manager-basics\u002FSKILL.md",[330,331],{"categoryNo":190,"categoryName":191,"taxonomyType":187,"taxonomyTypeDesc":188},{"categoryNo":223,"categoryName":224,"taxonomyType":187,"taxonomyTypeDesc":188},[333,334,210,335,9,260,336,43,261,337,338,339,340,29,341,269,206,342,343,344,345],"workload manager basics","workload","basics","cli","review","vpc","resources","inspect","you","create","libraries","server","run"]