[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6991292FVYS3XR3WE7VXZJD":3,"skill-same:01M6991292FVYS3XR3WE7VXZJD":72},{"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":43,"linkOnly":44,"markdownContent":45,"markdownBody":46,"frontMatter":47,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":51,"repositoryHtmlUrl":52,"repositoryHomepageUrl":53,"ownerHtmlUrl":54,"ownerBlogUrl":55,"ownerDescription":56,"updatedAt":57,"install":58,"resources":71},"01M6991292FVYS3XR3WE7VXZJD","bootstrap-google-tools",null,"Install\u002Fauth CLIs the sandbox lacks - `gws` (Drive, Gmail, Sheets, Calendar), `gcloud`, `agents-cli`, `mcp-cli` (MCP servers). Use on \"command not found\" or before GCP\u002FWorkspace\u002FMCP work.","google\u002Fadk-recipes","google","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1342004?v=4","01M698VYEFDM0VJBZDYYJ2T83S","Google","01M6990124CWS5627VKGSKJXRD",10609,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fcore\u002Fpython\u002Flong-horizon-harness\u002Fhorizon\u002Fbuiltin_skills\u002Fbootstrap-google-tools\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[9,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42],"bootstrap google tools","bootstrap","Tools","servers","MCP","sheets","gws","calendar","use","install","command","work","workspace","gcp","auth","sandbox","gcloud","cli","gmail","2026-11-10 10:12:30",false,"---\nname: bootstrap-google-tools\ndescription: Install\u002Fauth CLIs the sandbox lacks - `gws` (Drive, Gmail, Sheets, Calendar), `gcloud`, `agents-cli`, `mcp-cli` (MCP servers). Use on \"command not found\" or before GCP\u002FWorkspace\u002FMCP work.\n---\n# Install & authenticate CLIs in the sandbox\n\nThe sandbox ships lean — Node, `gws`, `gcloud`, `agents-cli`, and `mcp-cli` are\n**not** prebaked. This skill is the verified install + auth recipe for each.\nThe tools are **independent**: install only the one the task needs. This is a\nmenu, not a sequence — there's no 1-2-3 to run in order.\n\n## Persistence model — binaries in `~\u002F.local`, credentials in `\u002Fworkspace`\n\nTwo different durability rules, because the sandbox has two boundaries:\n\n- **Across normal sessions** the sandbox reattaches, so *everything* (`$HOME`\n  included) persists. Install once, reuse next session.\n- **Across a runtime-image upgrade** the sandbox is re-provisioned and **only\n  `\u002Fworkspace` is migrated** — and that migration is a zip that **drops symlinks\n  and strips executable bits** (and is best-effort). So it can't carry installed\n  CLIs at all; it's only safe for plain data files.\n\nThat dictates the split:\n\n| What | Where | On upgrade |\n|---|---|---|\n| CLI binaries | `~\u002F.local` (bin dir `~\u002F.local\u002Fbin` is on `PATH`) | gone — reinstalled (cheap, automatic via the `command -v` check) |\n| Credentials \u002F config | `\u002Fworkspace\u002Flha\u002Fconfig\u002F` (`gws\u002F`, `gcloud\u002F`, `mcp_servers.json`) | **migrated** — logins survive |\n\nSo: install binaries the normal way, but point each tool's **config dir** at\n`\u002Fworkspace\u002Flha\u002Fconfig` (via its own env var, shown per tool) so the expensive\npart — the OAuth client + tokens — survives upgrades. Don't put binaries on\n`\u002Fworkspace`: they can't migrate anyway, and bloating the migration zip risks\nthe credentials that *can*. `~\u002F.local\u002Fbin` is already on `PATH` (runtime image),\nand the `bash` shell is non-login (no `~\u002F.profile`), so that image `PATH` is\nwhat makes installs resolve.\n\n## Pick what you need\n\n| Task | Tool | Needs first |\n|---|---|---|\n| Google Workspace — Drive \u002F Gmail \u002F Sheets \u002F Calendar \u002F Chat | `gws` | Node |\n| Raw GCP, or creating a `gws` OAuth client by hand | `gcloud` | — |\n| Call another agent deployed remotely (A2A \u002F ADK) | `agents-cli` | — (`uv` is present) |\n| Use tools exposed by an MCP server | `mcp-cli` | — (standalone binary) |\n\nEach tool's **usage** lives in its own skill (`google-workspace`, mcp-cli's\nshipped skill, the `google-agents-cli-*` set). This skill only gets a tool\ninstalled and authed, then hands off.\n\n## Before installing: check first\n\nWithin a session (and across sessions without an upgrade) a tool may already be\npresent — check before installing, and install only what's missing:\n\n```\nbash(command=\"command -v gws\")   # or gcloud \u002F agents-cli \u002F mcp-cli \u002F node\n```\n\n## Node + npm  *(prerequisite for `gws`)*\n\nThe sandbox is Debian x86_64 with `curl` and `tar` but **no `xz`**. So you must\ndownload the `.tar.gz` build, **not** the `.tar.xz`. Pick a current LTS version:\n\n```\nbash(command='mkdir -p ~\u002F.local\u002Fbin && cd ~ && V=v22.x.x && \\\n  curl -fsSLo node.tgz \"https:\u002F\u002Fnodejs.org\u002Fdist\u002F$V\u002Fnode-$V-linux-x64.tar.gz\" && \\\n  tar -xzf node.tgz -C ~\u002F.local && rm node.tgz && \\\n  ln -sf ~\u002F.local\u002Fnode-$V-linux-x64\u002Fbin\u002Fnode ~\u002F.local\u002Fnode-$V-linux-x64\u002Fbin\u002Fnpm ~\u002F.local\u002Fnode-$V-linux-x64\u002Fbin\u002Fnpx ~\u002F.local\u002Fbin\u002F')\n```\n\nReplace `v22.x.x` with the real current LTS. The `ln -sf … ~\u002F.local\u002Fbin\u002F` step\nputs `node`\u002F`npm`\u002F`npx` on `PATH`. Then verify:\n\n```\nbash(command=\"node --version && npm --version\")\n```\n\n- Use `.tar.gz` — `.tar.xz` will fail to extract (`xz` is absent).\n\n## `gws` — Google Workspace CLI\n\nInstall the npm global into `~\u002F.local` (needs Node on `PATH` — see above) with\n`--prefix`, so the binary lands at `~\u002F.local\u002Fbin\u002Fgws`:\n\n```\nbash(command='npm install -g --prefix ~\u002F.local @googleworkspace\u002Fcli && gws --version')\n```\n\nExpect `0.22.x`. `gws` self-identifies as \"not an officially supported Google\nproduct.\"\n\n**Keep `gws` credentials on `\u002Fworkspace`.** By default `gws` reads\u002Fwrites\n`~\u002F.config\u002Fgws` — which is **not** migrated on a runtime upgrade. Point it at\n`\u002Fworkspace` and use the file keyring (no OS keyring headless) **on every `gws`\ncommand** so the OAuth client, token, and encryption key survive:\n\n```\nexport GOOGLE_WORKSPACE_CLI_CONFIG_DIR=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws\nexport GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file\n```\n\n**First, always: probe the pre-injected token.** When the user has used\n**\"Connect Workspace\"** in the web UI, the `GOOGLE_WORKSPACE_CLI_TOKEN` secret is\nauto-injected into every `bash` command — `gws`'s **highest-priority** auth\nsource. Don't inspect the environment or ask; just run a cheap read against the\nsurface you need and see if it works:\n\n```\nbash(command=\"export GOOGLE_WORKSPACE_CLI_CONFIG_DIR=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file && gws gmail messages list --params '{\\\"maxResults\\\": 1}'\")\n```\n\nIf it returns data, you're done — **no OAuth client, no `gws auth login`, no\nloopback bridge**. It's a ~1h token (no refresh); the user re-clicks Connect\nwhen it lapses. The token only carries the **surfaces + access level**\n(read-only by default) the user picked — a `gws` call outside those scopes fails\n(`403`\u002Fscope error), which means \"reconnect with more surfaces or read-write,\"\n**not** that the token is missing. **Don't trust `gws auth status`** — with the\nenv token it reports `auth_method: none` \u002F `credential_source: token_env_var`\neven while reads succeed, so a real read is the only reliable check. Only if the\nprobe `401`s (truly no token) do you fall through to the OAuth-client options\nbelow.\n\n**Otherwise, point `gws` at an OAuth client** — `gws` ships none of its own. Pick one:\n\n1. Drop a `client_secret.json` into `\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws\u002F` (must be a\n   **Desktop app** OAuth client — see the `google-workspace` skill).\n2. Set `GOOGLE_WORKSPACE_CLI_CLIENT_ID` + `GOOGLE_WORKSPACE_CLI_CLIENT_SECRET`.\n3. Service account: `GOOGLE_APPLICATION_CREDENTIALS=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws\u002Fkey.json`\n   — for fully unattended automation (no interactive login).\n4. `gws auth setup` — provisions a project + OAuth client, but is a full-screen\n   TUI that **can't be driven headless**; prefer option 1 in the sandbox.\n\n`gws auth login` is loopback-browser only, but **does complete headless** — you\nbridge the OAuth redirect by hand (start it backgrounded, relay the auth URL to\nthe user, then `curl` their pasted `localhost:\u003Cport>\u002F?code=...` redirect back to\nthe waiting listener). The **`google-workspace`** skill has the full auth recipe\n(Desktop-app client type, Internal audience, the loopback bridge) plus command\nshapes (Drive, Docs, Sheets, Gmail, Calendar, Chat). For fully unattended jobs\nwith no user present to paste the redirect, use the service-account option.\n\n**Under a routine, the Google\u002Fgcloud token is present only if you declared its\nsecret name (`GOOGLE_WORKSPACE_CLI_TOKEN` \u002F `CLOUDSDK_AUTH_ACCESS_TOKEN`) in the\nroutine's `secrets:`.**\n\n**Once `gws` is set up, strongly suggest installing Google's official `gws`\nskills.** They live in the `googleworkspace\u002Fcli` repo and go deeper than the\nbuiltin `google-workspace` skill — one per surface. Install the ones the user\nneeds (`gws-shared` is the common base the others build on):\n\n```\nbash(command=\"npx --yes skills add googleworkspace\u002Fcli@gws-shared -y\")\nbash(command=\"npx --yes skills add googleworkspace\u002Fcli@gws-gmail -y\")\n# also: gws-drive, gws-docs, gws-docs-write, gws-sheets, gws-calendar,\n#       gws-events, gws-chat-send\n```\n\nThe Skills CLI stages each under `.agents\u002Fskills\u002F\u003Cskill>\u002F`, which Horizon\nauto-discovers — just `load_skill(action=\"reload\")`, no move needed (see the\n`find-skills` skill for details). (`npx --yes skills find gws` lists the\ncurrent set with install counts.)\n\n## `gcloud`\n\nInstall under `~\u002F.local` (slim — don't add extra components) and symlink the\nentrypoints onto `PATH`:\n\n```\nbash(command='mkdir -p ~\u002F.local\u002Fbin && cd ~\u002F.local && \\\n  curl -fsSLo gcloud.tgz \"https:\u002F\u002Fdl.google.com\u002Fdl\u002Fcloudsdk\u002Fchannels\u002Frapid\u002Fdownloads\u002Fgoogle-cloud-cli-linux-x86_64.tar.gz\" && \\\n  tar -xzf gcloud.tgz && rm gcloud.tgz && \\\n  .\u002Fgoogle-cloud-sdk\u002Finstall.sh --quiet --usage-reporting=false --path-update=false && \\\n  ln -sf ~\u002F.local\u002Fgoogle-cloud-sdk\u002Fbin\u002Fgcloud ~\u002F.local\u002Fgoogle-cloud-sdk\u002Fbin\u002Fgsutil ~\u002F.local\u002Fgoogle-cloud-sdk\u002Fbin\u002Fbq ~\u002F.local\u002Fbin\u002F')\n```\n\n**No durable gcloud credentials are kept in the sandbox.** GCP access is via the\nshort-lived **token-as-secret** path below, which persists nothing — no refresh\ntoken, no ADC file, no key. (You may set `CLOUDSDK_CONFIG=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgcloud`\nas a scratch config dir, but there is no login state to persist across upgrades.)\n\nVerify:\n\n```\nbash(command=\"gcloud --version\")\n```\n\n### Security: GCP creds is a high-trust combination\n\nLogging in deposits credentials **the agent** can use, in a sandbox with open\noutbound internet egress. An injected agent could read the user's GCP data,\n`bq extract` \u002F `gsutil cp` it to a foreign bucket, mint a service-account key,\nor grant external IAM — all over `*.googleapis.com`. Layer A (exfil_guard) still\ngates credential\u002Fsecret exfil and uploads to non-allowlisted hosts, and still\nblocks the GCP metadata server; it has no GCP-action awareness (it can't see\nwhat a `gcloud` call does). **The real control is credential minimization:**\n\n- **Use the short-lived token-as-secret path only** (below). We keep **no durable\n  credential** (refresh token \u002F ADC file \u002F SA key) in the sandbox, so a single\n  injection can't become standing access that outlives the ~1 h token.\n- Mint the token with the **narrowest scopes** the task needs; `cloud-platform`\n  (everything the user's IAM allows) is a broad, high-trust default — not a free one.\n- Confirm the user actually wants the agent acting as them on GCP before adding the\n  token.\n\n### Authenticate — short-lived access token as a secret (the only GCP path)\n\nThe lowest-trust, least-friction path, and the **only** one we use (works for corp \u002F\norg-restricted accounts too): the user mints a **short-lived access token on their own\nmachine** (already gcloud-authed there, so the org's device\u002FCAA policy is\nsatisfied) and hands it to the agent as a **secret**. Nothing durable lands in the\nsandbox, and the token self-expires in ~1 hour.\n\n1. The user runs locally, in their own terminal (authed as the right account):\n   ```\n   gcloud auth print-access-token\n   ```\n2. The user saves it as a secret **named `CLOUDSDK_AUTH_ACCESS_TOKEN`** in the\n   `\u002Flha\u002Fsecrets` UI — never pasted into chat (it's a live credential).\n3. Secrets are **auto-injected as env vars into every `bash` command**, and\n   gcloud reads `CLOUDSDK_AUTH_ACCESS_TOKEN` from the environment — so the agent\n   just runs commands, no login \u002F ADC \u002F OAuth client at all:\n   ```\n   bash(command=\"export CLOUDSDK_CONFIG=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgcloud && gcloud projects list\")\n   ```\n   `gsutil` and `bq` read the same env token. **Don't name the token in a\n   `curl`\u002F`wget`** (`-H \"Authorization: Bearer $CLOUDSDK_AUTH_ACCESS_TOKEN\"`): the\n   exfil guard hard-blocks a network command that references a secret env var (by\n   design — it stops the agent exfiltrating the token). Use the gcloud-family CLIs,\n   which pick it up from the environment without naming it; a raw REST call that\n   must carry the token needs a `\u002Fgrant`.\n\nWhy this is the default:\n- **Short-lived (~1 h):** a single injection can't become standing access; on\n  expiry the user re-mints and updates the secret.\n- **Nothing durable in the sandbox** — no refresh token on `\u002Fworkspace` to reuse.\n- **Corp-clean:** consent already happened through the user's org-approved local\n  gcloud — no `Account restricted`, no custom OAuth client, no remote-bootstrap.\n- It still acts as the user for that window (short lifetime bounds misuse, doesn't\n  eliminate it) and carries the user's login scopes. For a **long unattended job**\n  the token expires (~1 h) and must be **re-minted and the secret updated** — by\n  design we keep no durable credential in the sandbox to fall back on.\n\n## `agents-cli` — call a remote agent (A2A \u002F ADK)\n\nTo hand a task to **another agent deployed remotely** (Cloud Run, Vertex Agent\nRuntime, or any A2A endpoint), shell out to `agents-cli` — no in-process wiring\nneeded. This is the outbound counterpart to in-process `subagent()`: the remote\nagent is its own service with its own state; you just send a prompt over HTTP.\n\nInstall (one-time; `uv` is already in the sandbox — it installs to `~\u002F.local\u002Fbin`):\n\n```\nbash(command=\"command -v agents-cli || uv tool install google-agents-cli\")\nbash(command=\"agents-cli --version\")\n```\n\n(Install pulls from wherever `google-agents-cli` is published — if the sandbox\ncan't reach that index, that's the same egress dependency as the Node\u002Fgcloud\ndownloads.)\n\nInvoke:\n\n```\nbash(command='agents-cli run \"summarize this repo\" --url https:\u002F\u002Fmy-agent-xxxx.run.app --mode a2a')\n```\n\n- `--mode a2a` for the A2A protocol; `--mode adk` for ADK SSE (`\u002Frun_sse`, or\n  `:streamQuery` on Agent Runtime). `--mode` is **required** with `--url`.\n- `--app-name \u003Cname>` to target a specific agent at that endpoint.\n- `--session-id \u003Cid>` to continue a conversation; `-v` for full JSON events.\n- stdout is the remote agent's final response — that *is* your result (blocking).\n  For a long-running remote task, run it with `process(action='spawn', command=...)`\n  and poll via the `process` tool (fire-and-forget).\n\n**Auth — usually automatic.** `agents-cli` auto-detects Google credentials from\nthe sandbox identity: an **ID token** (audience = service URL) for Cloud Run, an\n**access token** for Vertex AI \u002F Agent Runtime. For this to yield a usable token,\nthe sandbox\u002FCloud Run service account needs the right IAM on the target\n(`roles\u002Frun.invoker` for Cloud Run; Vertex perms for Agent Runtime) — a 401\u002F403\nis almost always missing IAM, not a CLI problem.\n\n**User-delegated auth** (call *as the user*): pass the token explicitly, which\noverrides auto-detect:\n\n```\nbash(command='agents-cli run \"...\" --url https:\u002F\u002F... --mode a2a -H \"Authorization: Bearer $USER_TOKEN\"')\n```\n\nSource the token from the secrets \u002F headless-auth subsystem (never inline a raw\nsecret into chat).\n\n`--url` is a thin client — it loads no local skills (the remote agent's skills\nare its own concern). If you need `agents-cli`'s **broader toolchain** (scaffold,\ndeploy, eval, observability, publish, workflow), install those skills on demand\nvia the **`find-skills`** skill.\n\n## `mcp-cli` — use tools exposed by an MCP server\n\nTo call tools served by an **MCP server** (GitHub, filesystem, databases,\nthird-party APIs) from the sandbox. This is the *client* side — using external\nMCP servers via `bash`, not running one. (Auth is **static token only** —\ninject the server's bearer via `${VAR}` headers, below; there is no OAuth\u002Fconsent\nflow. For GCP, use the token-as-secret path in the `gcloud` section, not MCP.)\n\nInstall — `install.sh` downloads a **checksum-verified, self-contained prebuilt\nbinary** (`mcp-cli-linux-x64`, ~100 MB) to `~\u002F.local\u002Fbin\u002Fmcp-cli`. It's compiled\nwith Bun but needs **no Bun\u002FNode** at install or runtime — it's standalone.\n\n**Don't pipe-to-bash.** `curl … | bash` is blocked by the tool policy (piping\nremote content to a shell). Download the script, then run it from a file:\n\n```\nbash(command=\"command -v mcp-cli || (curl -fsSLo \u002Ftmp\u002Fmcp_install.sh https:\u002F\u002Fraw.githubusercontent.com\u002Fphilschmid\u002Fmcp-cli\u002Fmain\u002Finstall.sh && bash \u002Ftmp\u002Fmcp_install.sh)\")\nbash(command=\"mcp-cli --version\")\n```\n\n(Optionally `read('\u002Ftmp\u002Fmcp_install.sh')` first — it just fetches the latest\nrelease binary and verifies its SHA256.) It installs to `~\u002F.local\u002Fbin`.\n\n**Configure servers — this is the real onboarding work.** `mcp-cli` is\nconfig-driven: it reads `mcp_servers.json`. Keep it on `\u002Fworkspace` (config is a\ndata file — it migrates) and point `mcp-cli` at it with `MCP_CONFIG_PATH` (its\nhighest-priority resolver); the default `~\u002F.config\u002Fmcp\u002F…` is not migrated:\n\n```\nexport MCP_CONFIG_PATH=\u002Fworkspace\u002Flha\u002Fconfig\u002Fmcp_servers.json\n```\n\nWrite that file (Claude-Desktop \u002F Gemini \u002F VS-Code compatible):\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-filesystem\", \"\u002Fworkspace\"]\n    },\n    \"remote-api\": {\n      \"url\": \"https:\u002F\u002Fmcp.example.com\",\n      \"headers\": { \"Authorization\": \"Bearer ${MCP_TOKEN}\" }\n    }\n  }\n}\n```\n\n- **stdio** server → `command` + `args` the sandbox can spawn (install the server\n  too, e.g. via `npx`\u002F`uvx`).\n- **HTTP** server → `url` (+ `headers`).\n- **Auth:** `${VAR}` in `headers` is substituted from the environment at config\n  load (missing var errors unless `MCP_STRICT_ENV=false`). Source that token from\n  the **secrets subsystem** (env-injection) — never inline a raw secret.\n\nUse (or install mcp-cli's **own usage skill** via `find-skills` for the full\nreference):\n\n```\nbash(command=\"mcp-cli\")                                              # list servers + tools\nbash(command=\"mcp-cli info filesystem read_file\")                    # tool schema\nbash(command=\"mcp-cli call filesystem read_file '{\\\"path\\\": \\\".\u002FREADME.md\\\"}'\")\n```\n\nUse `call` to invoke and `info` to inspect — `mcp-cli \u003Cserver> \u003Ctool>` directly\nis ambiguous and errors.\n\n## Failure cheat-sheet\n\n| Symptom | Cause \u002F fix |\n|---|---|\n| any tool \"command not found\" after a runtime upgrade | binaries live in `$HOME` and aren't migrated — reinstall per this skill (the `command -v` check does this) |\n| `node`\u002F`gcloud: command not found` after install | the `ln -sf … ~\u002F.local\u002Fbin\u002F` symlink step was skipped; re-run it (`~\u002F.local\u002Fbin` is on PATH, the versioned\u002FSDK bin dir isn't) |\n| `tar: ... cannot exec xz` | downloaded `.tar.xz`; use the `.tar.gz` build instead |\n| `gws` asks to log in again after an upgrade | its credentials were written under `$HOME` (not migrated); set `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` to the `\u002Fworkspace\u002Flha\u002Fconfig\u002F*` path on **every** call (gcloud keeps no persisted login — re-add the token secret) |\n| `gws` login token not saved \u002F no keyring | set `GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file` (alongside the config-dir export) |\n| `gws auth status` says `auth_method: none` but reads work | expected when `GOOGLE_WORKSPACE_CLI_TOKEN` is the source — `auth status` doesn't reflect the env token. Confirm with a real read, not `auth status`; don't start a login dance |\n| `gws auth login` hangs on the listener | expected headless — bridge the redirect (see `google-workspace` skill) or use a service account if no user is present |\n| `403 access_denied \"Account restricted\"` | Context-Aware Access on the OAuth client — don't fight it. Use the **token-as-secret** path: user runs `gcloud auth print-access-token` locally and stores it as the secret `CLOUDSDK_AUTH_ACCESS_TOKEN` |\n| network command blocked: \"reads a credential path or secret env var\" | Don't name `$CLOUDSDK_AUTH_ACCESS_TOKEN` (or any `*_TOKEN`\u002F`*_KEY`) in a `curl`\u002F`wget` — the exfil guard hard-blocks it. Let `gcloud`\u002F`gsutil`\u002F`bq` read the token from the env instead; a raw REST call needs a `\u002Fgrant` |\n| Unattended job has no GCP token | the `CLOUDSDK_AUTH_ACCESS_TOKEN` secret is missing or expired; surface \"needs a fresh token\" and stop — don't loop |\n| `agents-cli: command not found` | `uv tool install google-agents-cli` (uv is already in the sandbox) |\n| remote `agents-cli run --url` 401\u002F403 | missing IAM on the target (`roles\u002Frun.invoker` \u002F Vertex perms), not a CLI bug |\n| `--mode is required when using --url` | add `--mode a2a` (or `--mode adk`) to the remote call |\n| `mcp-cli: command not found` | download `install.sh` then `bash` the file (don't `\\| bash` — policy blocks it); installs to `~\u002F.local\u002Fbin` |\n| mcp-cli `AMBIGUOUS_COMMAND` | use `mcp-cli call`\u002F`info \u003Cserver> \u003Ctool>`, not `mcp-cli \u003Cserver> \u003Ctool>` |\n| mcp-cli `${VAR}` missing at config load | export the token (from the secrets subsystem) or set `MCP_STRICT_ENV=false` |\n","# Install & authenticate CLIs in the sandbox\n\nThe sandbox ships lean — Node, `gws`, `gcloud`, `agents-cli`, and `mcp-cli` are\n**not** prebaked. This skill is the verified install + auth recipe for each.\nThe tools are **independent**: install only the one the task needs. This is a\nmenu, not a sequence — there's no 1-2-3 to run in order.\n\n## Persistence model — binaries in `~\u002F.local`, credentials in `\u002Fworkspace`\n\nTwo different durability rules, because the sandbox has two boundaries:\n\n- **Across normal sessions** the sandbox reattaches, so *everything* (`$HOME`\n  included) persists. Install once, reuse next session.\n- **Across a runtime-image upgrade** the sandbox is re-provisioned and **only\n  `\u002Fworkspace` is migrated** — and that migration is a zip that **drops symlinks\n  and strips executable bits** (and is best-effort). So it can't carry installed\n  CLIs at all; it's only safe for plain data files.\n\nThat dictates the split:\n\n| What | Where | On upgrade |\n|---|---|---|\n| CLI binaries | `~\u002F.local` (bin dir `~\u002F.local\u002Fbin` is on `PATH`) | gone — reinstalled (cheap, automatic via the `command -v` check) |\n| Credentials \u002F config | `\u002Fworkspace\u002Flha\u002Fconfig\u002F` (`gws\u002F`, `gcloud\u002F`, `mcp_servers.json`) | **migrated** — logins survive |\n\nSo: install binaries the normal way, but point each tool's **config dir** at\n`\u002Fworkspace\u002Flha\u002Fconfig` (via its own env var, shown per tool) so the expensive\npart — the OAuth client + tokens — survives upgrades. Don't put binaries on\n`\u002Fworkspace`: they can't migrate anyway, and bloating the migration zip risks\nthe credentials that *can*. `~\u002F.local\u002Fbin` is already on `PATH` (runtime image),\nand the `bash` shell is non-login (no `~\u002F.profile`), so that image `PATH` is\nwhat makes installs resolve.\n\n## Pick what you need\n\n| Task | Tool | Needs first |\n|---|---|---|\n| Google Workspace — Drive \u002F Gmail \u002F Sheets \u002F Calendar \u002F Chat | `gws` | Node |\n| Raw GCP, or creating a `gws` OAuth client by hand | `gcloud` | — |\n| Call another agent deployed remotely (A2A \u002F ADK) | `agents-cli` | — (`uv` is present) |\n| Use tools exposed by an MCP server | `mcp-cli` | — (standalone binary) |\n\nEach tool's **usage** lives in its own skill (`google-workspace`, mcp-cli's\nshipped skill, the `google-agents-cli-*` set). This skill only gets a tool\ninstalled and authed, then hands off.\n\n## Before installing: check first\n\nWithin a session (and across sessions without an upgrade) a tool may already be\npresent — check before installing, and install only what's missing:\n\n```\nbash(command=\"command -v gws\")   # or gcloud \u002F agents-cli \u002F mcp-cli \u002F node\n```\n\n## Node + npm  *(prerequisite for `gws`)*\n\nThe sandbox is Debian x86_64 with `curl` and `tar` but **no `xz`**. So you must\ndownload the `.tar.gz` build, **not** the `.tar.xz`. Pick a current LTS version:\n\n```\nbash(command='mkdir -p ~\u002F.local\u002Fbin && cd ~ && V=v22.x.x && \\\n  curl -fsSLo node.tgz \"https:\u002F\u002Fnodejs.org\u002Fdist\u002F$V\u002Fnode-$V-linux-x64.tar.gz\" && \\\n  tar -xzf node.tgz -C ~\u002F.local && rm node.tgz && \\\n  ln -sf ~\u002F.local\u002Fnode-$V-linux-x64\u002Fbin\u002Fnode ~\u002F.local\u002Fnode-$V-linux-x64\u002Fbin\u002Fnpm ~\u002F.local\u002Fnode-$V-linux-x64\u002Fbin\u002Fnpx ~\u002F.local\u002Fbin\u002F')\n```\n\nReplace `v22.x.x` with the real current LTS. The `ln -sf … ~\u002F.local\u002Fbin\u002F` step\nputs `node`\u002F`npm`\u002F`npx` on `PATH`. Then verify:\n\n```\nbash(command=\"node --version && npm --version\")\n```\n\n- Use `.tar.gz` — `.tar.xz` will fail to extract (`xz` is absent).\n\n## `gws` — Google Workspace CLI\n\nInstall the npm global into `~\u002F.local` (needs Node on `PATH` — see above) with\n`--prefix`, so the binary lands at `~\u002F.local\u002Fbin\u002Fgws`:\n\n```\nbash(command='npm install -g --prefix ~\u002F.local @googleworkspace\u002Fcli && gws --version')\n```\n\nExpect `0.22.x`. `gws` self-identifies as \"not an officially supported Google\nproduct.\"\n\n**Keep `gws` credentials on `\u002Fworkspace`.** By default `gws` reads\u002Fwrites\n`~\u002F.config\u002Fgws` — which is **not** migrated on a runtime upgrade. Point it at\n`\u002Fworkspace` and use the file keyring (no OS keyring headless) **on every `gws`\ncommand** so the OAuth client, token, and encryption key survive:\n\n```\nexport GOOGLE_WORKSPACE_CLI_CONFIG_DIR=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws\nexport GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file\n```\n\n**First, always: probe the pre-injected token.** When the user has used\n**\"Connect Workspace\"** in the web UI, the `GOOGLE_WORKSPACE_CLI_TOKEN` secret is\nauto-injected into every `bash` command — `gws`'s **highest-priority** auth\nsource. Don't inspect the environment or ask; just run a cheap read against the\nsurface you need and see if it works:\n\n```\nbash(command=\"export GOOGLE_WORKSPACE_CLI_CONFIG_DIR=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file && gws gmail messages list --params '{\\\"maxResults\\\": 1}'\")\n```\n\nIf it returns data, you're done — **no OAuth client, no `gws auth login`, no\nloopback bridge**. It's a ~1h token (no refresh); the user re-clicks Connect\nwhen it lapses. The token only carries the **surfaces + access level**\n(read-only by default) the user picked — a `gws` call outside those scopes fails\n(`403`\u002Fscope error), which means \"reconnect with more surfaces or read-write,\"\n**not** that the token is missing. **Don't trust `gws auth status`** — with the\nenv token it reports `auth_method: none` \u002F `credential_source: token_env_var`\neven while reads succeed, so a real read is the only reliable check. Only if the\nprobe `401`s (truly no token) do you fall through to the OAuth-client options\nbelow.\n\n**Otherwise, point `gws` at an OAuth client** — `gws` ships none of its own. Pick one:\n\n1. Drop a `client_secret.json` into `\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws\u002F` (must be a\n   **Desktop app** OAuth client — see the `google-workspace` skill).\n2. Set `GOOGLE_WORKSPACE_CLI_CLIENT_ID` + `GOOGLE_WORKSPACE_CLI_CLIENT_SECRET`.\n3. Service account: `GOOGLE_APPLICATION_CREDENTIALS=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgws\u002Fkey.json`\n   — for fully unattended automation (no interactive login).\n4. `gws auth setup` — provisions a project + OAuth client, but is a full-screen\n   TUI that **can't be driven headless**; prefer option 1 in the sandbox.\n\n`gws auth login` is loopback-browser only, but **does complete headless** — you\nbridge the OAuth redirect by hand (start it backgrounded, relay the auth URL to\nthe user, then `curl` their pasted `localhost:\u003Cport>\u002F?code=...` redirect back to\nthe waiting listener). The **`google-workspace`** skill has the full auth recipe\n(Desktop-app client type, Internal audience, the loopback bridge) plus command\nshapes (Drive, Docs, Sheets, Gmail, Calendar, Chat). For fully unattended jobs\nwith no user present to paste the redirect, use the service-account option.\n\n**Under a routine, the Google\u002Fgcloud token is present only if you declared its\nsecret name (`GOOGLE_WORKSPACE_CLI_TOKEN` \u002F `CLOUDSDK_AUTH_ACCESS_TOKEN`) in the\nroutine's `secrets:`.**\n\n**Once `gws` is set up, strongly suggest installing Google's official `gws`\nskills.** They live in the `googleworkspace\u002Fcli` repo and go deeper than the\nbuiltin `google-workspace` skill — one per surface. Install the ones the user\nneeds (`gws-shared` is the common base the others build on):\n\n```\nbash(command=\"npx --yes skills add googleworkspace\u002Fcli@gws-shared -y\")\nbash(command=\"npx --yes skills add googleworkspace\u002Fcli@gws-gmail -y\")\n# also: gws-drive, gws-docs, gws-docs-write, gws-sheets, gws-calendar,\n#       gws-events, gws-chat-send\n```\n\nThe Skills CLI stages each under `.agents\u002Fskills\u002F\u003Cskill>\u002F`, which Horizon\nauto-discovers — just `load_skill(action=\"reload\")`, no move needed (see the\n`find-skills` skill for details). (`npx --yes skills find gws` lists the\ncurrent set with install counts.)\n\n## `gcloud`\n\nInstall under `~\u002F.local` (slim — don't add extra components) and symlink the\nentrypoints onto `PATH`:\n\n```\nbash(command='mkdir -p ~\u002F.local\u002Fbin && cd ~\u002F.local && \\\n  curl -fsSLo gcloud.tgz \"https:\u002F\u002Fdl.google.com\u002Fdl\u002Fcloudsdk\u002Fchannels\u002Frapid\u002Fdownloads\u002Fgoogle-cloud-cli-linux-x86_64.tar.gz\" && \\\n  tar -xzf gcloud.tgz && rm gcloud.tgz && \\\n  .\u002Fgoogle-cloud-sdk\u002Finstall.sh --quiet --usage-reporting=false --path-update=false && \\\n  ln -sf ~\u002F.local\u002Fgoogle-cloud-sdk\u002Fbin\u002Fgcloud ~\u002F.local\u002Fgoogle-cloud-sdk\u002Fbin\u002Fgsutil ~\u002F.local\u002Fgoogle-cloud-sdk\u002Fbin\u002Fbq ~\u002F.local\u002Fbin\u002F')\n```\n\n**No durable gcloud credentials are kept in the sandbox.** GCP access is via the\nshort-lived **token-as-secret** path below, which persists nothing — no refresh\ntoken, no ADC file, no key. (You may set `CLOUDSDK_CONFIG=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgcloud`\nas a scratch config dir, but there is no login state to persist across upgrades.)\n\nVerify:\n\n```\nbash(command=\"gcloud --version\")\n```\n\n### Security: GCP creds is a high-trust combination\n\nLogging in deposits credentials **the agent** can use, in a sandbox with open\noutbound internet egress. An injected agent could read the user's GCP data,\n`bq extract` \u002F `gsutil cp` it to a foreign bucket, mint a service-account key,\nor grant external IAM — all over `*.googleapis.com`. Layer A (exfil_guard) still\ngates credential\u002Fsecret exfil and uploads to non-allowlisted hosts, and still\nblocks the GCP metadata server; it has no GCP-action awareness (it can't see\nwhat a `gcloud` call does). **The real control is credential minimization:**\n\n- **Use the short-lived token-as-secret path only** (below). We keep **no durable\n  credential** (refresh token \u002F ADC file \u002F SA key) in the sandbox, so a single\n  injection can't become standing access that outlives the ~1 h token.\n- Mint the token with the **narrowest scopes** the task needs; `cloud-platform`\n  (everything the user's IAM allows) is a broad, high-trust default — not a free one.\n- Confirm the user actually wants the agent acting as them on GCP before adding the\n  token.\n\n### Authenticate — short-lived access token as a secret (the only GCP path)\n\nThe lowest-trust, least-friction path, and the **only** one we use (works for corp \u002F\norg-restricted accounts too): the user mints a **short-lived access token on their own\nmachine** (already gcloud-authed there, so the org's device\u002FCAA policy is\nsatisfied) and hands it to the agent as a **secret**. Nothing durable lands in the\nsandbox, and the token self-expires in ~1 hour.\n\n1. The user runs locally, in their own terminal (authed as the right account):\n   ```\n   gcloud auth print-access-token\n   ```\n2. The user saves it as a secret **named `CLOUDSDK_AUTH_ACCESS_TOKEN`** in the\n   `\u002Flha\u002Fsecrets` UI — never pasted into chat (it's a live credential).\n3. Secrets are **auto-injected as env vars into every `bash` command**, and\n   gcloud reads `CLOUDSDK_AUTH_ACCESS_TOKEN` from the environment — so the agent\n   just runs commands, no login \u002F ADC \u002F OAuth client at all:\n   ```\n   bash(command=\"export CLOUDSDK_CONFIG=\u002Fworkspace\u002Flha\u002Fconfig\u002Fgcloud && gcloud projects list\")\n   ```\n   `gsutil` and `bq` read the same env token. **Don't name the token in a\n   `curl`\u002F`wget`** (`-H \"Authorization: Bearer $CLOUDSDK_AUTH_ACCESS_TOKEN\"`): the\n   exfil guard hard-blocks a network command that references a secret env var (by\n   design — it stops the agent exfiltrating the token). Use the gcloud-family CLIs,\n   which pick it up from the environment without naming it; a raw REST call that\n   must carry the token needs a `\u002Fgrant`.\n\nWhy this is the default:\n- **Short-lived (~1 h):** a single injection can't become standing access; on\n  expiry the user re-mints and updates the secret.\n- **Nothing durable in the sandbox** — no refresh token on `\u002Fworkspace` to reuse.\n- **Corp-clean:** consent already happened through the user's org-approved local\n  gcloud — no `Account restricted`, no custom OAuth client, no remote-bootstrap.\n- It still acts as the user for that window (short lifetime bounds misuse, doesn't\n  eliminate it) and carries the user's login scopes. For a **long unattended job**\n  the token expires (~1 h) and must be **re-minted and the secret updated** — by\n  design we keep no durable credential in the sandbox to fall back on.\n\n## `agents-cli` — call a remote agent (A2A \u002F ADK)\n\nTo hand a task to **another agent deployed remotely** (Cloud Run, Vertex Agent\nRuntime, or any A2A endpoint), shell out to `agents-cli` — no in-process wiring\nneeded. This is the outbound counterpart to in-process `subagent()`: the remote\nagent is its own service with its own state; you just send a prompt over HTTP.\n\nInstall (one-time; `uv` is already in the sandbox — it installs to `~\u002F.local\u002Fbin`):\n\n```\nbash(command=\"command -v agents-cli || uv tool install google-agents-cli\")\nbash(command=\"agents-cli --version\")\n```\n\n(Install pulls from wherever `google-agents-cli` is published — if the sandbox\ncan't reach that index, that's the same egress dependency as the Node\u002Fgcloud\ndownloads.)\n\nInvoke:\n\n```\nbash(command='agents-cli run \"summarize this repo\" --url https:\u002F\u002Fmy-agent-xxxx.run.app --mode a2a')\n```\n\n- `--mode a2a` for the A2A protocol; `--mode adk` for ADK SSE (`\u002Frun_sse`, or\n  `:streamQuery` on Agent Runtime). `--mode` is **required** with `--url`.\n- `--app-name \u003Cname>` to target a specific agent at that endpoint.\n- `--session-id \u003Cid>` to continue a conversation; `-v` for full JSON events.\n- stdout is the remote agent's final response — that *is* your result (blocking).\n  For a long-running remote task, run it with `process(action='spawn', command=...)`\n  and poll via the `process` tool (fire-and-forget).\n\n**Auth — usually automatic.** `agents-cli` auto-detects Google credentials from\nthe sandbox identity: an **ID token** (audience = service URL) for Cloud Run, an\n**access token** for Vertex AI \u002F Agent Runtime. For this to yield a usable token,\nthe sandbox\u002FCloud Run service account needs the right IAM on the target\n(`roles\u002Frun.invoker` for Cloud Run; Vertex perms for Agent Runtime) — a 401\u002F403\nis almost always missing IAM, not a CLI problem.\n\n**User-delegated auth** (call *as the user*): pass the token explicitly, which\noverrides auto-detect:\n\n```\nbash(command='agents-cli run \"...\" --url https:\u002F\u002F... --mode a2a -H \"Authorization: Bearer $USER_TOKEN\"')\n```\n\nSource the token from the secrets \u002F headless-auth subsystem (never inline a raw\nsecret into chat).\n\n`--url` is a thin client — it loads no local skills (the remote agent's skills\nare its own concern). If you need `agents-cli`'s **broader toolchain** (scaffold,\ndeploy, eval, observability, publish, workflow), install those skills on demand\nvia the **`find-skills`** skill.\n\n## `mcp-cli` — use tools exposed by an MCP server\n\nTo call tools served by an **MCP server** (GitHub, filesystem, databases,\nthird-party APIs) from the sandbox. This is the *client* side — using external\nMCP servers via `bash`, not running one. (Auth is **static token only** —\ninject the server's bearer via `${VAR}` headers, below; there is no OAuth\u002Fconsent\nflow. For GCP, use the token-as-secret path in the `gcloud` section, not MCP.)\n\nInstall — `install.sh` downloads a **checksum-verified, self-contained prebuilt\nbinary** (`mcp-cli-linux-x64`, ~100 MB) to `~\u002F.local\u002Fbin\u002Fmcp-cli`. It's compiled\nwith Bun but needs **no Bun\u002FNode** at install or runtime — it's standalone.\n\n**Don't pipe-to-bash.** `curl … | bash` is blocked by the tool policy (piping\nremote content to a shell). Download the script, then run it from a file:\n\n```\nbash(command=\"command -v mcp-cli || (curl -fsSLo \u002Ftmp\u002Fmcp_install.sh https:\u002F\u002Fraw.githubusercontent.com\u002Fphilschmid\u002Fmcp-cli\u002Fmain\u002Finstall.sh && bash \u002Ftmp\u002Fmcp_install.sh)\")\nbash(command=\"mcp-cli --version\")\n```\n\n(Optionally `read('\u002Ftmp\u002Fmcp_install.sh')` first — it just fetches the latest\nrelease binary and verifies its SHA256.) It installs to `~\u002F.local\u002Fbin`.\n\n**Configure servers — this is the real onboarding work.** `mcp-cli` is\nconfig-driven: it reads `mcp_servers.json`. Keep it on `\u002Fworkspace` (config is a\ndata file — it migrates) and point `mcp-cli` at it with `MCP_CONFIG_PATH` (its\nhighest-priority resolver); the default `~\u002F.config\u002Fmcp\u002F…` is not migrated:\n\n```\nexport MCP_CONFIG_PATH=\u002Fworkspace\u002Flha\u002Fconfig\u002Fmcp_servers.json\n```\n\nWrite that file (Claude-Desktop \u002F Gemini \u002F VS-Code compatible):\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-filesystem\", \"\u002Fworkspace\"]\n    },\n    \"remote-api\": {\n      \"url\": \"https:\u002F\u002Fmcp.example.com\",\n      \"headers\": { \"Authorization\": \"Bearer ${MCP_TOKEN}\" }\n    }\n  }\n}\n```\n\n- **stdio** server → `command` + `args` the sandbox can spawn (install the server\n  too, e.g. via `npx`\u002F`uvx`).\n- **HTTP** server → `url` (+ `headers`).\n- **Auth:** `${VAR}` in `headers` is substituted from the environment at config\n  load (missing var errors unless `MCP_STRICT_ENV=false`). Source that token from\n  the **secrets subsystem** (env-injection) — never inline a raw secret.\n\nUse (or install mcp-cli's **own usage skill** via `find-skills` for the full\nreference):\n\n```\nbash(command=\"mcp-cli\")                                              # list servers + tools\nbash(command=\"mcp-cli info filesystem read_file\")                    # tool schema\nbash(command=\"mcp-cli call filesystem read_file '{\\\"path\\\": \\\".\u002FREADME.md\\\"}'\")\n```\n\nUse `call` to invoke and `info` to inspect — `mcp-cli \u003Cserver> \u003Ctool>` directly\nis ambiguous and errors.\n\n## Failure cheat-sheet\n\n| Symptom | Cause \u002F fix |\n|---|---|\n| any tool \"command not found\" after a runtime upgrade | binaries live in `$HOME` and aren't migrated — reinstall per this skill (the `command -v` check does this) |\n| `node`\u002F`gcloud: command not found` after install | the `ln -sf … ~\u002F.local\u002Fbin\u002F` symlink step was skipped; re-run it (`~\u002F.local\u002Fbin` is on PATH, the versioned\u002FSDK bin dir isn't) |\n| `tar: ... cannot exec xz` | downloaded `.tar.xz`; use the `.tar.gz` build instead |\n| `gws` asks to log in again after an upgrade | its credentials were written under `$HOME` (not migrated); set `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` to the `\u002Fworkspace\u002Flha\u002Fconfig\u002F*` path on **every** call (gcloud keeps no persisted login — re-add the token secret) |\n| `gws` login token not saved \u002F no keyring | set `GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file` (alongside the config-dir export) |\n| `gws auth status` says `auth_method: none` but reads work | expected when `GOOGLE_WORKSPACE_CLI_TOKEN` is the source — `auth status` doesn't reflect the env token. Confirm with a real read, not `auth status`; don't start a login dance |\n| `gws auth login` hangs on the listener | expected headless — bridge the redirect (see `google-workspace` skill) or use a service account if no user is present |\n| `403 access_denied \"Account restricted\"` | Context-Aware Access on the OAuth client — don't fight it. Use the **token-as-secret** path: user runs `gcloud auth print-access-token` locally and stores it as the secret `CLOUDSDK_AUTH_ACCESS_TOKEN` |\n| network command blocked: \"reads a credential path or secret env var\" | Don't name `$CLOUDSDK_AUTH_ACCESS_TOKEN` (or any `*_TOKEN`\u002F`*_KEY`) in a `curl`\u002F`wget` — the exfil guard hard-blocks it. Let `gcloud`\u002F`gsutil`\u002F`bq` read the token from the env instead; a raw REST call needs a `\u002Fgrant` |\n| Unattended job has no GCP token | the `CLOUDSDK_AUTH_ACCESS_TOKEN` secret is missing or expired; surface \"needs a fresh token\" and stop — don't loop |\n| `agents-cli: command not found` | `uv tool install google-agents-cli` (uv is already in the sandbox) |\n| remote `agents-cli run --url` 401\u002F403 | missing IAM on the target (`roles\u002Frun.invoker` \u002F Vertex perms), not a CLI bug |\n| `--mode is required when using --url` | add `--mode a2a` (or `--mode adk`) to the remote call |\n| `mcp-cli: command not found` | download `install.sh` then `bash` the file (don't `\\| bash` — policy blocks it); installs to `~\u002F.local\u002Fbin` |\n| mcp-cli `AMBIGUOUS_COMMAND` | use `mcp-cli call`\u002F`info \u003Cserver> \u003Ctool>`, not `mcp-cli \u003Cserver> \u003Ctool>` |\n| mcp-cli `${VAR}` missing at config load | export the token (from the secrets subsystem) or set `MCP_STRICT_ENV=false` |\n",{"name":5,"description":7},"main","665f7b2a181686f2ba3c6c942e9b30a084b12ec3","core\u002Fpython\u002Flong-horizon-harness\u002Fhorizon\u002Fbuiltin_skills\u002Fbootstrap-google-tools",2958,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes","https:\u002F\u002Fadk.dev","https:\u002F\u002Fgithub.com\u002Fgoogle","https:\u002F\u002Fopensource.google\u002F","Google ❤️ Open Source","2026-11-12 02:02:17",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add google\u002Fadk-recipes --skill bootstrap-google-tools",{"tool":64,"command":65},"bunx","bunx skills add google\u002Fadk-recipes --skill bootstrap-google-tools",{"tool":67,"command":68},"pnpm","pnpm dlx skills add google\u002Fadk-recipes --skill bootstrap-google-tools","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fcore\u002Fpython\u002Flong-horizon-harness\u002Fhorizon\u002Fbuiltin_skills\u002Fbootstrap-google-tools\u002FSKILL.md",true,[],[73,95,129,153,169,185],{"skillNo":74,"name":75,"nameZh":6,"description":76,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":77,"categories":78,"keywords":86,"publishedAt":43},"01M6991EKEG8XEM3VWW4VGV0ZQ","retail-virtual-tryon","Creates virtual try-on agents supporting image and video (catwalk animation) try-ons on Google Cloud (Gemini image models and Veo on Gemini Enterprise Agent Platform). Handles resource setup, user photo uploading, image\u002Fvideo generation pipelines, local testing, and evaluation.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fplugins\u002Fretail\u002Fskills\u002Fvirtual-tryon\u002FSKILL.md",[79,82,85],{"categoryNo":80,"categoryName":81,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":83,"categoryName":84,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[87,88,89,9,90,91,92,93,94],"retail virtual tryon","google cloud","image","testing","gemini","genai","adk","gemini enterprise agent platform",{"skillNo":96,"name":97,"nameZh":6,"description":98,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":110,"publishedAt":43},"01M6991ABTZW7FCPREXY8GD4RG","retail-product-search","Creates product search agents with semantic search and RAG on Google Cloud (Vector Search on Gemini Enterprise Agent Platform, BigQuery, embeddings). Use when the user wants to \"build a product search agent\", \"create an e-commerce search\", \"make a shopping assistant\", \"set up semantic catalog discovery\", \"ingest products into Vector Search\", or \"deploy a retail RAG agent\". Handles the full pipeline: catalog data ingestion to BigQuery, Gemini Enterprise Agent Platform Vector Search collection setup, ADK agent scaffolding, evaluation, and Cloud Run deployment.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fplugins\u002Fretail\u002Fskills\u002Fproduct-search\u002FSKILL.md",[101,104,105],{"categoryNo":102,"categoryName":103,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":106,"categoryName":107,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000031","产品经理","PROFESSION","适用职业",[111,112,113,94,93,91,114,9,88,115,116,117,118,119,120,121,122,123,124,125,126,127,128],"retail product search","product","search","assistant","pipeline","when","commerce","scaffolding","shopping","up","ingestion","collection","SET","vector","apache","run","create","rag",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":136,"publishedAt":43},"01M69918HZCYZHD7K9Y9ZSD287","routines","Use for a recurring unattended task (cron; pull data, open a PR, post a digest), or to test\u002Fdry-run a routine first. Explains authoring and testing via the routine tool.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fcore\u002Fpython\u002Flong-horizon-harness\u002Fhorizon\u002Fbuiltin_skills\u002Froutines\u002FSKILL.md",[135],{"categoryNo":80,"categoryName":81,"taxonomyType":21,"taxonomyTypeDesc":22},[131,137,138,139,140,141,142,143,144,32,145,146,147,148,149,150,126,151,90,152],"dry","routine","for","post","via","authoring","digest","task","recurring","pr","tool","open","first","pull","test","data",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":159,"publishedAt":43},"01M699178ZDFDXEZ11DG1Y9CTF","policy","Inspect the per-workspace tool-policy overlay (.lha\u002Fpolicies.jsonl) that gates destructive or sensitive tool calls, and tell the user what to change if they want a rule added or removed.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fcore\u002Fpython\u002Flong-horizon-harness\u002Fhorizon\u002Fbuiltin_skills\u002Fpolicy\u002FSKILL.md",[],[155,160,161,162,163,164,165,166,167,36,147,168],"gates","overlay","tool calls","inspect","calls","jsonl","rule","user","change",{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":173,"categories":174,"keywords":175,"publishedAt":43},"01M69915F8591SQBA1ZHK6NDA7","google-workspace","Read\u002Fwrite Google Drive, Docs, Sheets, Gmail, Calendar, Chat, Tasks, Slides via the `gws` CLI. Needs an OAuth client or service account configured first. Use for any Google Workspace task.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fcore\u002Fpython\u002Flong-horizon-harness\u002Fhorizon\u002Fbuiltin_skills\u002Fgoogle-workspace\u002FSKILL.md",[],[36,176,9,31,32,177,178,179,149,180,181,182,41,42,144,139,29,183,141,184,30],"google workspace","write","read","slides","OAuth","tasks","docs","client","chat",{"skillNo":186,"name":187,"nameZh":6,"description":188,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":189,"categories":190,"keywords":192,"publishedAt":43},"01M69914416KTZ6Z0WD425YYJ0","find-skills","Discover\u002Finstall NEW agent skills from external sources (skills.sh). Use for capabilities you lack, e.g. \"find a skill for X\". Do NOT use to list skills you already have; see `\u003Cavailable_skills>`.","https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fadk-recipes\u002Fblob\u002Fmain\u002Fcore\u002Fpython\u002Flong-horizon-harness\u002Fhorizon\u002Fbuiltin_skills\u002Ffind-skills\u002FSKILL.md",[191],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[193,194,139,195,196,197,198,199,32,33,200,201,202],"find skills","find","you","sources","discover","new agent","do","list","list skills","capabilities"]