Chuyển đến nội dung

Ứng dụng dòng lệnh

Gửi thông báo, điều khiển Hoạt động trực tiếp, cập nhật widget và chờ câu trả lời từ một tập lệnh shell, một cron job hay CI bằng ứng dụng dòng lệnh pushward.

ℹ Thông tin

pushward is a client for the same REST API, authenticated with your hlk_ integration key. It covers every operation in the public API, and anything newer is reachable through pushward api. Source and releases: mac-lucky/pushward-cli.

Install

brew install mac-lucky/tap/pushward

Homebrew also installs the shell completions (pushward completion bash|zsh|fish|powershell prints them otherwise). With Go:

go install github.com/mac-lucky/pushward-cli/cmd/pushward@latest

Or grab an archive from Releases. The macOS binaries in those archives are not signed, so a copy downloaded with a browser needs xattr -d com.apple.quarantine pushward first; Homebrew and go install are not affected. There is also a container image, ghcr.io/mac-lucky/pushward-cli:

docker run --rm -e PUSHWARD_API_TOKEN ghcr.io/mac-lucky/pushward-cli notify --title Hi --body There

Agent skill

Coding agents such as Claude Code, Codex and Cursor can drive the CLI for you. The pushward skill teaches them which command fits "ping me when the tests pass", "ask me before you push" or "show the migration on my lock screen", to end every Live Activity they start, and to keep your key out of the chat:

npx skills add mac-lucky/pushward-cli --skill pushward

The agent uses the key the CLI already has, so run pushward auth login yourself first. A key limited to agent-* slugs (see Creating scoped keys) keeps it away from your other activities. If your agent talks to the MCP server instead, use that page's skill.

Key

Copy an integration key from the app, then either export it or store it once:

export PUSHWARD_API_TOKEN=hlk_...

pushward auth login     # prompts, checks the key, writes ~/.config/pushward/config.json (0600)
pushward auth status

The environment variable wins over the stored key. There is no --token flag on purpose, so the key stays out of shell history and ps. pushward auth login --with-token reads the key from stdin, for piping it out of a password manager.

A key only does what its permissions allow: starting a Live Activity needs activities at manage, and notifications, widgets and email each need their own level. See Creating scoped keys.

Notifications

pushward notify --title "Backup done" --body "412 GB in 38m"
make 2>&1 | tail -20 | pushward notify --title "Build log" --body -
pushward notify --title "Disk" --body "/data at 91%" --level time-sensitive --url https://grafana.example.com

--body - reads the body from stdin. Add buttons with --action id=Title (repeatable), and --wait blocks until one is tapped:

answer=$(pushward notify --title "Deploy to prod?" --body v2.4.0 \
  --action deploy=Deploy --action skip=Skip --wait 15m --jq .action_id)
[ "$answer" = deploy ] && ./deploy.sh

Nobody answering in time exits 7. pushward notification answer <id> --wait 5m picks up the same answer later. How answers are recorded is covered in Answers.

Sắp có trong phiên bản ứng dụng 1.17.0

Phần này mô tả một tính năng trong bản cập nhật ứng dụng đang chờ App Store xét duyệt. Tính năng sẽ tự động mở khóa tại đây ngay khi bản cập nhật được phát hành.

Live Activities

pushward activity start deploy --name "Deploy api" --template steps --step 1/3 --step-labels Build,Test,Ship --text Building
pushward activity update deploy --step 2/3 --text Testing
pushward activity end deploy --status success

activity start creates the activity if needed and sets it ongoing with its first content; starting a slug that already exists restarts it.

activity end --status success|failure|cancelled shows a final frame first (green check, red cross or grey stop, with the progress filled on success), holds it for --display-time (4s by default) and then ends the card, so the Lock Screen shows the outcome instead of a card that just vanishes. --text, --icon and --color override the preset.

All ten templates work. For the ones without a dedicated flag, set content fields directly:

pushward activity update ci -F content.progress=0.4 -f content.state="Compiling"
pushward activity update board --data @board.json

Approval

An approval card waits for a decision the same way a notification does. activity wait gives up after --timeout (10 minutes by default) and exits 7:

pushward activity start release --template approval --text "Ship 2.4?" --option ship=Ship --option hold=Hold
pushward activity wait release --timeout 30m --jq .content.answer.option
ℹ Thông tin

activity start makes two calls, a create and then the first update, and both count against your Live Activity quota (see Limits). The API has no single call that creates an activity with a name and shows it.

Widgets, schedules, email

pushward widget create cpu --template gauge --min 0 --max 100 --unit % --value 12
pushward widget update cpu --value 57

pushward schedule create --in 2h --title "Stand up" --body Stretch
pushward schedule create --cron "0 9 * * 1-5" --tz Europe/Warsaw --title Standup --body "In 5 minutes"
pushward schedule list
pushward schedule cancel 1234 --purge

pushward email send --to [email protected] --subject "Nightly report" --text-file report.txt

See Widgets, Scheduled notifications and Email for what each field does. Email only goes to recipients you have verified in the app.

With a key from an organization, notify, schedule create, activity create, activity start and activity update take --target-groups, --target-tags and --target-members (CLI 1.3.0 and later), and activity update --no-target clears the target.

Request bodies

Every write command builds its body from four layers, later ones winning:

  1. --data (-d): a JSON literal, @file, or - for stdin.
  2. The command's own flags.
  3. -f key=value: always a string.
  4. -F key=value: typed, so numbers, true/false/null, JSON literals and @file.

Keys are dotted paths; key[] appends to an array and key[2] sets an index.

pushward notify --title T --body B -F push=false -f metadata.host=web-1
pushward activity update rack -F content.template=board \
  -F 'content.tiles[]={"label":"CPU","value":"12","unit":"%"}' -F 'content.tiles[]={"label":"Fans","value":"on"}'

For endpoints or fields the other commands do not cover, pushward api calls any path with the same key and the same -f/-F/--data handling:

pushward api /activities?state=ongoing
pushward api -X PATCH /activities/build -F content.progress=0.5

Output

On a terminal you get a short summary or a table. Piped, or with --json, you get the API response as JSON; --jq filters it and -q prints nothing.

pushward activity list --state ongoing --jq '.items[].slug'
pushward me --jq .live_activity_updates_used

Exit codes

Exit codes are stable, so scripts can branch on them:

CodeMeaning
0OK
1Any other error, such as a 422 validation failure
2Bad usage
3Missing, invalid or unauthorized key
4Not found
5Rate limited or out of quota
6Server error or network failure
7--wait (or activity wait) ran out

Rate limits (429) and 503s are retried for up to a minute, honoring Retry-After. Other server errors and network failures are only retried for reads and deletes: retrying a POST could send a notification twice.

GitHub Actions

The same binary runs the mac-lucky/pushward-action GitHub Action, which turns these commands into workflow steps with the run's context filled in. See GitHub Actions.