omp packages

@qcts33/pi-notify0.5.0

Send notifications through Bark or Nextcloud when pi completes agent turns

qcts33 Published 7 days ago MIT ~314 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-notify ๐Ÿ“ฑ

Send notifications through Bark or Nextcloud when pi completes agent turns. Get notified on your phone โ€” or in your Nextcloud clients โ€” when long-running tasks finish, errors occur, or after each individual turn, without watching the terminal.

Notifications are off until you run /notify on in the session you want to hear from. Every other session โ€” including the pi child process of a subagent โ€” stays silent. See Activation.

Package: @qcts33/pi-notify Repository: forgejo.horse-carat.ts.net/qcts33/pi-extensions (tailnet-only), package packages/pi-notify

How it works

pi (your computer)
  โ”‚
  โ”‚ agent completes a turn โ†’ extension fires
  โ”‚
  โ–ผ
pi-notify extension
  โ”‚
  โ”œโ”€โ”€ Bark channel โ”€โ”€โ”€โ”€โ”€โ”€โ–บ POST https://api.day.app/push
  โ”‚                        { title, body, sound, group }
  โ”‚                        Bark server โ†’ Apple Push Notification service โ†’ iPhone
  โ”‚
  โ””โ”€โ”€ Nextcloud channel โ”€โ–บ POST /ocs/v2.php/apps/notifications/api/v3/
                              admin_notifications/{recipient}
                           { subject, message }
                           Nextcloud โ†’ your phone, desktop and web clients

Every configured channel sends; a channel with no credentials is skipped. Configure both and one event produces one notification on each (see Two channels at once).

Prerequisites

  1. A computer running pi (macOS, Linux, or Windows)
  2. Pi 1.x (floor 1.0.0, tested on 1.2.0) โ€” the extension uses native fetch and ExtensionAPI. Below the floor a session shows one warning at session start; the rest of the extension still runs.
  3. One channel:
    • Bark โ€” the Bark iOS app, free on the App Store, plus the device key it shows.
    • Nextcloud โ€” Nextcloud 30 or newer with the Notifications app enabled, an account that is an administrator, and an app password. The recipient's Nextcloud mobile clients must be signed in and registered for push; otherwise the notification still appears in the web UI's notification list, but no phone wakes.

Installation

via npm

pi install npm:@qcts33/pi-notify

from a local checkout

pi install /path/to/pi-extensions/packages/pi-notify

Quick test (no install)

pi -e /path/to/pi-extensions/packages/pi-notify

The upstream package @aslamplr/pi-ios-notify still exists on npm. Installing it gets upstream's 0.1.1, without the changes listed under Fork provenance.

Setup

Bark channel

  1. Install Bark on your iPhone and open it. It shows a device key URL like https://api.day.app/YOUR_DEVICE_KEY_HERE.
  2. In pi, run /notify bark setup and paste the YOUR_DEVICE_KEY_HERE part.
  3. Run /notify test bark โ€” a "๐Ÿ”” Test" notification should arrive within a second or two.

Nextcloud channel

  1. In Nextcloud, open Settings โ†’ Security โ†’ Devices & sessions and create an app password. Name it for this extension; revoke it there when you stop using it.
  2. In pi, run /notify nextcloud setup and answer four prompts:
    • URL โ€” the Nextcloud base URL, including any subdirectory, e.g. https://cloud.example.com or https://host/nextcloud.
    • User โ€” the account that signs the request. The v3 endpoint requires an administrator.
    • App password โ€” the password from step 1. It is visible while you type it; the prompt says so.
    • Recipient โ€” the user ID that receives the notification. Leave it empty to notify the authenticated account.
  3. Run /notify test nextcloud. The output names the failure when one occurs: a 401 means the user or app password is wrong, a 403 means the account is not an administrator, a 404 means the instance is older than Nextcloud 30 or the Notifications app is disabled.

An empty answer at any prompt keeps the value already configured. /notify nextcloud remove clears the whole channel.

Activation

Notifications are off by default and every session starts off. Only a session you activate sends:

/notify on

The state lives in the running pi process and is never written to disk, so each of these starts you inactive again: /reload, --resume, /new, a fork, a session switch, a restart. Run /notify on again after any of them. While the session is active the footer shows ๐Ÿ“ฑ, and /notify off clears it.

/notify on needs at least one configured channel; it covers both channels at once. /notify test ignores the gate: it sends whenever you ask it to.

The events toggles below choose which events an active session may send. They never make an inactive session send.

Commands

Command Description
/notify on Activate notifications for the current session
/notify off Deactivate notifications for the current session
/notify test [bark|nextcloud] Send a test through every configured channel, or through the one named
/notify status Show the channels, events and settings
/notify events <type> <true|false> Enable/disable notification types (agent-end, agent-settled, prompt-tools, turn-end, error)
/notify prompt-tools list List configured prompt tool names and labels
/notify prompt-tools add <name> [label] Add a tool name to watch with optional label
/notify prompt-tools remove <name> Remove a tool from the watch list
/notify prompt-tools clear Remove all prompt tools
/notify bark setup Enter or replace the Bark device key
/notify bark remove Clear the Bark device key
/notify bark sound <name> Set the Bark notification sound
/notify bark icon <url|pi|default> Set a custom Bark notification icon
/notify bark url <value> Set the URL Bark opens when the notification is tapped
/notify nextcloud setup Enter or replace the Nextcloud URL, user, app password and recipient
/notify nextcloud remove Clear the Nextcloud channel
/notify debug <on|off> Enable/disable debug logging
/notify hostname <true|false> Append the hostname to notification bodies
/notify body-content <prompt|output> Set whether the Complete notification shows the agent's last output or your prompt

Notification events

An active session sends the events switched on here. These toggles do not make an inactive session send; see Activation.

Event Default Description
agent-end โœ… on Notify when agent finishes a response
agent-settled โŒ off Notify only when the agent is truly idle (no auto retry/compaction/continuation). More accurate than agent-end; recommended with agent-end disabled
prompt-tools โœ… on Notify mid-turn when a configured tool calls for user input
turn-end โŒ off Notify after each individual LLM turn (can be noisy!)
error โœ… on Notify when a tool execution fails

Note: Enabling both agent-end and agent-settled sends duplicate completion notifications โ€” one per agent_end run plus one when the agent fully settles. For a single, accurate completion signal, use agent-end=false + agent-settled=true.

Toggle with:

/notify events agent-end false
/notify events agent-settled true
/notify events prompt-tools false
/notify events turn-end true
/notify events error false

Notification body content

The "โœ… Complete" notification body can show either the agent's last output or your original prompt:

  • output (default) โ€” the agent's final natural-language reply, truncated to 120 characters. The notification itself tells you what the agent concluded.
  • prompt โ€” the prompt you typed, with the turn count (legacy behavior).

If the agent's final turn produced no text (e.g. it ended on pure tool calls or thinking blocks), output mode falls back to showing your prompt so the notification body is never empty. Thinking content is never captured.

Toggle with:

/notify body-content output
/notify body-content prompt

Check the current value with /notify status.

Prompt tools

Prompt tools are tools registered by extensions that may ask for user input mid-turn, such as an approval gate or a question tool. The extension watches none of them until you list it: a tool name in this list is the only reason its mid-turn call sends a notification. When the LLM calls a listed tool, every configured channel is notified immediately.

/notify prompt-tools list
/notify prompt-tools add my_approval_tool "Approval"
/notify prompt-tools remove my_approval_tool

The label is shown as the notification title suffix; omitting it uses the tool name. The list is stored as promptTools in the config file, and removing a tool there (or with remove / clear) is permanent โ€” it is not re-added on the next start.

Cross-extension notifications

Any extension can send a notification by emitting an event on pi's shared event bus:

pi.events.emit("pi-notify:notify", {
  title: "๐Ÿ”’ Approval needed",
  body: "bash: rm -rf node_modules",
  source: "my-extension", // optional
});

pi-notify listens for pi-notify:notify and forwards the title and body to every configured channel. The emitter controls the notification content entirely. Requires an active session (see Activation) and the prompt-tools event toggle to be enabled.

The event was called pi-ios-notify:notify before 0.5.0; the old name is no longer heard.

Bark-specific settings

/notify bark sound birdsong
/notify bark icon https://example.com/my-icon.png
/notify bark url ssh://user@myserver
  • Sound โ€” any sound the Bark app offers. Common values: default, minuet, alarm, anticipate, birdsong, bloom, calypso, chime, descant, electronic, fanfare, horn, ladder, mazurka, nightingale, piano, rocket, sirius, strums, suspense, telegraph, tiptoes, tritone, tuberose, twinkle.
  • Icon โ€” default resets to Bark's icon, pi uses the pi logo, anything else is a URL.
  • URL โ€” any URL scheme; opens when the notification is tapped. Clear it with /notify bark url "".

Nextcloud's endpoint accepts none of these: the v3 request carries a subject and a message only, and the client decides the rest.

Two channels at once

Configured channels are independent. With both Bark and Nextcloud set up, every notification goes to both, so a completion wakes the phone twice. To stop that, remove one channel (/notify bark remove or /notify nextcloud remove); there is no per-channel event toggle.

Configuration file

The extension stores its config at ~/.pi/notify.json. You can edit it directly:

{
  "title": "pi",
  "bodyContent": "output",
  "showHostname": false,
  "debug": false,
  "events": {
    "agentEnd": true,
    "agentSettled": false,
    "promptTools": true,
    "turnEnd": false,
    "error": true
  },
  "promptTools": {},
  "bark": {
    "key": "YOUR_DEVICE_KEY",
    "server": "https://api.day.app",
    "sound": "default",
    "icon": "",
    "url": ""
  },
  "nextcloud": {
    "server": "https://cloud.example.com",
    "user": "admin",
    "appPassword": "YOUR_APP_PASSWORD",
    "recipient": "alice"
  }
}

An empty bark.key leaves the Bark channel off; an empty nextcloud.server, nextcloud.user or nextcloud.appPassword leaves Nextcloud off. An empty nextcloud.recipient sends to nextcloud.user. promptTools maps each watched tool name to its notification label; an empty object watches none, which is the default.

Upgrading from 0.4.0 reads the old ~/.pi/ios-notify.json once and writes its settings into the new file; the old file is left untouched and no longer read afterwards.

Custom Bark server

If you self-host Bark, set the server:

{
  "bark": {
    "server": "https://bark.yourdomain.com",
    "key": "YOUR_KEY"
  }
}

What notifications look like

Event Notification
Agent completes response โœ… pi Complete โ€” "refactor the auth module to use JWT" (3 turns)
Prompt tool called mid-turn ๐Ÿ’ฌ pi Approval โ€” my_approval_tool
Prompt tool called mid-turn ๐Ÿ’ฌ pi Wait โ€” my_question_tool
Cross-extension event emit ๐Ÿ’ฌ pi {emitter's title} โ€” {emitter's body}
Each turn ๐Ÿ”„ pi Turn โ€” Turn 3 finished
Tool error โš ๏ธ pi Error โ€” Error in bash: command not found: foobar

On Nextcloud these arrive as a notification from the admin_notifications app: the title line is the subject and the body is the message.

Privacy

  • The Bark device key and the Nextcloud app password are stored in plaintext in ~/.pi/notify.json. The Nextcloud password is an app password, so it can be revoked in Nextcloud without touching the account's main password; create one for this extension alone.
  • Notification content goes to the servers you configured: the Bark server and your Nextcloud instance. The body โ€” your prompt, or the agent's last text truncated to 120 characters โ€” is the only conversation content that leaves the machine.
  • A Nextcloud notification is stored by your Nextcloud server until it is dismissed, which is why it also appears in the web UI's notification list.
  • Bark stores notification content encrypted on its server; you can additionally set up end-to-end encryption in the Bark app.

Project structure

pi-notify/
โ”œโ”€โ”€ index.ts        # Extension entry point: events, activation, /notify command
โ”œโ”€โ”€ channels.ts     # The Bark and Nextcloud request builders and delivery
โ”œโ”€โ”€ config.ts       # Config file, defaults and the 0.4.0 migration
โ”œโ”€โ”€ utils.ts        # Pure text helpers
โ”œโ”€โ”€ test/           # Vitest suite for config, channels and the helpers
โ”œโ”€โ”€ defaults.json   # Default Bark icon
โ”œโ”€โ”€ package.json    # Package manifest with pi.extensions entry
โ””โ”€โ”€ README.md       # This file

Standard npm package layout โ€” the pi.extensions field in package.json tells pi where to find entry points.

Development

This package is a workspace member of the pi-extensions monorepo. Everything runs from the repo root through npm workspaces:

npm install          # once, at the repo root
npm test             # vitest for this package, node --test for the others
npm run verify       # lint + typecheck + tests + pack check

Load for testing:

pi -e /path/to/pi-extensions/packages/pi-notify

Reload changes:

/reload

Tests

npm test

Runs vitest on everything that does not need a live pi session:

  • test/config.test.ts โ€” defaults, the flat 0.4.0 shape, the nested shape, trimming and invalid values
  • test/channels.test.ts โ€” configured-channel selection, UTF-8 byte truncation, both request formats, per-channel failure lines and the timeout
  • test/utils.test.ts โ€” prompt truncation, pluralization, boolean parsing and custom-message text

index.ts binds the handlers and the command; no test imports it, so check it in a live pi session.

โš–๏ธ No Warranty

THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. The authors make no representations that this extension will deliver notifications reliably or in a timely manner. You are responsible for testing notification delivery and configuring appropriate settings.


License

MIT โ€” see LICENSE, which carries upstream's copyright notice as well as this fork's.

Fork provenance

This package is qcts33's fork of aslamplr/pi-ios-notify, taken from upstream 0.1.1 and published under the @qcts33 scope. From 0.5.0 it publishes as @qcts33/pi-notify with the command /notify; the old names were dropped rather than aliased (ADR-0007). On top of upstream's 0.1.1 it adds:

  • an agent-settled event, driven by pi's agent_settled event, as a more accurate completion signal than agent-end
  • a body-content setting that puts the agent's last output in the notification body instead of your prompt
  • bounded fetch timeouts per channel (5 seconds for Bark, 20 for Nextcloud) and fire-and-forget delivery, so a slow server cannot stall the agent loop
  • notifications only in a session the user activated with /notify on; every other session, including the child pi process of a subagent, starts silent
  • a Nextcloud channel that creates notifications through the Notifications v3 API, alongside Bark

Upstream is kept as a read-only remote: upstream fixes are cherry-picked into this fork, and this fork's changes are not upstreamed automatically.

Credits