@gitmyabi/cli
v1.0.5
Published
gma - Standalone CLI for generating and publishing npm packages of typed ABI bindings
Readme
gitmyabi (gma)
The gma CLI generates a typed-ABI npm package (viem) from your contract
artifacts and can publish the result to any npm registry. It supports Foundry,
Hardhat, or a flat set of ABI JSON files.
You can use the codegen and publishing features without any gitmyabi
account — everything runs on your machine except the actual npm publish
request to the registry you choose. After you
gma login, the same binary unlocks
teams, projects, cloud builds, repos, and the interactive gma shell against
the gitmyabi API (same features as the web app, scriptable from the terminal).
Install
Main package (@gitmyabi/cli) — one install provides three binaries (same code):
npm i -g @gitmyabi/cli| Binary | Typical use |
| --- | --- |
| gma | Primary command (this doc uses gma … everywhere). |
| forge-gma | Foundry-flavored name; see Forge integration. |
| gmacli | Same CLI; also the name of the unscoped shim package. |
Per-project (no global install):
npm i -D @gitmyabi/cli
npx gma --helpInstall via gmacli (unscoped shim)
If you prefer an unscoped package name or shorter npx invocation:
npm i -g gmacli
# or, no global install:
npx gmacli --helpThe gmacli package pulls in @gitmyabi/cli and exposes only the gmacli binary (thin wrapper). See packages/gmacli/README.md in the repo for details.
Without logging in: local codegen only
No GitHub sign-in and no ~/.gma session are required for:
| Command | What it does |
| --- | --- |
| gma init | Create gma.config.json (detects Foundry / Hardhat / raw ABIs). |
| gma generate | Build a .tgz with TypeScript + viem types from your ABIs. |
| gma publish | Upload that tarball to npm (or another registry) using an npm token — not the gitmyabi API. |
| gma demo | Interactive walkthrough with mocked output (gma demo --yes for non-interactive). |
You only need a normal npm access token (e.g. from npmjs.com) in --token, in NPM_TOKEN, or saved via gma login --credentials-only (OAuth is skipped; only registry credentials are stored).
Not available until you log in: gma shell, gma team, gma project, gma build (cloud), gma repo, gma abi (API-backed), gma whoami, and related shortcuts. If you are not logged in, gma --help lists only the public commands; after login, the full list appears.
Generate and publish (typical flow)
Configure the package (once per repo):
gma init # edit gma.config.json: packageName, packageVersion, output, registry, etc.Compile contracts (Foundry / Hardhat) so ABIs exist on disk.
Generate the npm package tarball:
gma generate # writes e.g. ./gma-out/<name>-<version>.tgzPublish to your registry (uses your npm token, not gitmyabi auth):
gma publish --tar ./gma-out/<name>-<version>.tgz \ --registry https://registry.npmjs.org \ --token "$NPM_TOKEN"One-shot generate + publish:
gma generate --publish \ --registry https://registry.npmjs.org \ --token "$NPM_TOKEN"Dry run (see what would be published, no network upload):
gma generate --publish --registry https://registry.npmjs.org --dry-run gma publish --tar ./gma-out/<pkg>.tgz --registry https://registry.npmjs.org --dry-run
gma.config.json can hold defaults (registry, tokenEnv pointing at an env var name, access: public|restricted); flags and env vars still override. See Configuration for precedence.
For MCP generation, --mcp-self-contained (or mcpSelfContained: true in config) builds an MCP package that embeds ABIs and does not require a separately published bindings package.
Use --mcp-contracts (or mcpContracts) to limit MCP tools to your main deployed contract ABI(s).
When generateMcp: true and no mcpContracts is set, the CLI auto-detects
project-source contracts by reading compilationTarget metadata from each
Foundry artifact (Hardhat: artifact path structure). Only contracts whose
Solidity source lives inside the configured src directory are considered
"project" contracts; everything from lib/, node_modules/, test/, and
script/ is classified as a dependency and excluded.
- 1+ project contracts found → all are auto-selected for MCP (use
mcpContractsto narrow). - 0 / unclassifiable → MCP is skipped with a hint to set
mcpContracts.
After login: full gitmyabi platform
Run gma login (GitHub OAuth once per machine or profile) so the CLI can
call the gitmyabi API with your account. You then get:
gma shell— interactive REPL: teams, projects, cloud builds (trigger, watch logs, cancel), linked GitHub repos, ABIs, session dashboard.- Top-level groups (same as shell, scriptable in CI):
gma team,gma project,gma build,gma repo,gma abi,gma session. gma whoami/gma logout— inspect or clear the stored profile.
You still use gma generate / gma publish / gma init the same way when logged
in; login adds the platform on top, it does not replace local codegen. Many users
log in to manage teams and builds, and use generate / publish for npm
packages in the same workflow.
Details: Signing in and the API shell (OAuth, staging vs production) and the shell examples below.
Commands
Always available (no gitmyabi session):
gma init
gma generate [options]
gma publish [options]
gma demo [--yes] [--fast]
gma login
gma --login # alias for gma loginAfter gma login (session in ~/.gma/config.json):
gma logout
gma whoami
gma shell
gma team <sub>
gma project <sub>
gma build <sub>
gma repo <sub>
gma abi <sub>
gma session <sub>Subcommand groups mirror the shell (team list, build trigger, …). See the
sections below for examples.
Run gma <command> --help for the full flag list.
Quick start - Foundry
Given a Foundry project with foundry.toml and compiled artifacts in out/:
forge build
gma init # creates gma.config.json, framework: foundry
$EDITOR gma.config.json # set packageName, packageVersion
gma generate # produces ./gma-out/<pkg>-<version>.tgz
gma publish \
--tar ./gma-out/<pkg>-<version>.tgz \
--registry https://registry.npmjs.org \
--token $NPM_TOKENOr in one shot:
gma generate --publish --registry https://registry.npmjs.org --token $NPM_TOKENTest contracts (*.t.sol), scripts (*.s.sol), artifacts under test/ /
tests/ / script/ / scripts/ / mocks/, dependency paths such as
forge-std and ds-test, and node_modules segments are skipped when collecting Foundry/Hardhat ABIs.
Pass --include-tests-and-scripts to include the test/script/mocks side of
that list, and --include-standard-library-abis if you really need forge-std /
ds-test artifacts. You can also set includeTestsAndScripts /
includeStandardLibraryAbis in gma.config.json. Pass --include-empty-abis
to include interfaces/libraries with empty ABI arrays. gma generate also keeps only one artifact per *.json contract name (e.g. a single IERC20.json from several out/ paths), which matches how codegen names exports and avoids duplicate TypeScript identifiers. You get a console.warn if a skipped file’s ABI array differs from the one we kept (then adjust --abi-exclude or codegen if you truly need both).
Use --verbose (-v) to print collection flags, every resolved ABI path (relative and absolute), and the parsed ABI JSON from each file before codegen runs.
If you need tighter control over what gets packaged, use ABI path filters:
gma generate \
--abi-include "artifacts/hardhat/contracts/**/*.json" \
--abi-exclude "artifacts/hardhat/contracts/test/**/*.json,artifacts/hardhat/contracts/forge-std/**/*.json"Quick start - Hardhat (without the plugin)
npx hardhat compile
gma generate --framework hardhat \
--package-name @acme/contracts \
--package-version 0.1.0The plugin (@gitmyabi/hardhat) is the preferred integration if you already
use Hardhat - it reuses hre.artifacts and integrates with the task system.
Quick start - raw ABIs
gma generate --framework abis \
--abis ./abis/**/*.json \
--package-name @acme/contracts \
--package-version 0.1.0Configuration
gma uses cosmiconfig to look
for:
gma.config.json/gma.config.ts/gma.config.js/.gmarc.json- a
"gma"key inpackage.json
Example gma.config.json (every supported project key is shown below; remove or change entries you do not need—most projects only use a subset):
{
"$schema": "https://gitmyabi.com/schema/gma.config.json",
"packageName": "@acme/contracts",
"packageVersion": "0.1.0",
"projectName": "acme-contracts",
"framework": "foundry",
"abis": ["./abis/**/*.json"],
"abiInclude": [],
"abiExclude": [
"out/**/Test*.sol/**/*.json",
"out/**/Test*.json"
],
"output": "./gma-out",
"tar": "./gma-out/acme-contracts-0.1.0.tgz",
"target": "viem",
"generateMcp": true,
"mcpAllowWrites": false,
"mcpSelfContained": true,
"mcpContracts": ["FiatTokenProxy"],
"includeEmptyAbis": false,
"includeTestsAndScripts": false,
"includeStandardLibraryAbis": false,
"registry": "https://registry.npmjs.org",
"access": "public",
"tag": "latest",
"tokenEnv": "NPM_TOKEN"
}For framework: "foundry" or "hardhat", abis is ignored unless you switch to "abis". For framework: "abis", abis is required (or pass --abis). Empty abiInclude / abiExclude arrays are equivalent to omitting those keys.
All keys are optional unless a command needs them (e.g. gma generate with framework: abis requires abis or --abis). Unknown keys are rejected (strict schema).
| Field | Purpose |
| --- | --- |
| $schema | JSON Schema URL for editor validation only; ignored by the CLI. |
| packageName | Generated npm package name (--package-name). |
| packageVersion | Generated package version (--package-version). |
| projectName | Human-facing name embedded in codegen metadata (--project-name). |
| framework | auto, foundry, hardhat, or abis (--framework). |
| abis | Paths or glob strings used when framework is abis (same as --abis, comma-separated on the CLI). |
| abiInclude | After collection, only keep ABI files matching these globs (--abi-include). |
| abiExclude | After collection, drop ABI files matching these globs (--abi-exclude). |
| output | Directory for generated package (--out). |
| tar | Explicit .tgz path for gma publish when the default under output is not used (--tar). |
| target | Codegen target; currently only viem (--target). |
| generateMcp | Also emit the companion MCP server package (--generate-mcp). |
| mcpAllowWrites | MCP server includes writeContract tools (--mcp-allow-writes). Default is read-only. |
| mcpSelfContained | MCP package embeds ABIs; no runtime dependency on the bindings package (--mcp-self-contained). |
| mcpContracts | Contract names to expose as MCP tools; unset uses auto-detection for Foundry/Hardhat (--mcp-contracts). |
| includeEmptyAbis | Include artifacts with an empty ABI array (--include-empty-abis). |
| includeTestsAndScripts | Include test/script/mocks paths and .t.sol / .s.sol trees (--include-tests-and-scripts). |
| includeStandardLibraryAbis | Include forge-std / ds-test style dependency ABIs (--include-standard-library-abis). |
| registry | Default npm registry URL for generate --publish / publish (--registry). |
| access | public or restricted when publishing (--access). |
| tag | Dist-tag for publish (--tag). |
| tokenEnv | Name of env var holding the npm token (e.g. NPM_TOKEN); falls back to NPM_TOKEN and profile. |
Credential storage (~/.gma/config.json, 0600):
{
"profiles": {
"default": {
"apiUrl": "https://api.gitmyabi.com",
"accessToken": "<jwt from /auth/exchange>",
"refreshToken": "<refresh token>",
"tokenExpiresAt": 1729600000000,
"user": { "id": "...", "email": "...", "name": "...", "provider": "github" },
"registry": "https://registry.npmjs.org",
"npmToken": "npm_xxx..."
}
},
"activeProfile": "default",
"cli": {
"firstRunWelcomeDone": true,
"shellAliases": {
"bl": "build list"
}
}
}The cli object is optional. firstRunWelcomeDone suppresses the bare-gma demo prompt; shellAliases drives custom shortcuts in gma shell. Omit cli entirely if you do not need either.
Precedence for any option (lowest -> highest): project config < profile < env < CLI flag.
Signing in and the API shell
gma login runs a GitHub OAuth loopback flow that mirrors the web app's
/auth/exchange contract. It:
- starts a one-shot HTTP server on
http://127.0.0.1:47823/callback, - opens GitHub's authorize page in your browser,
- receives the
code, posts it to the backend's/auth/exchange, and - persists the returned
jwt,refreshToken,expiresIn, and user snapshot to your active profile.
The redirect URI sent to GitHub must be registered on the same OAuth App
that powers the web UI. Add http://127.0.0.1:47823/callback as an
additional authorized callback URL (or whichever port you pass via
--port). The shell stores only the loopback URI the CLI actually used,
and that exact value is sent back to /auth/exchange.
Production vs staging (default API + GitHub OAuth client id)
The CLI embeds public defaults (API host + GitHub OAuth client id). You can switch the whole stack with one environment variable or a login flag.
| | Production (default) | Staging |
| --- | --- | --- |
| API | https://api.gitmyabi.com | https://api.staging.gitmyabi.com |
| Pick tier | GMA_ENV=production (or unset) | GMA_ENV=staging |
Configure for production (default — nothing required):
gma login
# or explicitly:
gma login --env productionConfigure for staging (CLI + API + bundled OAuth id for that tier):
export GMA_ENV=staging
gma login
# or for a single command without changing your shell:
gma login --env stagingOverride only the API URL (still uses the same OAuth client id selection unless
you also set GMA_GITHUB_CLIENT_ID):
export GMA_API_URL=https://api.staging.gitmyabi.com
gma loginOverride only the GitHub OAuth client id (e.g. a separate GitHub App for staging):
export GMA_STAGING_GITHUB_CLIENT_ID=Iv1.staging_xxxxxxxx
export GMA_PRODUCTION_GITHUB_CLIENT_ID=Iv1.production_xxxxxx
# or a single var used for every tier:
export GMA_GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxxxxx
gma login --env stagingRecognized environment variables: GMA_ENV, GMA_TIER, or GMA_TARGET (production / prod / live vs staging / stage).
gma login # or: gma --login
gma whoami # shows session expiry
gma shell # starts the REPLFlags worth knowing:
gma login --env <production|staging>- default API + OAuth id for that deployment.gma login --client-id <id>- override allGMA_*_GITHUB_CLIENT_IDvars.gma login --port <n>- use a different loopback port.gma login --no-browser- print the authorize URL instead of opening it.gma login --credentials-only --registry <url> --npm-token <token>- save only the npm publishing credentials, skip the OAuth flow entirely.gma logout --keep- clear tokens but keep the npm/registry entries.
gma shell opens an interactive prompt backed by gitmyabi-backend-client.
Commands are organized into groups; tab-completion is group-aware (first
token completes groups, built-in shortcuts, custom alias names, second
completes subcommands, third+ completes IDs).
gma> help # list all groups + shortcuts
gma> help team # show subcommands for one group
gma> team list # (or: teams)
gma> team create acme --slug acme --description "..."
gma> team members --team acme
gma> team invite [email protected] --role admin --team acme
gma> team set-role <userId> admin --team acme
gma> project list # (or: projects)
gma> project show my-project
gma> project create my-proj --git-url https://github.com/acme/my.git \
--full-name acme/my --installation-id 12345 --framework hardhat \
--build-cmd "npx hardhat compile"
gma> project settings my-proj --auto-build --build-cmd "npm run build" \
--env KEY=value --env OTHER=x
gma> build list my-project # (or: builds my-project)
gma> build trigger my-project # also: trigger my-project, rebuild my-project
gma> build run my-project # trigger + stream logs in one go
gma> build watch <buildId> # also: watch <buildId>, follow <buildId>
gma> build cancel <buildId> # also: cancel <buildId>
gma> build logs <buildId> --lines 500
gma> build artifacts <buildId>
gma> build tiers # show backend build resource tiers
gma> repo list --sync
gma> repo branches acme/my-repo
gma> abi project my-proj
gma> status # redraw the dashboardTop-level aliases (status, whoami, teams, projects, builds,
repos, trigger, watch, run, cancel, logs, artifacts) keep
muscle memory working. Ctrl-C inside a stream closes the socket and
returns to the prompt; on the bare prompt it clears the line like
bash/zsh. Tokens are refreshed automatically at start-up using the stored
refresh token. MCP endpoints are intentionally excluded.
Shell history and custom aliases
History — Commands you type in
gma shellare appended to~/.gma/shell_history(one line per submission, up to a cap). They reappear on the up-arrow the next time you open the shell. The file is created with restrictive permissions alongsideconfig.json.Aliases — Define first-token shortcuts stored under
cli.shellAliasesin~/.gma/config.json, or manage them inside the shell:gma> alias add bl build list gma> bl --limit 10 # runs: build list --limit 10 gma> alias list # show custom shortcuts (see README) gma> alias remove blNames must be a single identifier (
a-z, digits,-,_). The wordshelp,?,exit,quit, andaliasare reserved and never expand as aliases. You can chain aliases (each step re-reads the map) with a depth limit to avoid accidents. Tab completion suggests alias names and, after a trailing space, completes the expanded command (e.g. afterblyou getbuild listcompletions).To edit by hand, merge into
config.json:"cli": { "shellAliases": { "bl": "build list", "pt": "project list" } }
Trigger and stream builds
Both the shell and the top-level CLI can kick off a build and follow its
logs live. The stream uses the same Socket.IO /events gateway the web app
uses (subscribe-to-project, subscribe-to-logs), so you see the exact
same log lines and codegen milestones (codegen started, codegen
completed, ABI ready).
From the shell:
gma> trigger my-project # queue a new build, prints the build id/number
gma> watch 6602abc... # stream logs + status updates (Ctrl-C to detach)
gma> run my-project # trigger + immediately watch (`run ... --no-logs` to detach)
gma> cancel 6602abc... # cancel a queued/running buildCtrl-C while a stream is active cleanly closes the socket and returns you
to the prompt — the build itself keeps running server-side. A second
Ctrl-C in the top-level CLI (gma build watch ...) kills the process.
From scripts / CI:
gma build trigger my-project --watch # kick off and follow
gma build watch 6602abc... # reattach to an in-progress build
gma build status 6602abc... # one-shot status probe
gma build cancel 6602abc... # cancel
gma build list my-project # recent builds for a project
gma build logs 6602abc... --lines 500
gma build artifacts 6602abc...
gma build tiers # available compute tiersgma build watch exits non-zero when the build ends in failed/error,
so it can be used as a gate in CI pipelines.
Managing teams and projects
Everything in the shell is also available as a top-level subcommand:
gma team list
gma team create acme --slug acme --description "Acme Inc."
gma team members --team acme
gma team invite [email protected] --role admin --team acme
gma project list --team acme
gma project create my-proj \
--git-url https://github.com/acme/my.git \
--full-name acme/my --installation-id 12345 \
--framework hardhat --build-cmd "npx hardhat compile"
gma project settings my-proj --auto-build --build-cmd "npm run build"
gma project rename my-proj new-name
gma project delete my-proj --yes
gma repo list --sync
gma abi project my-projAny subcommand accepts --json / --raw to emit the raw backend payload
instead of the pretty-printed form. Destructive commands (delete,
remove-member) require an explicit --yes / --force.
Note: a few team-scoped endpoints (
members,invite,invitations,set-role,remove-member) have a known codegen bug ingitmyabi-backend-clientthat leaves a literal:teamIdin the URL. The CLI works around this by calling those paths via a small raw-fetch helper (src/api/raw-request.ts) that reuses the client's auth/cookie/ApiError pipeline. Once the codegen is fixed upstream the helper can be removed.
Forge integration
Foundry does not have a formal plugin/extension system today
(foundry-rs/foundry#7760
was closed as "not planned"; #8354
tracking the forge run / [actions] work is T-post-V1). Forge does not
auto-dispatch unknown subcommands to external binaries the way git does,
so forge gma (with a space) cannot work without modifying forge itself.
Instead, gma follows the forge-<tool> convention already used by
community tools like forge-deploy
and forge-flamegraph: install
the tool, invoke it directly by its hyphenated name:
# from your Foundry project root
forge build
forge-gma generate
forge-gma generate --publish --registry https://registry.npmjs.org --token $NPM_TOKENforge-gma and gma are the same binary — pick whichever reads better in
your scripts. The CLI prints whichever name it was invoked as in help output.
Useful recipes:
- Makefile:
abis: ; forge build && forge-gma generate - justfile:
gma-build: forge build && forge-gma generate - CI step:
forge build && forge-gma generate --publish
Environment variables
Defaults & tiers — see Production vs staging under Signing in and the API shell.
GMA_ENV/GMA_TIER/GMA_TARGET—production(default) orstaging; picks default API host whenGMA_API_URLis unset.GMA_API_URL— gitmyabi API base URL; overrides the tier default (used after login and forgma login).
OAuth & npm (login / publish)
GMA_GITHUB_CLIENT_ID— GitHub OAuth App client id forgma login(optional; the CLI ships public defaults; see staging section for per-env overrides).GMA_STAGING_GITHUB_CLIENT_ID/GMA_PRODUCTION_GITHUB_CLIENT_ID— per-tier overrides.NPM_TOKEN— fallback forgma publish/gma generate --publishwhen--tokenand profilenpmTokenare not set.
Debugging & demos
GMA_DEBUG=1— print stack traces on errors.GMA_NO_DEMO=1— skip the first-run interactive tour on baregma.GMA_ALLOW_GENERATE_WITHOUT_CONFIG=1ortrue— allowgma generatewithoutgma.config.jsonwhen you do not pass--framework(normallygma initis required first so baregma generatedoes not auto-run on Foundry/Hardhat without a project config).
Notes on the bundled backend client
The CLI depends on gitmyabi-backend-client via
file:./vendor/gitmyabi-backend-client (a full copy of the generated client
shipped under vendor/ in the npm package). That avoids file:…tgz quirks
with npm install -g @gitmyabi/cli and avoids a separate registry package
for the client for now. To refresh it, unpack a new
gitmyabi-backend-client-*.tgz into vendor/gitmyabi-backend-client/ and
adjust its package.json version if needed.
