@khaale/gitlab-cli
v0.3.0
Published
LLM-agent native GitLab explorer CLI
Readme
glc
glc is a GitLab explorer CLI built for agents and shell users.
It is designed around a few constraints that matter in practice:
- explicit resource-first commands
- no interactive login, prompts, or pagers
- brief default list output instead of full GitLab payloads
- built-in
jqfiltering and projection - data-only stdout so it works well with pipes
- local JSON-file caching to avoid repeated expensive API reads
The intended use case is exploration and inspection of GitLab groups, projects, repositories, merge requests, pipelines, and jobs, especially from low-grade LLMs and shell scripts.
Status
This repository currently contains a first working scaffold:
doctorapi requestgroups list|get|treeprojects list|get|treerepos tree|refs|filemrs list|get|commits|pipelines|versions|changes|snapshotpipelines list|getjobs list|get|tracecache status|clear|warmconfig init|get|path
The CLI is GitLab-only and read-oriented in this version.
Why glc
GitLab CLIs tend to be optimized for human operators who already know the product model and are comfortable with mixed modes, aliases, and interactive flows.
glc takes a different approach:
- commands follow one stable grammar:
glc <resource> <verb> ... - selectors are explicit:
--group,--project,--pipeline,--job - list commands return a restricted stable schema by default
- full payloads are opt-in with
--full - output can be refined with
--fieldsor--jq
That makes the next command easier to generate for both people and weaker models.
Installation
Node.js 22+ is required.
For development in this repo:
npm install
node ./bin/glc.jsIntended package usage:
npm install -g @khaale/gitlab-cli
glc --helpor:
npx @khaale/gitlab-cli --helpRecommended first-run smoke test:
command -v glc
glc --json doctorAuthentication
glc reads GitLab connection settings from either:
- environment variables
- a persisted global JSON config file
Per-key precedence is:
GITLAB_HOST,GITLAB_TOKEN,GITLAB_CACHE_DIRfrom the environment- the same keys in the global
config.json - built-in OS-specific cache-dir default for
GITLAB_CACHE_DIR
The global config lives at:
- Linux:
${XDG_CONFIG_HOME:-~/.config}/glc/config.json - macOS:
~/Library/Application Support/glc/config.json - Windows:
%APPDATA%\glc\config.json
Recommended setup:
export GITLAB_HOST=https://gitlab.example.com
export GITLAB_TOKEN=glpat-xxxxxxxx
glc config initThat persists the current values into config.json.
You can also write config explicitly:
glc config init \
--gitlab-host https://gitlab.example.com \
--gitlab-token glpat-xxxxxxxxJSON keys use the same names as the environment variables:
{
"GITLAB_HOST": "https://gitlab.example.com",
"GITLAB_TOKEN": "glpat-xxxxxxxx"
}Environment variables remain the override path for temporary or session-specific credentials.
export GITLAB_HOST=https://gitlab.example.com
export GITLAB_TOKEN=glpat-xxxxxxxxPowerShell:
$env:GITLAB_HOST="https://gitlab.example.com"
$env:GITLAB_TOKEN="glpat-xxxxxxxx"There is no interactive login or prompt-based config flow in v1.
Basic Usage
Command shape:
glc <resource> <verb> [flags]
glc doctor [flags]Resources:
doctorapi requestgroupsprojectsrepospipelinesmrsjobscacheconfig
Common selectors:
--group <full-path>--project <path-with-namespace>--pipeline <id>--mr <iid>--job <id>--version <id|latest>--ref <name>--path <repo-path>
Common output flags:
--fields a,b,c--full--json--jsonl--raw--compact--jq '<expression>'
Common control flags:
--limit <n>--page <n>--refresh--verbose
Read-only raw API flags:
api request --path <absolute-api-path>--method <GET|HEAD>--query key=value&key2=value2
Config init flags:
--gitlab-host <url>--gitlab-token <token>--gitlab-cache-dir <path>--force
Examples
Configure access
Show the resolved config file path:
glc config pathRun the recommended preflight check:
glc --json doctorPersist the current env-backed configuration:
glc config initInspect the effective config with a redacted token:
glc config getUse the raw escape hatch for a read-only endpoint:
glc --json api request --path /api/v4/projects --query per_page=1Discover groups and projects
List top-level groups:
glc groups listList subgroups under a group:
glc groups list --group platformShow a namespace tree:
glc groups tree --group platformList projects inside a group:
glc projects list --group platformInspect one project:
glc projects get --project platform/apiShow a project resource tree:
glc projects tree --project platform/apiExplore repositories
Browse repository files:
glc repos tree --project platform/api --ref mainBrowse a subdirectory:
glc repos tree --project platform/api --ref main --path src/List repository refs:
glc repos refs --project platform/apiFetch a file:
glc repos file --project platform/api --ref main --path package.jsonExplore pipelines and jobs
List recent pipelines:
glc pipelines list --project platform/api --limit 10Inspect one pipeline:
glc pipelines get --project platform/api --pipeline 8123List jobs in a pipeline:
glc jobs list --project platform/api --pipeline 8123Inspect one job:
glc jobs get --project platform/api --job 99123Read a job trace:
Explore merge requests
List recent opened MRs in a project:
glc mrs list --project platform/api --state opened --limit 10Inspect one MR overview:
glc mrs get --project platform/api --mr 123List MR commits:
glc mrs commits --project platform/api --mr 123List MR pipelines:
glc mrs pipelines --project platform/api --mr 123Pin review to a diff version and inspect changed files:
glc mrs versions --project platform/api --mr 123
glc mrs changes --project platform/api --mr 123 --version latestWrite a review snapshot to disk:
glc mrs snapshot --project platform/api --mr 123 --include overview,commits,pipelines,changes,patch --output-dir /tmp/glc-mr-123glc jobs trace --project platform/api --job 99123Output Model
The output rules are intentionally simple:
listcommands default to JSON Linesgetcommands default to pretty JSONtreecommands default to a text treetracecommands return raw text
Formatting flags control the rendered form:
--json: force JSON object/array output--jsonl: force JSON Lines output--raw: emit raw scalar values without JSON quotes--compact: remove pretty indentation from JSON output--fields a,b,c: project a smaller field set before rendering--full: bypass the default summary schema and emit full GitLab objects
Current --compact behavior is narrow by design:
- it affects JSON output
--rawis the right choice when--jqreturns strings for shell loops- it does not change tree output
- it does not change raw trace/file output
- JSON Lines are already compact one-object-per-line output
List output is intentionally restricted by default. It should provide enough information for the next step, not a full API dump.
List commands return all matching rows by default. Use --limit <n> when you want only the first n results.
Examples:
glc projects list --group platformExample row:
{"id":102,"path":"api","path_with_namespace":"platform/api","web_url":"https://gitlab.example.com/platform/api","ssh_url_to_repo":"[email protected]:platform/api.git","http_url_to_repo":"https://gitlab.example.com/platform/api.git","last_activity_at":"2026-03-19T08:10:00Z"}Select a smaller schema:
glc projects list --group platform --fields id,path_with_namespaceRequest full GitLab objects:
glc projects list --group platform --fullForce pretty JSON instead of JSON Lines for a list:
glc projects list --group platform --jsonForce JSON Lines explicitly:
glc projects list --group platform --jsonlReturn compact JSON for a single object:
glc projects get --project platform/api --compactCombine --json and --fields on a tree command:
glc groups tree --group platform --jsonBuilt-in jq
glc can run jq expressions internally through --jq. This lets you filter or reshape output without an extra process in the common case.
Examples:
Project projection:
glc projects list --group platform --jq '{project: .path_with_namespace, last_activity: .last_activity_at}'Only failed pipelines:
glc pipelines list --project platform/api --jq 'select(.status == "failed")'Compact chaining-friendly output:
glc jobs list --project platform/api --pipeline 8123 --jq '{id, name, status}' --compactExtract project nodes from a group tree:
glc groups tree --group platform --json --jq '.. | objects | select(.kind? == "project") | .data.path_with_namespace'Extract raw project paths for a shell loop:
glc projects list --group platform --jq '.path_with_namespace' --rawjq must be available in PATH.
grep and pipes
glc is designed so stdout contains data only. That makes it work cleanly with shell tools.
Examples:
glc pipelines list --project platform/api | grep failed
glc jobs trace --project platform/api --job 99123 | grep -n ERROR
glc projects list --group platform --fields path_with_namespace | grep authCaching
Read commands use cache automatically unless --refresh is passed.
Cache logging is silent by default. Use --verbose if you want to see cache-hit diagnostics on stderr.
Cache examples:
glc cache status
glc cache warm --group platform
glc cache clear --project platform/api
glc projects list --group platform --verboseRefresh a command explicitly:
glc pipelines list --project platform/api --refreshCache location:
- Linux:
~/.cache/glc/or$XDG_CACHE_HOME/glc/ - macOS:
~/Library/Caches/glc/ - Windows:
%LocalAppData%/glc/cache/
Tests
Run the current test suite:
npm testCurrent coverage includes:
- argument parsing
- output mode and field projection
- tree rendering
- JSON-file cache behavior
- CLI help and missing-env error handling
Publishing builds a self-contained dist/ bundle during npm run pack:check and npm publish, so the released package does not depend on workspace-only packages.
Repository Layout
- bin/glc.js: executable entrypoint
- src/cli.js: command dispatch and top-level runtime
- src/commands: resource handlers
- src/lib: shared config, cache, output, jq, and GitLab client logic
- docs/design.md: user-facing design document
Limitations
Current gaps in this first implementation:
- no write operations
- no interactive auth/config flow
- no retry/backoff policy yet
- no dedicated integration tests against a real GitLab instance
--jqdepends on an installedjqexecutable
Next Steps
Useful next improvements:
- package publishing under a real npm scope
- integration tests with recorded or mocked GitLab API responses
- richer pagination and sorting behavior
- clearer field-profile support for list and tree output
- command-specific help and examples
