Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
Expand Down
56 changes: 50 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,33 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

**gcpath** is a CLI utility for querying Google Cloud Platform (GCP) resource hierarchy paths. It translates between GCP resource names (e.g., `folders/12345`) and human-readable paths (e.g., `//example.com/department/team`).
**gcpath** is an AXI-compliant CLI utility for querying Google Cloud Platform (GCP) resource hierarchy paths. It translates between GCP resource names (e.g., `folders/12345`) and human-readable paths (e.g., `//example.com/department/team`).

Key features:

- AXI-compliant output: TOON format by default, with `--format toon|json|yaml|rich`
- Dual API modes: Cloud Asset API (default, fast) and Resource Manager API (slower, different permissions)
- Commands: `ls`, `tree`, `name` (path → resource name), `path` (resource name → path)
- Commands: `ls`, `tree`, `name`, `path`, `find`, `ancestors`, `stats`, `diagram`
- Scoped loading to improve performance for large hierarchies
- Support for organizationless projects (`//_` prefix)
- Ambient context hooks for Claude Code and Codex (`gcpath hook install`)

## AXI Compliance

gcpath follows the [AXI specification](https://axi.md/) for agent-friendly CLI tools:

- **TOON default output**: All commands output TOON format by default (token-efficient, structured)
- **`--format` flag**: `toon` (default), `json`, `yaml`, `rich` (human-friendly colored tables)
- **Pre-computed aggregates**: `ls` shows `count: N of M total`, `find` shows match count
- **Definitive empty states**: `0 resources found` with contextual help
- **Structured errors**: Errors go to stdout in TOON format, not stderr Rich markup
- **Content-first home**: Running `gcpath` with no args shows a live dashboard from cache
- **Contextual help**: `help[]` sections appended after list outputs with relevant next-step commands
- **`--fields` flag**: Control which columns appear in tabular output (`path,type,display_name,resource_name,project_id,labels,tags`)
- **`--full` flag**: Expand truncated labels/tags without truncation
- **No interactive prompts**: All confirm prompts removed; commands just proceed
- **`tree` is human-oriented**: Classic unicode tree output, not TOON. Agents should use `ls -R` instead. No `help[]` suggestions for `tree` in agent followups.
- **`diagram` is raw output**: Mermaid/D2 text output as-is, no TOON wrapping

## Setup and Build

Expand Down Expand Up @@ -59,8 +78,18 @@ The codebase is organized into focused, single-responsibility modules:

- **`formatters.py`**: Display formatting logic for paths, trees, and resource filtering.

- **`serializers.py`**: Output serialization — TOON, JSON, YAML serializers for all commands.

- **`toon.py`**: Thin wrapper around `toon_format.encode()` plus gcpath-specific AXI helpers (error formatting, empty states, help sections, dashboards).

- **`hooks.py`**: Agent session hook management (install/uninstall/status for Claude Code and Codex).

- **`cli.py`**: CLI commands and entry points using Typer framework.

- **`cache.py`**: Cache management for hierarchy data.

- **`config.py`**: Configuration management (entrypoint settings).

### Data Flow

1. **Hierarchy Loading** (`Hierarchy.load()`):
Expand All @@ -78,17 +107,20 @@ The codebase is organized into focused, single-responsibility modules:
- Loaders use filters to only fetch descendants of that resource
- Significantly reduces API calls and latency for large hierarchies

4. **Display**: CLI uses formatters to present data:
- Direct children filtering for `ls` (non-recursive mode)
- Tree recursion with depth limiting
- Path display with URL encoding via `path_escape()`
4. **Output**: CLI dispatches to serializers based on `--format`:
- `toon` (default): TOON tabular arrays, objects, help sections
- `json`/`yaml`: Structured dicts via `dump_json`/`dump_yaml`
- `rich`: Rich-colored tables and tree widgets
- `tree` command always uses Rich tree output (not TOON)
- `diagram` command always outputs raw Mermaid/D2 text

### Key Design Patterns

- **Lookup Maps**: `Hierarchy` maintains `_orgs_by_name`, `_folders_by_name`, `_projects_by_name` for O(1) lookups
- **Protobuf Objects**: Use actual `google.cloud.resourcemanager_v3` protobuf objects (not mocks) throughout the data layer
- **Optional Organization**: Projects can be organizationless (no parent organization)
- **Lightweight Path Resolution**: `Hierarchy.resolve_ancestry()` traverses up the hierarchy without loading full state
- **Content-first home**: `gcpath` with no args reads cache and shows dashboard, never shows help text

## Important Implementation Details

Expand All @@ -113,6 +145,15 @@ The Asset API returns STRUCT fields as `MapComposite` objects. Key handling:
- `ancestors_filter`: Returns all descendants including in ancestors list (recursive)
- Default (no filter): Returns org-level or root-level resources

### TOON Output Conventions

- Default `ls` schema: `{path,type,display_name}` (3 fields); adds `project_id` for projects
- `--fields` overrides: any subset of `path,type,display_name,resource_name,project_id,labels,tags`
- Labels/tags truncated to 5 entries by default; `--full` shows all
- `count: N of M total` header on list outputs
- `help[]` sections with next-step suggestions (omitted for single-result commands like `name`, `path`)
- Errors to stdout as `error: <message>` with optional `help[]`

## Testing

Test files mirror source organization:
Expand All @@ -121,6 +162,7 @@ Test files mirror source organization:
- `test_loaders.py`: GCP API loading functions
- `test_parsers.py`: Asset API response parsing
- `test_formatters.py`: Display formatting
- `test_serializers.py`: Output serialization (TOON, JSON, YAML)
- `test_cli.py`: CLI command integration

Run specific test:
Expand Down Expand Up @@ -181,3 +223,5 @@ The project uses **semantic versioning** with automated release workflow via Git
- All exceptions inherit from `GCPathError` base class
- CLI commands should wrap GCP API calls with error handling
- Follow conventional commits for automatic version bumping
- TOON encoding uses `toon_format` library (imported as `toon_format`)
- `toon.py` is a thin wrapper that adds gcpath-specific AXI conventions on top of `toon_format.encode()`
109 changes: 75 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
# gcpath

`gcpath` is a CLI utility to query Google Cloud Platform resource hierarchy paths.
It helps you translate between GCP resource names (e.g., `folders/12345`) and human-readable paths (e.g., `//example.com/department/team`).
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/)
[![AXI Compliant](https://img.shields.io/badge/AXI-compliant-green.svg)](https://axi.md/)
[![PyPI](https://img.shields.io/pypi/v/gcpath.svg)](https://pypi.org/project/gcpath/)
[![CI](https://github.com/tardigrde/gcpath/actions/workflows/ci.yml/badge.svg)](https://github.com/tardigrde/gcpath/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/tardigrde/gcpath/branch/main/graph/badge.svg)](https://codecov.io/gh/tardigrde/gcpath)

## Why should I use gcpath?
`gcpath` is an agent-native, read-only CLI for querying Google Cloud Platform resource hierarchy paths. It translates between GCP resource names (e.g., `folders/12345`) and human-readable paths (e.g., `//example.com/department/team`).

- familiar linux-like CLI
- 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
## Why gcpath?

GCP's resource hierarchy — organizations, folders, projects — is central to how teams structure access, billing, and governance. But navigating it with `gcloud` means juggling multiple subcommands, parsing verbose output, and stitching together parent-child relationships yourself.

gcpath gives you a single tool that treats the hierarchy as a first-class concept: list, search, resolve paths, and traverse ancestry with Unix-style commands.

### Built for AI agents

gcpath is designed from the ground up to be used by AI coding agents (Claude Code, Codex, etc.), not just humans:

- **Fully read-only** — every command is a query, never a mutation. Agents can run gcpath freely with zero risk of modifying your GCP environment.
- **[AXI-compliant](https://axi.md/) output** — defaults to [TOON format](https://github.com/mwmwmw/toon-format), a token-efficient structured format that agents parse natively. Includes pre-computed aggregates, definitive empty states, structured errors, and contextual help sections — no screen-scraping required.
- **Ambient context hooks** — `gcpath hook install` registers a session-start hook with Claude Code and Codex so the agent automatically knows your GCP hierarchy context when a session begins. No manual prompting needed.
- **Agent Skill definition** — ships with an [Agent Skills](https://agentskills.io) manifest that teaches agents when to use gcpath, what commands are available, and common workflows — so the agent reaches for the right tool without you telling it to.
- **Multiple output formats** — `--format toon|json|yaml|rich` lets agents pick the format that suits the task, with TOON as the default for maximum token efficiency.

### Also great for humans

- Familiar Linux-like CLI (`ls`, `tree`, `find`)
- Stay in the terminal for quick hierarchy lookups
- Rich colored output with `--format rich`
- No need to learn the complex `gcloud` resource manager interface

## Features

Expand All @@ -20,8 +41,8 @@ It helps you translate between GCP resource names (e.g., `folders/12345`) and hu
- **Find**: Search for resources by name using glob patterns.
- **Ancestors**: Show the full ancestry chain from any resource up to the org root.
- **Type Filtering**: Filter `ls`, `tree`, and `find` output by resource type (folder, project, organization).
- **Structured Output**: `--json` and `--yaml` flags for machine-readable output across all commands.
- **Dual Mode**:
- **Structured Output**: `--format toon|json|yaml|rich` for machine-readable or human-friendly output across all commands.
- **Dual API Mode**:
- **Cloud Asset API (Default)**: Fast, bulk loading using GCP Cloud Asset Inventory.
- **Resource Manager API**: Iterative loading using standard Resource Manager API (slower, but different permissions).

Expand Down Expand Up @@ -89,8 +110,8 @@ gcpath diagram
gcpath diagram folders/123456789 --format d2

# Machine-readable output
gcpath --json ls -R
gcpath --yaml tree -L 2
gcpath --format json ls -R
gcpath --format yaml tree -L 2
```

## Usage
Expand Down Expand Up @@ -246,31 +267,32 @@ gcpath ancestors projects/my-project
gcpath ancestors folders/123456789

# JSON output for scripting
gcpath --json ancestors projects/my-project
gcpath --format json ancestors projects/my-project
```

### Structured Output (`--json`, `--yaml`)
### Output Formats (`--format`)

All commands support `--format toon|json|yaml|rich`:

All commands support `--json` and `--yaml` global flags for machine-readable output:
| Format | Best for | Description |
|--------|----------|-------------|
| `toon` | AI agents (default) | Token-efficient structured format with aggregates and help sections |
| `json` | Scripting / piping | Standard JSON |
| `yaml` | Config files / readability | Standard YAML |
| `rich` | Humans in a terminal | Colored tables and trees |

```bash
# JSON output
gcpath --json ls -R
gcpath --json tree -L 2
gcpath --json find "*prod*"
gcpath --json ancestors projects/my-project
gcpath --json name //example.com/engineering
gcpath --json path folders/123456789
# Default TOON output (agent-optimized)
gcpath ls -R

# YAML output
gcpath --yaml ls
gcpath --yaml tree
```
# JSON for scripting
gcpath --format json ls -R | jq '.[] | select(.type == "project")'

The flags are mutually exclusive. Structured output goes to stdout with status messages redirected to stderr, so it's safe to pipe:
# Rich colored output for humans
gcpath --format rich ls -R

```bash
gcpath --json ls -R | jq '.[] | select(.type == "project")'
# YAML output
gcpath --format yaml ancestors projects/my-project
```

## API Modes
Expand Down Expand Up @@ -479,11 +501,30 @@ 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
## Agent Integration

gcpath is designed to work seamlessly with AI coding agents. There are two complementary ways to set this up.

### Ambient Context Hooks

Session-start hooks inject your GCP hierarchy context into the agent's conversation automatically — the agent knows about your orgs, folders, and projects from the moment a session begins.

```bash
# Install hooks for Claude Code and Codex
gcpath hook install

# Check hook status
gcpath hook status

# Remove hooks
gcpath hook uninstall
```

This registers a `SessionStart` hook that runs `gcpath hook run`, which outputs a compact TOON dashboard of your cached hierarchy (under 500 tokens). The agent sees this context without you having to explain your GCP setup each session.

gcpath ships with an [Agent Skills](https://agentskills.io) definition so AI agents (Claude, Codex, etc.) can discover and use it without extra setup.
### Agent Skill

Install the skill into your agent environment:
gcpath ships with an [Agent Skills](https://agentskills.io) definition that teaches agents when and how to use it.

```bash
bunx skills add github:tardigrde/gcpath --skill gcpath
Expand All @@ -493,10 +534,10 @@ npx skills add github:tardigrde/gcpath --skill gcpath

The skill teaches the agent:

- when to reach for `gcpath` vs other GCP tools
- when to reach for `gcpath` vs other GCP tools (and when *not* to — e.g., IAM, billing, compute)
- all commands, flags, and output formats
- common workflows (ancestry lookup, scoped listing, path ↔ name conversion)
- gotchas (organizationless projects, caching behaviour, API modes)
- gotchas (organizationless projects, caching behavior, 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.

Expand Down
14 changes: 14 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
coverage:
precision: 2
round: down
range: "60...100"

status:
project:
default:
target: auto
threshold: 2%
patch:
default:
target: 80%
threshold: 5%
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies = [
"google-cloud-resource-manager>=1.15.0",
"pyyaml>=6.0",
"rich>=14.2.0",
"toon-format @ git+https://github.com/toon-format/toon-python.git@90861444e5bf7d6408e91bd95e58dba41dd99be8",
"typer>=0.20.1",
]

Expand All @@ -47,6 +48,9 @@ dev = [
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.metadata]
allow-direct-references = true

[tool.hatch.build.targets.wheel]
packages = ["src/gcpath"]

Expand Down
Loading
Loading