Skip to main content

Command-line client for Grim, the OSINT/recon platform.

Project description

grim-cli

A command-line client for Grim. It's a thin wrapper around Grim's HTTP API — every command maps to one API call, authenticated with a personal API key generated from the Grim account page.

Install

pipx install grim-cli   # or: pip install grim-cli
grim --help

To install from source instead (e.g. to work on the CLI itself):

poetry install
poetry run grim --help

Setup

Generate an API key from the Grim account page (Account → API keys → Create), then:

grim configure

This prompts for your API key, verifies it against Grim, and saves it to ~/.config/grim-cli/config.toml (owner-only permissions). You only need to do this once. The prompt is intentionally not a plain --api-key flag — that would leak the key into shell history and be visible to other local users via ps. Running grim configure again asks for confirmation before overwriting an already-saved key. grim logout removes the saved key from disk (the key itself stays valid server-side — revoke it from the account page if it was compromised).

Also worth running once: grim --install-completion — this is a stock Typer/Click feature (every grim --help shows it, not something specific to this CLI), and it's a bigger win here than on a smaller tool given how many nested subcommands there are (scan/template/schedule, each with 7-8 of their own). It detects your shell and adds a completion script to its config (e.g. ~/.zshrc); restart your shell afterward for it to take effect. grim --show-completion prints the same script to stdout instead of installing it, if you'd rather wire it into your dotfiles by hand.

Usage

grim account                        # tier, credits, 2FA/Tor status
grim modules                        # list available scan modules

grim scan create example.com                          # scan with all modules
grim scan create example.com -m headers -m dns        # only specific modules
grim scan create example.com --preset quick             # canned module list (see below)
grim scan create example.com --force                   # re-run cached modules too
grim scan create example.com --wait                    # stream progress until done

grim scan list                      # your scan history
grim scan get                       # status + per-module results of the scan you just created
grim scan stream                    # tail a running scan's progress
grim scan cancel                    # cancel a running scan
grim scan delete                    # delete a scan and its results
grim scan retry headers             # free re-run of one infra-failed module
grim scan diff                      # compare against the previous force re-scan
grim scan export                    # full Markdown report to stdout (or --output FILE)

grim template create quick -m headers -m dns -m tls  # save a reusable module list
grim template list                  # your saved templates
grim template get <template-id>     # a single template's modules
grim template update <template-id> --name renamed -m headers  # rename/replace modules
grim template delete <template-id>  # delete a template

grim schedule create example.com --interval daily             # all modules, daily
grim schedule create example.com --interval weekly -m headers -m tls
grim schedule create example.com --interval monthly --template-id <template-id>
grim schedule create example.com --interval daily --diff-only # email a diff, not the full report
grim schedule list                  # your scheduled scans
grim schedule get <schedule-id>     # a single schedule's settings
grim schedule update <schedule-id> --interval weekly
grim schedule update <schedule-id> --disable           # pause without deleting
grim schedule update <schedule-id> --diff-only         # switch report style
grim schedule delete <schedule-id>  # delete a scheduled scan
grim schedule run-now <schedule-id> # trigger immediately instead of waiting

grim logout                         # remove the locally saved API key
grim --version                      # print the CLI version and exit

The scan ID is usually optional

Every scan subcommand that acts on a specific scan (get, stream, cancel, delete, retry, diff, export) takes the scan ID as an optional trailing argument — omit it and the CLI uses whichever scan you most recently ran scan create against, saved locally in ~/.config/grim-cli/config.toml. This is what makes the common create-then-inspect flow short:

grim scan create example.com --wait
grim scan export --output report.md   # no id to paste — it's the scan you just created

Pass a scan ID explicitly at any time to target a different scan instead (e.g. grim scan get abc-123); it always wins over the saved one, and nothing here is fetched from the server or verified to still exist — it's just "the last id scan create returned," refreshed every time you create or resume a scan. scan list/scan get <explicit-id> never change it, so checking on an old scan doesn't knock the scan you're actively working on out of "last." If you've never run scan create (e.g. right after grim configure), omitting the ID fails with a clear error telling you to run scan create first or pass one.

Running specific modules

-m/--module is repeatable and takes exactly the module names grim modules lists (e.g. headers, dns, tls, whois, crawler, portscan, git_exposure — run grim modules for the full, current list rather than relying on it being documented here, since new modules get added over time):

grim modules                                          # see what's available
grim scan create example.com -m headers -m tls -m dns  # only these three

Omitting -m entirely runs every module. --preset quick (headers, dns, tls) and --preset passive (whois, dns, wayback, typosquat) apply the same canned module lists as the dashboard's Quick/Passive only buttons — --preset passive in particular never touches the target directly (every module in it is third-party-sourced or DNS-only). --module and --preset are mutually exclusive; for a reusable named list instead of a one-off preset, see grim template below. scan create --template-id doesn't exist — templates are only a module-list source when creating a schedule (--template-id); for a one-off scan, resolve the template's modules yourself with grim template get and pass them via repeated -m.

Exporting the Markdown report

grim scan export downloads the full per-module report for a completed scan — the same report generated by the dashboard's "Export as Markdown" button and linked from scheduled-scan report emails, byte-for-byte identical either way, since all three are the same server endpoint. It fails with a 409 if the scan is still running or hasn't been scanned yet (check grim scan get first). With no --output, the Markdown is written straight to stdout so it composes with shell redirection:

grim scan create example.com --wait
grim scan export --output report.md     # save to a file
grim scan export > report.md            # equivalent, via redirection
grim scan export | grep -A2 "## Findings"  # or pipe it straight into another tool

Unlike every other command here, scan export has no --json — it downloads Markdown, not JSON, so there's no JSON form to switch to.

Scheduled scans always email their report to your account's own confirmed address (add and confirm one from the Grim account page first — there's no way to point a schedule at a different inbox) and always force a fresh re-scan, charging a credit on every successful run just like scan create --force.

Every command accepts --json (except scan export, above) for raw JSON output instead of a formatted table/message — handy for piping into jq. On scan create --wait, scan stream, and scan retry --wait, --json switches the live progress feed to one JSON object per line (instead of colored text), so each event stays independently parseable, e.g. piped through jq -c. Every invocation also prints a startup banner to stderr, so none of this ever mixes into piped/redirected stdout — including the "Using last scan: ..." note printed whenever a scan ID is defaulted, which also goes to stderr for the same reason.

Commands that return a single JSON document (account, modules, every scan/template/schedule subcommand except scan stream and scan export) also accept --output/-o FILE to save that JSON to disk in addition to whatever's printed to the screen — independent of --json, so you can keep the human-readable table on screen and still get a saved artifact:

grim scan get --output result.json

template update and schedule update only change the fields you pass — omitted fields are left as-is server-side. Calling either with no fields at all is rejected locally before any request is sent.

If the connection drops during scan create --wait, scan stream, or scan retry --wait, the CLI automatically reconnects with backoff (up to 5 attempts) instead of dying with a traceback; already-printed module results aren't repeated. Any other network failure (unreachable host, timeout) is reported as a clean one-line error instead of a raw Python traceback.

Common workflow — start a scan, wait for it, then fetch the results as JSON:

grim configure
grim scan create example.com --wait
grim scan get --json | jq

Scope

This wraps the API-key-accessible subset of the Grim API: scan create/get/list/cancel/delete/stream/retry/diff/export, scan templates, scheduled scans, the module list, and the caller's own account info (tier/credits). Admin operations (user management, tier/role changes, the audit log) require a browser session and aren't reachable with an API key — use the Grim web dashboard for those.

Development

poetry install --with dev
poetry run pytest

Releasing

Publishing to PyPI is automated (.github/workflows/publish-cli.yml) and triggered by a cli-vX.Y.Z tag — the tag itself doesn't set the version, it's checked against cli/pyproject.toml's version and the workflow fails loudly if they don't match. To cut a release:

# bump the version field in cli/pyproject.toml, then:
git add cli/pyproject.toml
git commit -m "Release grim-cli vX.Y.Z"
git tag cli-vX.Y.Z
git push origin main cli-vX.Y.Z

The workflow runs cli/'s own test suite before building and publishing, so a red test suite blocks the release rather than shipping a broken package. Publishing uses PyPI's trusted publishing (OIDC), not a stored API token — see the workflow file's header comment for the one-time PyPI-side setup this needs before the first tag.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grim_cli-0.1.0.tar.gz (18.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grim_cli-0.1.0-py3-none-any.whl (17.4 kB view details)

Uploaded Python 3

File details

Details for the file grim_cli-0.1.0.tar.gz.

File metadata

  • Download URL: grim_cli-0.1.0.tar.gz
  • Upload date:
  • Size: 18.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for grim_cli-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c15e85843c4d656cb57e5d0a1164d8212218de639d39ab20662b3e92609fc76a
MD5 43418833a32d5fac69d26788036cd6e6
BLAKE2b-256 c229fac275c1208ec0aba9b0b5b45f99d2a9c62d8fdc62c042788202d52b25a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for grim_cli-0.1.0.tar.gz:

Publisher: publish-cli.yml on smowggyayy/grim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file grim_cli-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: grim_cli-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for grim_cli-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5bfc5d49bfa2d0dd8d23c8b518bb07f2d2390c7dab943f763d0d2928ba98bb4a
MD5 c2335f71efe1a55b9d01330057322724
BLAKE2b-256 203ba75fb194d1735318980ed1252240baa08b7d3856ce9ca255aaa1a6ea8581

See more details on using hashes here.

Provenance

The following attestation bundles were made for grim_cli-0.1.0-py3-none-any.whl:

Publisher: publish-cli.yml on smowggyayy/grim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page