{"id":47613294,"url":"https://github.com/gkoreli/ghx","last_synced_at":"2026-04-15T08:04:01.272Z","repository":{"id":343059051,"uuid":"1175713059","full_name":"gkoreli/ghx","owner":"gkoreli","description":"Agent-first GitHub code exploration. GraphQL batching, code maps (~92% token reduction), AND search, repo discovery with README previews. Codemode TypeScript sandbox, MCP server. Go.","archived":false,"fork":false,"pushed_at":"2026-04-01T22:19:42.000Z","size":345,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"mainline","last_synced_at":"2026-04-02T04:15:29.869Z","etag":null,"topics":["ai-agents","cli","code-search","developer-tools","github","golang","mcp"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@gkoreli/ghx","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gkoreli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-08T04:08:37.000Z","updated_at":"2026-04-01T22:19:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gkoreli/ghx","commit_stats":null,"previous_names":["gkoreli/ghx"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/gkoreli/ghx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkoreli%2Fghx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkoreli%2Fghx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkoreli%2Fghx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkoreli%2Fghx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gkoreli","download_url":"https://codeload.github.com/gkoreli/ghx/tar.gz/refs/heads/mainline","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkoreli%2Fghx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31831849,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T07:17:56.427Z","status":"ssl_error","status_checked_at":"2026-04-15T07:17:30.007Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","cli","code-search","developer-tools","github","golang","mcp"],"created_at":"2026-04-01T20:51:03.789Z","updated_at":"2026-04-15T08:04:01.263Z","avatar_url":"https://github.com/gkoreli.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ghx — GitHub Code Exploration for AI Agents\n\nOne command does what takes 3-5 API calls. Batch file reads, code maps, search — all via `gh` CLI. Write JS programs that compose operations in one round-trip.\n\n## Why\n\nAn agent wants to understand `packages/shadcn/src/utils/` in [shadcn-ui/ui](https://github.com/shadcn-ui/ui):\n\n**With `gh` CLI** — 4 turns, 4 API calls, reads 3 full files (3,761 tokens), sees 3 of 34 files:\n```\ngh api /repos/shadcn-ui/ui/contents/packages/shadcn/src/utils       → JSON with shas, urls, links (480 tokens for a file list)\ngh api /repos/.../get-config.ts --jq '.content' | base64 -d         → full file (1,981 tokens — agent only needed exports)\ngh api /repos/.../registries.ts --jq '.content' | base64 -d         → full file (676 tokens)\ngh api /repos/.../frameworks.ts --jq '.content' | base64 -d         → full file (624 tokens)\n```\n\n**With ghx** — 2 turns, 2 API calls, maps 10 files (3,058 tokens), sees signatures of all 10:\n```\nghx read shadcn-ui/ui packages/shadcn/src/utils                     → directory listing (199 tokens)\nghx read shadcn-ui/ui \"packages/shadcn/src/utils/*.ts\" --map        → signatures of 10 files (2,859 tokens)\n```\n\nSame token budget. The `gh` agent read 3 full files. The ghx agent saw the structure of 10 — imports, exports, function signatures — and knows which ones to drill into. Pass a file, get content. Pass a directory, get a listing. Pass a glob, get matching files. Same command, always useful output.\n\n| Tool | Files per call | Matching context | Programmable | Dependencies |\n|------|---------------|-----------------|-------------|-------------|\n| GitHub MCP | 1 | No | No (~10K token schemas) | Go binary |\n| `gh` CLI | 1 | No | No (exact phrase, base64, no README) | `gh` |\n| **ghx** | **1-10 (batch)** | **Yes** | **Yes (codemode)** | **`gh`** |\n\n## Install\n\n```bash\n# Zero install — just run it\nnpx @gkoreli/ghx explore vercel/next.js\n\n# Homebrew\nbrew install gkoreli/tap/ghx\n\n# npm (global)\nnpm install -g @gkoreli/ghx\n\n# Go\ngo install github.com/gkoreli/ghx/v2@latest\n\n# Build from source\ncd v2 \u0026\u0026 go build -o ghx .\n```\n\nRequires: [gh CLI](https://cli.github.com/) authenticated (`gh auth login`).\n\n### MCP Config (Claude Desktop, Cursor)\n\n```json\n{\n  \"mcpServers\": {\n    \"ghx\": {\n      \"command\": \"npx\",\n      \"args\": [\"@gkoreli/ghx\", \"serve\"]\n    }\n  }\n}\n```\n\nNo install step — npx downloads and caches the binary on first run.\n\n## Commands\n\n```bash\nghx explore \u003cowner/repo\u003e                    # Branch + tree + README in 1 API call\nghx explore \u003cowner/repo\u003e \u003cpath\u003e             # Subdirectory listing\nghx read \u003cowner/repo\u003e \u003cf1\u003e [f2] [f3]       # Read 1-10 files (GraphQL batching)\nghx read \u003cowner/repo\u003e \u003cdir\u003e                 # Directory path → returns file listing\nghx read \u003cowner/repo\u003e \"src/**/*.ts\" --map   # Glob patterns with structural map\nghx read \u003cowner/repo\u003e --map \u003cf1\u003e [f2]       # Parser-backed structural map (~92% token reduction)\nghx read \u003cowner/repo\u003e --map --kind func \u003cf\u003e # Map only functions/methods\nghx read \u003cowner/repo\u003e --map --kind type \u003cf\u003e # Map only types/structs/interfaces\nghx read \u003cowner/repo\u003e --map --level minimal \u003cf\u003e # Symbol names only (e.g. UserService.GetUser)\nghx read \u003cowner/repo\u003e --grep \"pat\" \u003cf\u003e      # Matching lines only (ERE regex, 2 lines context)\nghx read \u003cowner/repo\u003e --lines 42-80 \u003cf\u003e     # Specific line range\nghx search \"\u003cquery\u003e\"                        # Code search with matching lines\nghx repos \"\u003cquery\u003e\"                         # Repo search with README preview\nghx tree \u003cowner/repo\u003e [path]                # Full recursive tree\nghx tree \u003cowner/repo\u003e [path] --depth N      # Tree limited to N levels\n```\n\n## Codemode\n\nWrite JS programs that compose multiple operations in one round-trip. All `codemode.*` calls are synchronous — no `await`. Full TypeScript type stubs with return types are injected into the sandbox.\n\n```bash\n# What branch is this repo on?\nghx code 'var r = codemode.explore({repo: \"vercel/next.js\"}); return r.branch;'\n\n# Search + read composition\nghx code 'var hits = codemode.search({query: \"useState repo:vercel/next.js\", limit: 3});\nvar first = codemode.read({repo: \"vercel/next.js\", files: [hits.matches[0].path]});\nreturn {file: hits.matches[0].path, lines: first[0].content.split(\"\\n\").length};'\n\n# See what tools and types are available\nghx code --list\n```\n\nType stubs tell the LLM exactly what fields exist — no guessing:\n\n```typescript\ndeclare const codemode: {\n  explore: (input: ExploreInput) =\u003e { description: string; branch: string; files: { name: string; type: string }[]; readme: string };\n  search: (input: SearchInput) =\u003e { total: number; incomplete: boolean; matches: { repo: string; path: string; fragment: string }[] };\n  tree: (input: TreeInput) =\u003e string[];\n  // ...\n}\n```\n\n## MCP Server\n\n```bash\nghx serve                                   # stdio (for Claude, Cursor, etc.)\nghx serve --http :8080                       # HTTP transport\n```\n\n7 tools: `explore`, `read`, `search`, `repos`, `tree`, `code` (meta-tool), `search_tools`.\n\n## Agent Integration\n\n```bash\nghx skill                                   # CLI skill (for SKILL.md injection)\nghx skill --mcp                             # MCP skill\n```\n\nDesigned for eager context injection via spawn hooks — the agent always has the latest ghx knowledge without loading it mid-conversation.\n\n## How It Was Built\n\n23 agent sessions, 2,500+ conversation turns, 3 rewrites, 12 ADRs. The full story: **[Build the GitHub Exploration Tool, No Mistakes](https://gkoreli.com/how-ghx-was-born)**\n\n## How It Works\n\nWraps `gh` CLI with GraphQL batching. `repos` and `explore` batch search + metadata + README into 1 call. `read` uses GraphQL aliases to fetch up to 10 files in 1 call — and if a path is a directory, returns its file listing instead of \"not found\" (via `... on Tree` inline fragments in the same query, zero extra API calls). Glob patterns (`src/**/*.ts`) auto-expand via tree fetch + [doublestar](https://github.com/bmatcuk/doublestar) matching in 2 API calls. `--grep` uses ERE regex with BRE normalization (agents trained on `grep` write `\\|` for alternation — both styles work). `search` hits REST `/search/code` with `text_matches` for matching context and 200-char token protection.\n\n`--map` runs a dedicated parser engine on the fetched content — no extra API calls. Engine selection is automatic: **Go** uses `go/ast` (top-level declarations only, full multi-line signatures, generics preserved), **TypeScript, JavaScript, Python, Rust** use [gotreesitter](https://github.com/odvcencio/gotreesitter) (captures class/impl methods that regex cannot reach), everything else falls back to regex. Methods carry a parent reference (`UserService.GetUser`) visible at `--level minimal`. `--map-engine regex` forces the fallback for any file.\n\nCodemode runs JS in a [goja](https://github.com/nicholasgasior/goja) sandbox with esbuild TypeScript transpilation. Tools are injected as synchronous functions on a `codemode` global object. Max 20 tool calls per execution, 64KB code size limit.\n\n## Architecture\n\n```\nv2/\n├── internal/mapengine/ — parser-backed map engine (GoAST, TreeSitter, Regex, engine routing)\n├── pkg/ghx/            — core library (Explore, Read, Search, Repos, Tree, Glob)\n├── pkg/codemode/       — JS executor (goja sandbox, TS transpilation, type generation)\n└── cmd/                — CLI frontend (cobra) + MCP server (mcp-go)\n```\n\nSee [docs/adr/](docs/adr/) for architectural decisions.\n\n## v1 (bash)\n\nThe original bash implementation is in [`v1/`](v1/). Zero dependencies beyond `gh` and `jq` — useful if you just want a shell script you can drop anywhere without compiling Go.\n\n```bash\nnpm install -g @gkoreli/ghx    # npm\ncp v1/ghx /usr/local/bin/ghx   # manual\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgkoreli%2Fghx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgkoreli%2Fghx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgkoreli%2Fghx/lists"}