Website · Start · App Store · Google Play · Run agent
Encrypted CI/CD, cron, webhook and server alerts to iPhone and Android.
Sender secrets can only send. Relay sees ciphertext. Actions are optional.
echo "deploy failed" | nerve send- Create a pipe in the Nerve mobile app.
- Open Pipe Setup and choose Send signals.
- Copy the sender DSN.
- Install
nerve. - Send your first encrypted alert:
curl -fsSL https://nerve.ink/install.sh | sh
export NERVE_DSN="nerve://TOKEN:SENDER_KEY@api.nerve.ink"
echo "deploy failed" | nerve send --title "Nerve test"Expected output:
sent
The phone receives an encrypted signal. The relay routes ciphertext; decryption happens locally on the device that owns the pipe.
NerveOps is available on the App Store and Google Play.
nerve send is the safe first Nerve integration. It reads plaintext from stdin,
encrypts it locally with the sender key from NERVE_DSN, and posts only
ciphertext to the Nerve relay.
The sender DSN can send signals into one pipe. It cannot read history, decrypt old messages, connect as an agent, or execute commands.
| Boundary | What happens |
|---|---|
| CI secret leaks | A sender DSN can create alert noise in one pipe. It cannot read history, decrypt content, connect as an agent, or execute commands. |
| Relay receives traffic | The relay routes encrypted records and delivery metadata. Signal content is encrypted before it reaches the relay. |
| Phone receives push | APNs/FCM wake or notify the device. Clients sync the encrypted record and decrypt locally. |
| Agent is needed | Use nerve-agent only when you want signed actions on a machine you control. |
Recommended:
curl -fsSL https://nerve.ink/install.sh | shGo fallback / developer install:
go install github.com/nerve-ink/nerve-cli/cmd/nerve@latest
export PATH="$PATH:$(go env GOPATH)/bin"
nerve --helpUse the Docker image when you want nerve send in CI, cron, or a host where you
do not want to install Go or a local binary.
echo "deploy failed" | docker run -i --rm \
-e NERVE_DSN="nerve://TOKEN:SENDER_KEY@api.nerve.ink" \
p1xel32/nerve-cli:latest sendGitHub Container Registry mirror:
echo "deploy failed" | docker run -i --rm \
-e NERVE_DSN="nerve://TOKEN:SENDER_KEY@api.nerve.ink" \
ghcr.io/nerve-ink/nerve-cli:latest sendThe image is send-only. It does not run an agent and cannot execute commands.
For signed actions on a trusted host, use
nerve-agent.
echo "deploy failed" | nerve send \
--severity critical \
--title "Deploy failed"Common flags:
| Flag | Default | Purpose |
|---|---|---|
--dsn |
NERVE_DSN |
Sender DSN. Prefer an env var or CI secret. |
--severity |
standard |
Signal severity, for example standard, alert, critical. |
--title |
empty | Optional short title shown by clients. |
--kind |
alert |
Signal kind metadata. |
--timeout |
10s |
HTTP request timeout. |
Store the sender DSN as a repository or organization secret named NERVE_DSN.
name: Notify Nerve
on:
workflow_run:
workflows: ["Backend Deploy"]
types: [completed]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Install nerve
run: curl -fsSL https://nerve.ink/install.sh | sh
- name: Send encrypted deploy signal
env:
NERVE_DSN: ${{ secrets.NERVE_DSN }}
run: |
printf 'deploy %s\nrun: %s\n' \
"${{ github.event.workflow_run.conclusion }}" \
"${{ github.event.workflow_run.html_url }}" \
| nerve send --title "Backend Deploy"For a regular job, send only on failure:
- name: Install nerve
run: curl -fsSL https://nerve.ink/install.sh | sh
- name: Notify Nerve on failure
if: failure()
env:
NERVE_DSN: ${{ secrets.NERVE_DSN }}
run: |
printf 'FAILED: %s\nbranch: %s\nrun: %s\n' \
"${{ github.repository }}" \
"${{ github.ref_name }}" \
"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
| nerve send --severity critical --title "CI failed"Keep the signal short: repository, branch/environment, status, commit SHA, and run URL. Do not pipe full logs or secrets into phone alerts.
Example message:
deploy success
sha: b62b038
run: https://github.com/nerve-ink/nerve-ops/actions/runs/26969431142
#!/usr/bin/env bash
set -euo pipefail
export NERVE_DSN="nerve://TOKEN:SENDER_KEY@api.nerve.ink"
if ! /opt/jobs/backup.sh; then
echo "backup failed on $(hostname)" | nerve send --severity alert
exit 1
fiCrontab:
15 3 * * * /opt/jobs/backup-with-nerve.shif ./smoke.sh; then
echo "smoke passed: api-prod" | nerve send
else
echo "smoke failed: api-prod" | nerve send --severity critical
fiA sender DSN contains:
- a sender token
- a sender encryption key
- the relay host
If it leaks, an attacker can send fake signals into that one pipe until the credential is rotated.
They cannot:
- read history
- decrypt old messages
- connect as an agent
- execute commands
Do not put secrets, tokens, private keys, or full environment dumps into signal text. Send short operational context: service, environment, status, commit SHA, and a run URL.
- Open pipe setup in the mobile app.
- Create a new Send signals credential.
- Update your CI secret or server env var.
- Delete the old sender credential.
Use the recommended installer instead of the Go fallback:
curl -fsSL https://nerve.ink/install.sh | shThe Go path is only for local development or environments that intentionally build from source.
You are probably calling the old nerve shell function or a generic webhook
instead of the Go CLI. Check:
type nerve
which nerve
nerve --helpThe current CLI prints sent on success and sends
Content-Type: application/json automatically.
Use the public module path exactly:
go install github.com/nerve-ink/nerve-cli/cmd/nerve@latestIf Go reports that GitHub needs credentials, verify that your environment is not rewriting GitHub URLs to a private mirror or stale local fork.
Export the DSN copied from pipe setup:
export NERVE_DSN="nerve://TOKEN:SENDER_KEY@api.nerve.ink"Or pass it directly:
echo "deploy failed" | nerve send --dsn "nerve://TOKEN:SENDER_KEY@api.nerve.ink"Check that:
- the phone is signed into the same Nerve account
- notifications are allowed
- the sender DSN belongs to the pipe you are watching
- the app can decrypt the pipe keys
Need signed actions from a machine you control? Use
nerve-agent.
The agent is the advanced path. Start with send-only signals unless you explicitly need remote actions.