Skip to content

Scaffolding CLI

The ggcommons scaffolding CLI is the fastest way to start a new Greengrass v2 component. It generates a ready-to-build project for any of the four languages, wires up the ggcommons dependency, and gives you commands to validate, build, publish, deploy, and upgrade the result.

The CLI is a single Python package (ggcommons-cli) that ships the templates for all four languages inside the wheel, so once installed it scaffolds offline — no network needed to generate a project.

The CLI installs from the cli/ directory of the monorepo. pipx is recommended (isolated global install); plain pip also works.

Terminal window
pipx install ./cli # recommended: isolated global `ggcommons`
# or:
python -m pip install ./cli # plain install
python -m pip install -e ./cli # editable (for developing the CLI itself)

Two identical console entry points are installed — ggcommons and ggcommons-cli — so use whichever you prefer. The examples below use ggcommons.

ggcommons --version # print the installed CLI version
ggcommons # no subcommand → prints top-level help
ggcommons <unknown> # → "Unknown command: <unknown>" (exit 2)

When a command fails it prints error: <message> (no Python traceback) and exits non-zero.

ggcommons doctor checks for the external tools needed to build and publish components and prints where each one was found. It takes no flags and reports status only — it does not exit non-zero when something is missing, so it is safe to run anytime.

Terminal window
ggcommons doctor

It checks eight tools, in this order:

Tool Needed to
git clone component templates
gdk build/publish components (Greengrass Development Kit)
cargo build Rust components
mvn build Java components
python3 (or python) run/build Python components
node run/build TypeScript components
npm install TypeScript dependencies
aws publish to AWS / deploy

Each line prints [ok] <name> -> <path> or [missing] <name> -- needed to …. You only need the tools for the language and workflow you actually target.

This is the core command. The minimal non-interactive form requires a fully-qualified component name (-n) and a language (-l):

Terminal window
# pick one language with -l (JAVA | PYTHON | RUST | TYPESCRIPT)
ggcommons create-component -n com.example.MyComponent -l JAVA
ggcommons create-component -n com.example.MyComponent -l PYTHON
ggcommons create-component -n com.example.MyComponent -l RUST
ggcommons create-component -n com.example.MyComponent -l TYPESCRIPT

The output directory is <path>/<ComponentName>, where ComponentName is the last dot-segment of --name (so com.example.MyComponent generates into ./MyComponent). On success the CLI prints Done. Component generated at: <dir>.

After generation it runs two guards: it fails fast if any <<TOKEN>> placeholder was left unsubstituted, and it lints the generated recipe.yaml, printing WARNING (recipe): … for any issues it finds.

Flag Short Default Notes
--name -n (required non-interactively) Fully-qualified component name, e.g. com.example.MyComponent.
--language -l (required non-interactively) One of JAVA, PYTHON, RUST, TYPESCRIPT.
--description -d This is a Greengrass v2 component Short component description.
--path -p . Parent directory for the generated project.
--jar -j the component name Jar file name (Java only).
--author -a Amazon Web Services Component author.
--bucket -b greengrass-component-artifacts-us-east-1 S3 artifact bucket (written into gdk-config.json).
--region -r us-east-1 AWS region (written into gdk-config.json).
--ggcommons-path -g libs/rust or libs/ts Absolute path to the local ggcommons library. Rust/TypeScript only (see below).
--template-url -u built-in template Override the template source: a git URL (cloned) or a local directory (copied).
--template-ref (none) repo default branch Git branch/tag to clone. Only applies to a git --template-url; ignored for local dirs.
--force -f off Overwrite the target directory if it already exists and is non-empty.
--interactive -i off Run the guided wizard (see below).
--platforms (none) GREENGRASS,HOST,KUBERNETES Comma-separated target platforms; gates which platform-specific artifacts are emitted.
--dep-source (none) local How the component depends on ggcommons: local (path/file dep) or registry (published artifact).

The wizard auto-enables when you pass -i/--interactive, or when you omit -n/--name while running on a terminal (a TTY). It collects the same inputs the flags do, then runs the identical generation flow. Press Enter to accept the [default] shown in each prompt.

The prompts, in order, are: language, fully-qualified name (required), description, target platform(s), dependency source, local ggcommons path (only asked for a Rust or TypeScript component with --dep-source local), and author.

Terminal window
$ ggcommons create-component -i
Interactive component scaffolding press Enter to accept the [default].
Language (JAVA/PYTHON/RUST/TYPESCRIPT): PYTHON
Fully-qualified component name (e.g. com.example.MyComponent): com.example.MyComponent
Description [This is a Greengrass v2 component]:
Target platform(s) comma-separated from GREENGRASS,HOST,KUBERNETES [GREENGRASS,HOST,KUBERNETES]: HOST
ggcommons dependency source (registry/local) [local]:
Author [Amazon Web Services]: Marc

--platforms controls which platform-specific artifacts the template emits. The three valid values are GREENGRASS, HOST, and KUBERNETES; the default selects all three. Selecting a subset prunes the artifacts only that platform needs.

The headline case: the Kubernetes Dockerfile and k8s/ manifests are emitted only when KUBERNETES is among the selected platforms.

Terminal window
# Greengrass + HOST only → no Dockerfile, no k8s/ manifests
ggcommons create-component -n com.example.MyComponent -l RUST --platforms GREENGRASS,HOST
# include KUBERNETES → also emits Dockerfile + k8s/ (configmap.yaml, deployment.yaml)
ggcommons create-component -n com.example.MyComponent -l RUST --platforms KUBERNETES

--dep-source decides how the generated component resolves the ggcommons library:

  • local (the default) — a path/file dependency on a monorepo checkout, ideal for developing against an unpublished library.
  • registry — the published artifact (GitHub Packages / git tag).

This flag (and --ggcommons-path) only affect Rust and TypeScript — the two languages whose generated dependency is a path/file reference. For Java and Python the dependency is always the named coordinate (com.mbreissi:ggcommons in pom.xml, greengrass-commons in requirements.txt), so --dep-source is a no-op there.

Here is the dependency declaration each language ends up with:

<!-- pom.xml — always this coordinate; --dep-source has no effect for Java -->
<dependency>
<groupId>com.mbreissi</groupId>
<artifactId>ggcommons</artifactId>
<version>0.1.0</version>
</dependency>

For a Rust or TypeScript component with --dep-source local, the CLI requires a valid --ggcommons-path (it defaults to libs/rust / libs/ts in this monorepo and is validated to exist before any files are written).

A generated project is a complete, buildable component: the language entry point, the ggcommons dependency wired in, a recipe.yaml and gdk-config.json for GDK packaging, and sample test-configs/. The exact layout is language-specific (for example pom.xml for Java, main.py for Python, Cargo.toml + build.sh for Rust, package.json + tsconfig.json for TypeScript).

The generated entry point constructs the ggcommons runtime and reads the config manager off it:

package com.example.mycomponent;
import com.mbreissi.ggcommons.GGCommons;
import com.mbreissi.ggcommons.config.ConfigManager;
public class MyComponent {
public static void main(String[] args) { new MyComponent(args); }
public MyComponent(String[] args) {
GGCommons ggCommons = new GGCommons("com.example.MyComponent", args);
ConfigManager configManager = ggCommons.getConfigManager();
// ... business logic ...
}
}

For building and running a generated component against a local MQTT broker, see the Quickstart.

list-templates — see available languages

Section titled “list-templates — see available languages”

Prints each language and the template source it will use — a local filesystem path (the bundled wheel copy, or the in-repo templates/<lang> directory). It takes no flags.

Terminal window
ggcommons list-templates

Checks a generated component’s recipe.yaml for problems that would break gdk component publish. Pass -p/--path to the project directory (or directly to a recipe.yaml); it defaults to the current directory. It prints OK: … when clean, or lists the issues and exits non-zero.

Terminal window
ggcommons validate -p ./MyComponent

Wraps the GDK (gdk component build, then optionally gdk component publish) and can create a cloud deployment with the AWS CLI.

Flag Short Default Notes
--path -p . Component project directory.
--publish (none) off Publish to the cloud after building.
--target -t (none) Deployment target ARN (thing or thing group). Implies --publish and creates a cloud deployment.
--region -r us-east-1 AWS region for the deployment.
Terminal window
ggcommons deploy -p ./MyComponent # build only
ggcommons deploy -p ./MyComponent --publish # build + publish
ggcommons deploy -p ./MyComponent -t <target-arn> # build + publish + create deployment

deploy requires gdk on PATH (and AWS credentials for publish/deploy). When deploying with --target, the project’s gdk-config.json must use a concrete version — a NEXT_PATCH version is rejected so the exact version to deploy is unambiguous. On-device development with greengrass-cli is out of scope for this command.

Updates the ggcommons dependency version in whichever manifest is present — pom.xml (Java), requirements.txt (Python), Cargo.toml (Rust), or package.json (TypeScript). The target version is required via -t/--to; the project path defaults to the current directory.

Terminal window
ggcommons upgrade -p ./MyComponent --to 1.2.3

A Rust path dependency is deliberately left untouched: upgrade reports it as “nothing to version-bump” rather than rewriting it.

For TypeScript, upgrade keys on the bare dependency name ggcommons and does not match the scoped @mbreissi/ggcommons key the TS template generates. As a result, for a generated TS component upgrade reports package.json: no ggcommons dependency found — for both a local (file:) and a registry (^0.1.0) dependency — and the file:/link: “nothing to version-bump” branch is never reached.

Each template directory ships a ggcommons-template.json manifest that fully describes how the CLI turns it into a project — adding a new language (or a forked template) needs only a template, not changes to the CLI. The manifest has these sections:

  • substitutions — maps each file to the list of <<TOKEN>> placeholders to replace in it (for example COMPONENTFULLNAME, COMPONENTNAME, GGCOMMONS_VERSION).
  • renames — file/directory renames, including templated targets such as src/main/java/{PACKAGEPATH}/{COMPONENTNAME}.java.
  • required — substitution keys that must be provided.
  • conditional — artifacts gated by an active condition flag.

The active condition flags are derived from your create-component inputs: one platform:<P> flag per selected --platforms value, plus one dep:<source> flag for --dep-source. A conditional entry’s paths are emitted only when its when flag is active. For example, the Java manifest gates the Kubernetes artifacts:

{
"conditional": [
{ "when": "platform:KUBERNETES", "paths": ["Dockerfile", "k8s"] }
]
}

and the TypeScript manifest additionally gates .npmrc on the registry dependency source:

{
"conditional": [
{ "when": "platform:KUBERNETES", "paths": ["Dockerfile", "k8s"] },
{ "when": "dep:registry", "paths": [".npmrc"] }
]
}

That is why --platforms KUBERNETES is what produces the Dockerfile and k8s/ manifests, and --dep-source registry is what produces the TypeScript .npmrc.