ghp provides a command-line interface for server management and token
operations. Use --help on any command for full details.
ghp --help
Commands
| Command | Description |
|---|---|
ghp serve |
Run the server (proxy + web UI + API) |
ghp migrate |
Run database migrations |
ghp auth |
Authenticate with the ghp server |
ghp token |
Create, list, and revoke proxy tokens |
ghp apptoken |
Generate a GitHub App installation access token |
ghp version |
Print version information |
Global Flags
| Flag | Description |
|---|---|
--config |
Path to server configuration file (or set GHP_CONFIG) |
Client Configuration
The CLI reads client settings from a YAML config:
server_url: "https://ghp.example.com"
user_token: "your-session-token"
Config sources and precedence
Settings are merged from several sources. Later sources override earlier ones, field by field:
- System config — a fleet-wide file resolved per platform (mirroring
dotvault's convention):
- Linux:
/etc/xdg/ghp/config.yaml(honouringXDG_CONFIG_DIRS) - macOS:
/Library/Application Support/ghp/config.yaml - Windows:
%ProgramData%\ghp\config.yaml
- Linux:
- User config —
~/.config/ghp/config.yaml. Overloads the system config. - Environment variables —
GHP_SERVER_URL,GHP_USER_TOKEN. - dotvault — when a
dotvault:stanza is configured (see below), the fields it resolves take the highest precedence.
| Variable | Description |
|---|---|
GHP_SERVER_URL |
URL of the ghp management server |
GHP_USER_TOKEN |
Session token from ghp auth login |
This lets an operator deploy a single system config to a fleet (with
server_url and a dotvault: stanza) and have every user inherit it with
zero per-user configuration, while still allowing an individual user to
overload any field in ~/.config/ghp/config.yaml.
ghp auth login and ghp auth set-token always write to the user config
(~/.config/ghp/config.yaml), never the system file.
No user_token in the system config
A session token is per-user, and the system config is shared and expected
to be world-readable. The CLI therefore rejects a user_token set in
the system file (it would otherwise hand one user's token to every local
account) — fix it by removing the key. To supply a per-user token from a
fleet-wide config, use a dotvault: stanza instead (below). For this
reason the system file is not permission-checked; the user file still is.
Sourcing the token from Vault with dotvault
Rather than storing user_token on disk, the CLI can fetch it just-in-time
from HashiCorp Vault via the dotvault
client. Add a dotvault: stanza:
server_url: "https://ghp.example.com"
dotvault:
service: ghp # reads kv/users/<identity>/ghp (may contain slashes)
# config: /etc/xdg/dotvault/config.yaml # optional; defaults to dotvault's own config path
fields:
user_token: token # set the CLI's user_token from the dotvault field "token"
dotvault itself owns Vault connectivity (address, CA, TLS), authentication,
cached-token resolution (including the peer-socket token borrow when its
config sets vault.token_socket), the KV mount, and the per-user path
convention — all read from dotvault's own config file. The ghp stanza only
declares which secret under the user root to read and which fields it maps
onto.
serviceis the path segment under the per-user root (kv/users/<identity>/<service>); it may include slashes for a nested layout (e.g.vendor/tool-name).fieldsmaps ghp CLI config keys to the dotvault secret field that supplies them. Supported keys:user_tokenandserver_url.configoptionally points at a specific dotvault config file; when omitted, dotvault's platform default is used.
When configured, the CLI calls dotvault's Authenticate flow (cached token →
token file → token borrow → interactive login as a last resort, suitable for a
human-run CLI) and reads the mapped fields. Resolution fails loudly: an
authentication error or a missing field is surfaced rather than silently
falling back. Combined with the system config above, a fleet can be deployed
with no per-user token on disk at all.
Identity is the OS user
dotvault derives <identity> from the OS account the CLI runs as. Each
user reads their own kv/users/<their-username>/<service> secret.