A Go CLI tool that acts as a package manager and orchestrator for the *2snipe integration suite — a collection of tools that sync vendor software licenses and assets into Snipe-IT.
snipemgr lets you discover, install, configure, schedule, and monitor all *2snipe integrations from a single place. It handles secrets via GCP Secret Manager, scheduling via Cloud Run Jobs and Cloud Scheduler, and discovery via a manifest-based GitHub registry.
Note:
snipemgrdoes not sync anything to Snipe-IT itself. It manages the tools that do. The individual*2snipeintegrations are standalone Go binaries — they know nothing about this manager and require no changes to work with it.
1. Download the binary:
# macOS (Apple Silicon)
curl -L https://github.com/jackvaughanjr/2snipe-manager/releases/latest/download/snipemgr-darwin-arm64 -o snipemgr && chmod +x snipemgr
# macOS (Intel)
curl -L https://github.com/jackvaughanjr/2snipe-manager/releases/latest/download/snipemgr-darwin-amd64 -o snipemgr && chmod +x snipemgr
# Linux (amd64)
curl -L https://github.com/jackvaughanjr/2snipe-manager/releases/latest/download/snipemgr-linux-amd64 -o snipemgr && chmod +x snipemgr
# Linux (arm64)
curl -L https://github.com/jackvaughanjr/2snipe-manager/releases/latest/download/snipemgr-linux-arm64 -o snipemgr && chmod +x snipemgrInstall to your $PATH:
sudo install -m 755 snipemgr /usr/local/bin/snipemgr2. Run the setup wizard:
snipemgr initThis creates snipemgr.yaml interactively — it walks you through your GitHub token, Snipe-IT credentials, and optional GCP config. Run it once; re-running prompts for confirmation before overwriting.
3. See what's available:
snipemgr list4. Install an integration:
snipemgr installWithout a name argument, install fetches the live registry and shows a scrollable picker. Select an integration, fill in the prompts, and you're done. The integration binary is downloaded to ~/.snipemgr/bin/ and its config is written to ~/.snipemgr/config/{name}/settings.yaml.
5. Run it manually or set a schedule:
To run immediately (GCP backend required):
snipemgr run github2snipeTo check status across all installed integrations:
snipemgr statusWant automated scheduling? Install with
--secrets-backend gcpto store secrets in Secret Manager and create a Cloud Run Job + Cloud Scheduler trigger. See GCP setup first.
To use pre-built binaries — nothing. Download and run.
To use the GCP backend (--secrets-backend gcp):
- A GCP project with billing enabled
- The
gcloudCLI installed and authenticated - See GCP setup below
To build container images for Cloud Run Jobs — choose one:
- Docker installed and running locally, or
- Cloud Build API enabled (
gcloud services enable cloudbuild.googleapis.com) — no local Docker required
To build from source — Go 1.25+
GitHub token (optional) — without one, GitHub rate-limits API calls to 60/hr. Sufficient for occasional use but tight if you run snipemgr list frequently. Set registry.github_token in snipemgr.yaml with a token scoped to public_repo (or repo for private integration repos).
snipemgr init First-time setup wizard — creates snipemgr.yaml interactively
snipemgr list Discover available integrations from the registry
snipemgr install [name] Download, configure, and install an integration
snipemgr config <name> Re-run the configuration wizard for an installed integration
snipemgr uninstall <name> Remove an integration (binary, config, GCP resources, state)
snipemgr categories list List all Snipe-IT license categories
snipemgr categories seed Seed default license categories (idempotent, --dry-run)
snipemgr status Show installed integrations with version, schedule, and last-run result
snipemgr run <name> Trigger a Cloud Run Job immediately
snipemgr enable <name> Resume a paused Cloud Scheduler job
snipemgr disable <name> Pause scheduling without removing the integration
snipemgr upgrade Check for and apply newer versions of installed integrations
snipemgr completion [shell] Generate shell completion scripts
Global flags on all commands: --config, -v/--verbose, -d/--debug, --log-file, --log-format, --no-interactive
--force Overwrite existing snipemgr.yaml without prompting for confirmation
init requires an interactive terminal. Re-running it on an existing config prompts for confirmation — it completely replaces snipemgr.yaml but does not affect installed integrations, integration config files, or state.
--snipe-url <url> Snipe-IT instance URL (sets snipe_it.url config field)
--snipe-token <key> Snipe-IT API key (sets snipe_it.api_key config field)
--field key=value Set any config field by key (repeatable)
--schedule <cron|manual> Sync schedule, e.g. "0 6 * * *" or "manual" (default: manual)
--secrets-backend <gcp|local> Secrets backend: "gcp" creates Cloud Run Job + Scheduler;
"local" writes settings.yaml only (default: local)
When called without a name argument in an interactive terminal, install fetches the registry and shows a scrollable picker so you can choose an integration without memorising its name. A "My integration is not listed..." option at the bottom explains how to add a new owner to registry.sources. Pass --no-interactive or pipe stdin to require an explicit name instead.
config accepts the same flags. Pass --no-interactive to skip wizard prompts and use flags only.
--all Upgrade all outdated integrations without prompting (non-interactive)
Pass --no-interactive without --all to list available upgrades without applying them.
Generate and install shell completions with the built-in completion command.
Bash
# Linux
snipemgr completion bash > /etc/bash_completion.d/snipemgr
# macOS
snipemgr completion bash > "$(brew --prefix)/etc/bash_completion.d/snipemgr"Zsh
mkdir -p "${fpath[1]}"
snipemgr completion zsh > "${fpath[1]}/_snipemgr"Fish
mkdir -p ~/.config/fish/completions
snipemgr completion fish > ~/.config/fish/completions/snipemgr.fishPowerShell
snipemgr completion powershell | Out-String | Invoke-ExpressionGCP Secret Manager, Cloud Run Jobs, and Cloud Scheduler are used when you install an integration with --secrets-backend gcp. Complete this one-time setup before your first GCP-backend install:
1. Enable required APIs (one-time per project):
gcloud services enable \
run.googleapis.com \
cloudscheduler.googleapis.com \
secretmanager.googleapis.com \
artifactregistry.googleapis.com \
--project YOUR_PROJECT_ID2. Create the Cloud Run runner service account:
gcloud iam service-accounts create snipemgr-runner \
--display-name="snipemgr Cloud Run Runner" \
--project YOUR_PROJECT_ID
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:snipemgr-runner@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"3. Authenticate your local machine:
gcloud auth application-default login4. Set in snipemgr.yaml:
gcp:
project: "YOUR_PROJECT_ID"
region: "us-central1"
service_account: "snipemgr-runner@YOUR_PROJECT_ID.iam.gserviceaccount.com"Cloud Run Jobs require a container image in Artifact Registry. This is a one-time step per integration. Run snipemgr run <name> after installing — it prints these instructions automatically if no image exists yet.
1. Create the Artifact Registry repository (one-time per project):
gcloud artifacts repositories create snipe-integrations \
--repository-format=docker \
--location=us-central1 \
--project=YOUR_PROJECT_ID \
--description="snipe-integrations container images"2. Clone the integration source (example: github2snipe):
git clone https://github.com/jackvaughanjr/github2snipe.git
cd github2snipeIf the repo doesn't have a Dockerfile, create a minimal one:
FROM golang:1.25-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o /app/github2snipe .
FROM alpine:3.21
COPY --from=builder /app/github2snipe /app/github2snipe
ENTRYPOINT ["/app/github2snipe"]3. Build and push — choose one method:
Option A — Docker (requires Docker installed and running):
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build -t us-central1-docker.pkg.dev/YOUR_PROJECT_ID/snipe-integrations/github2snipe:latest .
docker push us-central1-docker.pkg.dev/YOUR_PROJECT_ID/snipe-integrations/github2snipe:latestOption B — Cloud Build (no Docker required — builds and pushes via GCP):
# One-time project setup:
gcloud services enable cloudbuild.googleapis.com --project=YOUR_PROJECT_ID
PROJECT_NUMBER=$(gcloud projects describe YOUR_PROJECT_ID --format='value(projectNumber)')
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/cloudbuild.builds.builder"
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/logging.logWriter"
# Build and push:
gcloud builds submit \
--tag us-central1-docker.pkg.dev/YOUR_PROJECT_ID/snipe-integrations/github2snipe:latest \
--project=YOUR_PROJECT_ID .These three IAM grants are required once per project.
cloudbuild.builds.builderallows Cloud Build to read its source upload from Cloud Storage;artifactregistry.writerallows it to push the built image;logging.logWriterallows build logs to appear in Cloud Logging.
Replace YOUR_PROJECT_ID and github2snipe with your project and integration name. The image path pattern is:
{region}-docker.pkg.dev/{project}/snipe-integrations/{integration-name}:latest
After pushing, trigger the job:
snipemgr run github2snipesnipemgr list searches GitHub for repositories matching *2snipe under configured owners, then attempts to fetch a 2snipe.json manifest from each repo root. Repos without a valid manifest are silently excluded — the manifest file is the opt-in gate, not just metadata.
This means:
- Publishing a new integration to the registry is just committing a
2snipe.jsonto its repo - Third-party or experimental repos are excluded unless they deliberately opt in
- The manager has no hardcoded knowledge of any specific integration
The manifest also drives the install wizard — all config prompts come from the manifest's config_schema, so the manager never needs updating when a new integration is added.
Full manifest specification is in docs/manifest-spec.md. The JSON Schema for editor validation and programmatic checking is in 2snipe.schema.json.
In local mode, secrets are written to a settings.yaml file per integration under ~/.snipemgr/config/{name}/settings.yaml. This file is never committed.
In GCP mode, secrets are stored in GCP Secret Manager and injected as environment variables at Cloud Run Job execution time. The integration binaries pick them up via their existing viper env var bindings — no changes to the integrations are needed.
Shared secrets (Snipe-IT URL and token) are stored once and reused across all integrations. The install wizard detects existing shared secrets and offers to reuse them.
snipemgr tracks installed integrations in ~/.snipemgr/state.json. This file records the installed version, enabled status, cron schedule, and GCP resource names for each integration. It is never committed to the repo.
Before snipemgr install can work with an integration, that integration's repo needs a 2snipe.json manifest at its root. See docs/manifest-spec.md for the full spec and a complete example.
The short version:
{
"$schema": "https://raw.githubusercontent.com/jackvaughanjr/2snipe-manager/main/2snipe.schema.json",
"name": "yourvendor2snipe",
"display_name": "Your Vendor",
"description": "One-line description for snipemgr list",
"version": "1.0.0",
"config_schema": [
{ "key": "vendor.api_key", "label": "API Key", "secret": true, "required": true }
],
"shared_config": ["snipe_it"],
"releases": {
"github_releases": true,
"asset_pattern": "yourvendor2snipe-{os}-{arch}"
}
}Also add the GitHub topic 2snipe to the repo (Settings → Topics) — this is the primary discovery signal used by snipemgr list.
- Language: Go 1.25+
- CLI:
cobra+viper(same as all*2snipeintegrations) - Logging:
log/slog - Interactive forms:
charmbracelet/huh - Table rendering:
charmbracelet/lipgloss - GitHub API:
net/http(stdlib) — GitHub Search + Contents API directly - GCP:
cloud.google.com/go/run,cloud.google.com/go/scheduler,cloud.google.com/go/secretmanager
snipemgr.example.yaml Manager config template — copy to snipemgr.yaml and fill in values
2snipe.schema.json JSON Schema for validating integration manifests
docs/
README.md Index of all docs with audience and purpose at a glance
architecture.md [snipemgr] Component design, data types, wizard flow, dependency rationale
gcp-infra.md [snipemgr] GCP setup, IAM requirements, API references, cost estimate
features-backlog.md [snipemgr] Post-core enhancement ideas, tiered by value and complexity
historical/ [snipemgr] Frozen build log: order-of-operations.md + per-phase completion notes
INTEGRATION_CONTRACT.md [both] Stable contract between snipemgr and *2snipe integrations
manifest-spec.md [both] Full spec for the 2snipe.json integration manifest file
release.md [integrations] Versioning convention, release workflow template, badge/install patterns
scaffolding.md [integrations] File structure, go.mod, cmd/, and syncer templates for new integrations
source-files.md [integrations] Verbatim snipeit and slack client source to copy into new integrations
snipeit-api.md [integrations] Snipe-IT API reference: envelope behavior, checkout/checkin, sync flow, gotchas
Source code lives under cmd/ and internal/.
Working on snipemgr itself: read these in order:
CONTEXT.md— what this repo is, key decisions already made, and a reference table for the docs belowdocs/architecture.md— full component design- The relevant
docs/file for the area you're working in
Building a new *2snipe integration: read these in order:
docs/scaffolding.md— standard file structure, go.mod, cmd/, and syncer templatesdocs/source-files.md— verbatimsnipeitandslackclient source to copy indocs/snipeit-api.md— Snipe-IT API reference, sync flow, and gotchasdocs/release.md— versioning convention, release workflow, and README patternsdocs/manifest-spec.md— the2snipe.jsonmanifest your integration needs to be discoverable bysnipemgr
| Version | Key changes |
|---|---|
| v1.3.0 | snipemgr init writes snipemgr.yaml to ~/.snipemgr/ by default; snipemgr where diagnostic command; install/config wizard reordered (backend first, schedule/timezone GCP-only); Snipe-IT credentials pre-filled from snipemgr.yaml in wizard; gcp.credentials_file surfaced in init. |
| v1.2.0 | Shell completion: snipemgr completion [bash|zsh|fish|powershell] generates shell completion scripts; run, disable, enable, and uninstall now surface installed integration names as tab completions. |
| v1.1.0 | First public release. install name argument made optional — omitting it in an interactive terminal shows a scrollable picker populated from the live registry; includes a "not listed" option with instructions for adding a new owner to registry.sources. Also ships: upgrade command (binary-only updates, new-settings detection); ↑ update indicator in list and status; VERSION column in status; cross-platform release workflow (macOS arm64/amd64, Linux amd64/arm64, Windows amd64) with SHA256 checksums; race-safe atomic state writes; timezone-aware Cloud Scheduler (gcp.scheduler_timezone + wizard prompt) |
| v0.3.0 | GCP integration: --secrets-backend gcp writes credentials to Secret Manager; install creates Cloud Run Jobs and Cloud Scheduler triggers; status fetches live last-run data from executions API; run, enable, disable manage jobs. env_var field added to manifest ConfigField for explicit env var mapping. |
| v0.2.0 | snipemgr install end to end: GitHub Releases download, config wizard (huh forms + --no-interactive mode), Snipe-IT category management (categories list, categories seed --dry-run), settings.yaml generation, atomic state writes. Also: uninstall, config (re-run wizard), ● installed / ○ available status in list. |
| v0.1.0 | snipemgr list end to end: GitHub registry discovery (topic 2snipe + Contents API), manifest validation, lipgloss table in terminal, plain text when piped, state file creation. Manifests shipped for all five initial integrations. |
| v0.0.1 | Bootstrap — runnable snipemgr binary with cobra+viper CLI skeleton, all global flags, PersistentPreRunE logging init, snipemgr.yaml config loading, fatal() helper, and version embedding. |
jackvaughanjr/1password2snipe— 1Password Business member syncjackvaughanjr/github2snipe— GitHub Enterprise / org member syncjackvaughanjr/googleworkspace2snipe— Google Workspace license syncjackvaughanjr/okta2snipe— Okta member syncjackvaughanjr/slack2snipe— Slack billable member sync