zudo-slack-notify

Type to search...

to open search from anywhere

CLI Sender

Flags, environment, exit codes, dry runs, and keeping the key off the command line.

The sender is app/cli/notify.ts. It needs Node.js 24 or later, which runs the TypeScript file directly. Run it from app/ in the checkout, or use the script's absolute path. It sends nothing to Slack itself: it validates locally and calls the Worker.

Environment

VariableMeaning
ZUDO_SLACK_NOTIFY_URLFull endpoint, ending in /v1/notify
ZUDO_SLACK_NOTIFY_API_KEYThe relay key (32 to 256 printable ASCII characters), never the Slack token

The URL must be HTTPS, with no credentials, query, or fragment. Plain HTTP is accepted only for localhost, 127.0.0.1, and [::1], for local development.

Keep the key off argv

Put the two variables in the sender env file and load it with node --env-file. The key then never appears on the command line, in shell history, or in the process list:

node --env-file="$DROPBOX_ROOT/env/zudo-slack-notify/credentials/sender.env" \
  "$ZUDO_SLACK_NOTIFY_ROOT/app/cli/notify.ts" --file notification.json

The CLI has no --api-key flag on purpose.

Usage

node --env-file=.env cli/notify.ts \
  --target dev --message "Build finished." --kind success

Flags

FlagMeaning
--file PATH or -Complete JSON payload from a file or standard input. Cannot be mixed with the message flags below.
--target ALIASDestination alias
--message TEXTNotification body
--title TEXTOptional heading
--kind KINDinfo, success, warning, error, action_required
--source TEXTProject or agent label
--thread-ts TSParent receipt's ts; use with the same target
--dry-runValidate and print the request and Slack payload; no network
--helpPrint usage

Each flag may appear once, unknown flags are errors, and a flag value may not start with --. fields and links are available only through --file. Input files and stdin are limited to 16 KiB of UTF-8.

Dry run

--dry-run runs the same validation and rendering as the Worker, using the placeholder channel C0000000000, and prints dryRun, notification, and slackPayload as JSON. It needs no environment and makes no request. It exits 0 when the input is valid.

Exit codes

CodeMeaningdelivery
0Sent (verified receipt), or a successful dry run or --helpsent
1Rejected by the API and not sent (auth, validation, target, Slack rejection)not_sent
2Local input or configuration error, before any requestnot_sent
3Slack rate limited; wait for Retry-Afternot_sent
4Delivery unknown: check Slack before resendingunknown

The result JSON is printed on stdout, except code 2, whose error goes to stderr with error.code set to local_input_error.

Exit 4 also covers failures the CLI detects itself, with these error.code values: client_timeout (no answer within 20 seconds), client_network_error, and unrecognized_response (the reply could not be verified as an API response). When the API answers with an unrecognizable error code the CLI reports api_error.

Output

On failure the CLI prints ok, delivery, requestId, retryable, and error (with the message truncated and the relay key redacted). On exit 3 it adds retryAfter and retryAfterSeconds. It never prints an upstream HTML page or arbitrary response body.

No automatic retries

The CLI makes one request with redirects disabled. It never retries, on any exit code. A caller that wants to resend must do so deliberately after reading the exit code. See Delivery semantics.

Revision History

CreatedUpdated