Skip to content

Introduction

GGCommons (Greengrass Commons) is one SDK that gives every AWS IoT Greengrass v2 component the cross-cutting plumbing it would otherwise rewrite by hand — configuration, messaging, metrics, heartbeat, and logging — plus opt-in credentials, parameters, and telemetry streaming. You wire it up once at startup and write only business logic.

The unusual part: GGCommons is implemented four times, in Java, Python, Rust, and TypeScript, as deliberate mirrors of one another. The same config schema, the same CLI contract, the same subsystem boundaries, and the same on-wire message envelope apply to all four. Java is the canonical reference; the other three track it.

Every component gets these subsystems out of the box — they are always present:

  • config — loads the component config from one of several sources (FILE, ENV, GG_CONFIG, SHADOW, CONFIG_COMPONENT, CONFIGMAP), validates it against the canonical JSON schema, substitutes template variables like {ComponentName} and {ThingName}, and supports hot reload.
  • messaging — one interface over two transports (Greengrass IPC and dual-MQTT). Connections and subscriptions block until confirmed; request/reply uses correlation IDs; the message envelope is identical across all four languages.
  • metrics — pluggable targets: CloudWatch EMF, a cloudwatch component, the messaging bus, a local rotated log file, or a pull-based Prometheus endpoint.
  • heartbeat — periodic system metrics (CPU, memory, disk, threads, file descriptors) emitted through the metric or messaging subsystem.
  • logging — console logging plus optional size-rotated file logging, with a per-language format token (java_format, python_format, rust_format, ts_format).

Three more subsystems are opt-in — their accessor returns nothing unless the matching config section is present:

  • credentials — an encrypted local vault (envelope encryption) with optional central sync from AWS Secrets Manager.
  • parameters — offline-first externalized config from env, a mounted directory, or AWS SSM, reusing the credentials vault as an encrypted cache.
  • streaming — high-rate telemetry streaming with a durable (or in-memory) store-and-forward buffer that drains to Kinesis or Kafka.

A component runs on a platform and talks over a transport. These are two orthogonal axes, chosen at startup with --platform and --transport:

Platform What it is Default transport Default config source
GREENGRASS On-device, Nucleus-managed IPC GG_CONFIG
HOST Docker or a bare host MQTT (dual: local broker + AWS IoT Core) FILE
KUBERNETES A pod in a cluster MQTT CONFIGMAP

The transport is one of IPC (Greengrass IPC, valid only on GREENGRASS) or MQTT (the dual-MQTT provider that connects to a local broker and, optionally, AWS IoT Core).

By default --platform is auto: the library detects the platform from the environment (Greengrass Nucleus signals first, then a Kubernetes service-account token, then a HOST fallback) and derives the transport, config source, and other defaults from the resolved platform profile. An explicit --platform or --transport always wins. See the Quickstart for runnable command lines.

Working with GGCommons is the same three steps in every language:

  1. Build the runtime once. A fluent builder (GGCommonsBuilder / GgCommonsBuilder) takes your component name and the process arguments and returns a single runtime object. That object parses the CLI, resolves the platform profile, loads and validates config, and wires up every subsystem.
  2. Reach subsystems through accessors. Hold the runtime for your component’s lifetime and ask it for what you need — messaging, metrics, config, and the opt-ins. Each accessor returns the already-wired service.
  3. Let the library own the lifecycle. GGCommons installs its own signal handling and tears subsystems down on shutdown — you do not register your own signal handler.

The shape is the same everywhere — only the naming conventions differ. Note especially how each language passes process arguments and how each one shuts down.

import com.mbreissi.ggcommons.GGCommons;
import com.mbreissi.ggcommons.GGCommonsBuilder;
public static void main(String[] args) {
// Build the runtime from the standard CLI args (use the FULL component name).
GGCommons gg = GGCommonsBuilder.create("com.mbreissi.greengrass.JavaComponentSkeleton")
.withArgs(args)
.build();
var config = gg.getConfigManager();
var messaging = gg.getMessaging();
var metrics = gg.getMetrics();
// ... business logic ...
// The library wired SIGTERM/SIGINT to a graceful, idempotent shutdown() — do not add your own.
}

The four SDKs stay aligned because they share their contracts, not their code:

  • One config schema. The JSON schema lives only at schema/ggcommons-config-schema.json and is synced into each library; CI fails on drift. Every library validates fail-closed against its embedded copy.
  • One CLI contract. The same flags, defaults, platform profiles, and auto-detection rules are implemented by a shared resolver design in each language.
  • One message envelope. The on-wire format is identical, so a component in any language can talk to a component in any other.
  • Java is canonical. When public behavior changes, it changes in Java first; the other three mirror it. Differences that remain are idiomatic (naming, Option vs null, RAII vs explicit shutdown), never behavioral.

This is why the snippets above look like the same program written four ways — that is exactly what they are.