diff --git a/README.md b/README.md index 72212f6..c141a46 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ It helps you translate between GCP resource names (e.g., `folders/12345`) and hu - you can stay in the terminal for quick resource hierarchy lookups - no need to learn the complex `gcloud` interface - look-up only commands, so coding agents can't do harm using it +- installable as an [Agent Skill](#agent-skill) so AI agents know how to use it ## Features @@ -478,6 +479,27 @@ except GCPathError as e: | `PathParsingError` | Raised when a path string cannot be parsed. | | `path_escape()` | URL-encodes a display name for safe use in paths. | +## Agent Skill + +gcpath ships with an [Agent Skills](https://agentskills.io) definition so AI agents (Claude, Codex, etc.) can discover and use it without extra setup. + +Install the skill into your agent environment: + +```bash +bunx skills add github:tardigrde/gcpath --skill gcpath +# or +npx skills add github:tardigrde/gcpath --skill gcpath +``` + +The skill teaches the agent: + +- when to reach for `gcpath` vs other GCP tools +- all commands, flags, and output formats +- common workflows (ancestry lookup, scoped listing, path ↔ name conversion) +- gotchas (organizationless projects, caching behaviour, API modes) + +See [`skills/gcpath/SKILL.md`](skills/gcpath/SKILL.md) for the full skill definition and [`skills/gcpath/references/commands.md`](skills/gcpath/references/commands.md) for the compact command reference. + ## Acknowledgments Thanks for [xebia/gcp-path](https://github.com/xebia/gcp-path) for the inspiration! diff --git a/skills/gcpath/SKILL.md b/skills/gcpath/SKILL.md new file mode 100644 index 0000000..b7edd92 --- /dev/null +++ b/skills/gcpath/SKILL.md @@ -0,0 +1,143 @@ +--- +name: gcpath +description: > + Use this skill when you need to navigate, query, or resolve resources in a + Google Cloud Platform (GCP) organization hierarchy — listing folders or + projects under a resource, converting between resource names (e.g. + folders/12345) and human-readable paths (e.g. //example.com/dept/team), + searching resources by display name, showing ancestry chains, or generating + hierarchy diagrams. Do NOT use for IAM policy, billing, cost analysis, + Kubernetes, or Compute Engine resources. +license: MIT +compatibility: > + Requires gcpath CLI (pip install gcpath or uvx gcpath) and GCP Application + Default Credentials (gcloud auth application-default login or + GOOGLE_APPLICATION_CREDENTIALS env var). +allowed-tools: Bash(gcpath:*) Bash(uvx gcpath:*) +metadata: + author: tardigrde + repository: https://github.com/tardigrde/gcpath +--- + +# gcpath + +A read-only CLI for querying GCP resource hierarchy paths. Translates between +GCP resource names (`folders/12345`) and human-readable paths +(`//example.com/dept/team`) and lets you explore the org → folder → project +tree. + +## When to Use + +**Use gcpath when asked to:** + +- List folders or projects inside a GCP folder or organization +- Find the hierarchy path of a project or folder +- Convert a human-readable path to a GCP resource name (for use in `gcloud`, Terraform, etc.) +- Search for a project or folder by display name +- Show the ancestry chain of any resource +- Generate a Mermaid or D2 diagram of the resource hierarchy +- Count folders and projects under a scope + +**Do NOT use gcpath for:** + +- IAM policy management (`gcloud projects get-iam-policy` is the right tool) +- Billing or cost queries +- Compute, GKE, Cloud Run, or other product-level resources +- Resource creation or modification (gcpath is read-only) + +## Running gcpath + +Prefer the bare command if gcpath is already installed: + +```bash +gcpath +``` + +If not installed, use uvx (no install required): + +```bash +uvx gcpath +``` + +**Required IAM role** (on the org or target scope): `roles/cloudasset.viewer` +(default API mode), or `roles/resourcemanager.folderViewer` + +`roles/resourcemanager.projectViewer` (with `-U` flag). + +## Core Concepts + +- **Resource names**: `organizations/123`, `folders/456`, `projects/789` or `projects/my-project-id` +- **Paths**: `//example.com/Department/Team` — double-slash prefix, then org domain, then slash-separated display names +- **Organizationless projects**: shown with `//_/` prefix (no org parent) +- **Entrypoint**: a persistent default root resource (`gcpath config set-entrypoint folders/123`) + +## Common Workflows + +### Find which folder/org a project belongs to + +```bash +gcpath path projects/my-project +gcpath ancestors projects/my-project # full chain with display names +``` + +### List all projects in a folder + +```bash +gcpath ls folders/123 -R --type project +``` + +### Convert a path to a resource name (e.g. for gcloud/Terraform) + +```bash +gcpath name //example.com/Engineering/Backend +# → folders/456789 +``` + +### Search by display name + +```bash +gcpath find "*payments*" --type project +gcpath find "prod-*" folders/123 # scoped to a subtree +``` + +### Explore a subtree + +```bash +gcpath tree folders/123 -L 3 -i # tree, depth 3, show resource IDs +gcpath ls folders/123 -R -L 2 # flat list, depth 2 +``` + +### Machine-readable output + +```bash +gcpath --json ls -R | jq '.[] | .path' +gcpath --yaml ancestors projects/my-project +``` + +### Filter by GCP labels or tags + +```bash +gcpath ls -R --label env=production --label team=platform +gcpath find "*" --tag cost-center=eng +``` + +## Key Flags (most commands) + +| Flag | Short | Description | +|------|-------|-------------| +| `--json` / `--yaml` | | Structured output (global) | +| `--force-refresh` | `-F` | Bypass cache, re-fetch from GCP | +| `--recursive` | `-R` | List all descendants (`ls` only) | +| `--level N` | `-L` | Max depth | +| `--type TYPE` | `-t` | Filter: `folder`, `project`, `organization` | +| `--no-use-asset-api` | `-U` | Use Resource Manager API instead | + +For the full flag reference, read [`references/commands.md`](references/commands.md). + +## Gotchas + +- `tree`, `diagram`, `stats` do not accept projects as starting point (leaf nodes). +- Organizationless projects appear under `//_/` in paths. +- `--label` / `--tag` filters are ANDed when repeated. +- `gcpath path` and `gcpath ancestors` hit the GCP API directly — no cache needed, always fast. +- Scoped loads (`gcpath ls folders/123`) are not cached unless that folder is the configured entrypoint. +- Use `-U` if you get "Cloud Asset API not enabled" errors. diff --git a/skills/gcpath/references/commands.md b/skills/gcpath/references/commands.md new file mode 100644 index 0000000..c0e7de7 --- /dev/null +++ b/skills/gcpath/references/commands.md @@ -0,0 +1,243 @@ +# gcpath Command Reference + +Quick reference for all gcpath commands and flags. + +## Global Flags + +Apply to every command (place before the subcommand): + +| Flag | Short | Default | Description | +|------|-------|---------|-------------| +| `--entrypoint RESOURCE` | `-e` | config/none | Scope all commands to this resource | +| `--json` | | false | JSON output | +| `--yaml` | | false | YAML output | +| `--use-asset-api / --no-use-asset-api` | `-u / -U` | true (asset) | API backend | +| `--debug` | | false | Debug logging | + +--- + +## `ls [RESOURCE]` + +List direct children (or descendants with `-R`) of a resource. + +| Flag | Short | Description | +|------|-------|-------------| +| `--long` | `-l` | Show resource names alongside paths | +| `--recursive` | `-R` | List all descendants | +| `--level N` | `-L N` | Max depth (requires `-R`) | +| `--type TYPE` | `-t` | Filter: `folder`, `project`, `organization` | +| `--show-labels` | | Show GCP labels column | +| `--show-tags` | | Show GCP tags column | +| `--label KEY=VALUE` | | Filter by label (repeatable, ANDed) | +| `--tag KEY=VALUE` | | Filter by tag (repeatable, ANDed) | +| `--force-refresh` | `-F` | Bypass cache | + +**Examples:** + +``` +gcpath ls +gcpath ls folders/123 +gcpath ls folders/123 -R -L 2 --type project +gcpath ls -R --label env=prod --show-labels --json +``` + +--- + +## `tree [RESOURCE]` + +Display resource hierarchy as an interactive tree. + +| Flag | Short | Description | +|------|-------|-------------| +| `--level N` | `-L N` | Max display depth | +| `--ids` | `-i` | Show resource names next to display names | +| `--type TYPE` | `-t` | Filter: `folder`, `project` | +| `--yes` | `-y` | Skip confirmation for large unscoped loads | +| `--show-labels` | | Show labels in tree nodes | +| `--show-tags` | | Show tags in tree nodes | +| `--label KEY=VALUE` | | Filter by label (repeatable, ANDed) | +| `--tag KEY=VALUE` | | Filter by tag (repeatable, ANDed) | +| `--force-refresh` | `-F` | Bypass cache | + +**Examples:** + +``` +gcpath tree +gcpath tree folders/123 -L 3 -i +gcpath tree --type project --json +``` + +--- + +## `diagram [RESOURCE]` + +Generate a Mermaid or D2 diagram of the hierarchy. + +| Flag | Short | Description | +|------|-------|-------------| +| `--format FORMAT` | `-f` | `mermaid` (default) or `d2` | +| `--level N` | `-L N` | Max display depth | +| `--ids` | `-i` | Show resource names in node labels | +| `--output FILE` | `-o` | Write to file instead of stdout | +| `--yes` | `-y` | Skip confirmation | +| `--force-refresh` | `-F` | Bypass cache | + +**Examples:** + +``` +gcpath diagram folders/123 +gcpath diagram -f d2 -o org.d2 +gcpath diagram folders/123 -L 2 --ids +``` + +--- + +## `stats [RESOURCE]` + +Count organizations, folders, and projects in scope. Resource must be `organizations/...` or `folders/...`. + +| Flag | Short | Description | +|------|-------|-------------| +| `--force-refresh` | `-F` | Bypass cache | + +**Examples:** + +``` +gcpath stats +gcpath stats folders/123 +gcpath stats organizations/456 +``` + +--- + +## `name PATH [PATH ...]` + +Convert human-readable path(s) to GCP resource name(s). + +| Flag | Short | Description | +|------|-------|-------------| +| `--id` | | Print only the numeric ID (not the full resource name) | +| `--force-refresh` | `-F` | Bypass cache | + +**Examples:** + +``` +gcpath name //example.com/Engineering/Backend +gcpath name //example.com/Dept/Team --id +gcpath name //a.com/X //a.com/Y --json +``` + +--- + +## `path RESOURCE [RESOURCE ...]` + +Convert GCP resource name(s) to human-readable path(s). Does not load full hierarchy — resolves via GCP ancestry API directly. + +No extra flags (uses global `--json` / `--yaml`). + +**Examples:** + +``` +gcpath path folders/123 +gcpath path projects/my-project +gcpath path folders/123 folders/456 --json +``` + +--- + +## `find PATTERN [RESOURCE]` + +Search resources by display name glob pattern (case-insensitive). Supports `*` and `?`. + +| Flag | Short | Description | +|------|-------|-------------| +| `--type TYPE` | `-t` | Filter: `folder`, `project`, `organization` | +| `--label KEY=VALUE` | | Filter by label (repeatable, ANDed) | +| `--tag KEY=VALUE` | | Filter by tag (repeatable, ANDed) | +| `--force-refresh` | `-F` | Bypass cache | + +**Examples:** + +``` +gcpath find "*payments*" +gcpath find "prod-*" --type project +gcpath find "*" folders/123 --label env=staging +gcpath find "data-*" --json +``` + +--- + +## `ancestors RESOURCE` + +Show the full ancestry chain from a resource up to the organization root. Works for `organizations/...`, `folders/...`, and `projects/...`. + +No extra flags (uses global `--json` / `--yaml`). + +**Output columns:** Resource Name, Display Name, Type + +**Examples:** + +``` +gcpath ancestors projects/my-project +gcpath ancestors folders/123 --json +``` + +--- + +## `cache status` + +Show cache age, size, scope, and resource counts. + +No flags. + +--- + +## `cache clear` + +Delete the local cache file, forcing next run to re-fetch from GCP. + +No flags. + +--- + +## `config set-entrypoint RESOURCE` + +Set a persistent default entrypoint. Subsequent commands will scope to this resource unless overridden with `-e`. + +**Example:** + +``` +gcpath config set-entrypoint folders/123 +``` + +--- + +## `config show` + +Display current configuration and config file location. + +--- + +## `config clear-entrypoint` + +Remove the configured default entrypoint. + +--- + +## Resource Name Formats + +| Resource | Format | Example | +|----------|--------|---------| +| Organization | `organizations/ID` | `organizations/123456789` | +| Folder | `folders/ID` | `folders/987654321` | +| Project (by number) | `projects/NUMBER` | `projects/111222333` | +| Project (by ID) | `projects/PROJECT-ID` | `projects/my-project` | + +## Path Format + +``` +//DOMAIN/SEGMENT/SEGMENT/... +``` + +- `//example.com/Engineering/Backend/Services` +- `//_/OrphanedProject` (organizationless)