Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.9.0 - 2026-07-11

- Added safe, bounded tool-call progress cards with active, completed, and failed lifecycle aggregation, approval-aware publication, allowlisted intent summaries, redaction, and robust missing-ID correlation. #80
- Stabilized scoped broker startup, route ownership, and reconnect registration, including migration of legacy lock files that could stall startup with `ENOTDIR`. #81 #83
- Improved session cleanup and selection across messengers by hiding superseded same-workspace sessions by default, adding `/sessions all`, and providing Telegram `Use` and `Forget` actions. #81

## 0.8.0 - 2026-06-14

- Added cross-messenger live progress updates so supported Slack, Discord, and Telegram destinations update an existing progress message where possible instead of posting repeated snapshots. #78
Expand Down
18 changes: 18 additions & 0 deletions openspec/specs/messenger-command-surfaces/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,21 @@ The system SHALL expose remote skill discovery and invocation through stable PiR
- **THEN** labels and descriptions are truncated or paginated according to platform limits
- **AND** they include only safe skill name, description, and source category metadata permitted by skill exposure policy

### Requirement: Session-list action surfaces prioritize actionable controls
Messenger command surfaces SHALL keep session-list buttons, menus, and equivalent action affordances aligned with the session state and the canonical command behavior they invoke.

#### Scenario: Offline session action is rendered
- **WHEN** a messenger renders buttons or menu actions for an offline session row
- **THEN** the primary action is a safe cleanup or inspection action such as `/forget` or `/status`
- **AND** the action does not advertise prompt delivery, recent live progress, or switching as if the offline session were reachable
Comment thread
Copilot marked this conversation as resolved.

#### Scenario: Recent command remains available outside default row buttons
- **WHEN** the default session-list action surface omits per-row `Recent` actions
- **THEN** the messenger still supports `/recent` or `/activity` through the canonical command parser when that command is available for the platform
- **AND** command-surface parity tests treat the command as supported even if it is not present as a default row button

#### Scenario: Platform cannot fit all actions
- **WHEN** a messenger platform has limited button or menu space for session-list actions
- **THEN** PiRelay prioritizes session selection for online non-current sessions and cleanup for offline/superseded sessions before optional recent-activity shortcuts
- **AND** omitted optional shortcuts remain documented through text commands or detailed status views

154 changes: 154 additions & 0 deletions openspec/specs/messenger-relay-sessions/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -955,3 +955,157 @@ The system SHALL deliver non-terminal live progress as an updated per-destinatio
- **THEN** live progress update/edit behavior respects each binding's existing progress-mode eligibility independently
- **AND** quiet receives no live progress while completion-only receives no ordinary live progress

### Requirement: Workspace-aware stale session presentation
The system SHALL reduce stale session-list clutter by identifying older offline bindings from the same machine and workspace as superseded when a newer online session for that workspace exists.

#### Scenario: Newer online session supersedes older offline same-workspace bindings
- **WHEN** an authorized user requests `/sessions` and there is a newer online session for the same machine and workspace as one or more older offline bindings
- **THEN** the default session list shows the newer online session
- **AND** the older offline same-workspace bindings are hidden or marked superseded by default
- **AND** ordinary prompt routing does not target the superseded offline bindings unless the user explicitly selects them in an all-sessions or cleanup view

#### Scenario: Offline session has no online same-workspace replacement
- **WHEN** an authorized user requests `/sessions` and an offline binding has no newer online sibling for the same machine and workspace
- **THEN** the system may show that offline binding as an offline session so the user can understand and clean up the pairing

#### Scenario: Superseded sessions remain inspectable
- **WHEN** an authorized user requests `/sessions all`, `relay sessions all`, or an equivalent explicit all-sessions or diagnostic session list
- **THEN** the system includes superseded offline bindings with clear stale/superseded wording
- **AND** it does not expose raw session file paths, hidden prompts, tool internals, bot tokens, or transcripts

#### Scenario: Superseded session can be forgotten
- **WHEN** an authorized user invokes `/forget <session>` for a superseded offline binding
- **THEN** the system revokes or removes that binding according to existing forget semantics
- **AND** the binding no longer appears in default or all-sessions lists for that messenger identity

#### Scenario: Workspace grouping is unavailable
- **WHEN** the system cannot safely determine a workspace identity for a binding or route
- **THEN** it falls back to existing session selection/listing behavior for that entry
- **AND** it does not guess supersession solely from an ambiguous display label

### Requirement: Session list actions are primary-task oriented
The system SHALL render session-list buttons and equivalent platform actions according to the useful next action for each session state.

#### Scenario: Current online session is listed
- **WHEN** the session list includes the currently selected online session
- **THEN** the default actions identify it as current or active
- **AND** they prioritize status or relevant live controls over switching to itself

#### Scenario: Non-current online session is listed
- **WHEN** the session list includes an online session that is not the current active selection
- **THEN** the default actions include a way to select that session
- **AND** they MAY include a platform-appropriate one-shot prompt affordance when safe and supported

#### Scenario: Offline session is listed
- **WHEN** the session list includes an offline or superseded session
- **THEN** the default action SHOULD be cleanup-oriented, such as forgetting that offline binding
- **AND** tapping the row action MUST NOT imply that an offline prompt or control succeeded

#### Scenario: Busy current session is listed
- **WHEN** the currently selected session is online and busy
- **THEN** detailed session controls MAY prioritize steer, follow-up, abort, or compact actions according to existing authorization and delivery rules
- **AND** they do not bypass pause, revocation, or route availability checks

### Requirement: Recent activity remains explicit command-level inspection
The system SHALL keep `/recent` and `/activity` as explicit commands for safe recent relay activity inspection while not requiring them as default per-session list buttons.

#### Scenario: User requests recent activity explicitly
- **WHEN** an authorized user invokes `/recent`, `/activity`, or an equivalent explicit recent-activity command for the current or resolved session
- **THEN** the system returns recent safe relay activity according to existing progress/activity redaction and bounded retention rules

#### Scenario: Session list is rendered
- **WHEN** the system renders a default session-list button grid or equivalent action list
- **THEN** it is not required to include a `Recent` action for every session row
- **AND** removing those buttons MUST NOT remove the `/recent` or `/activity` text command behavior

### Requirement: Tool progress is summarized safely
The system SHALL summarize tool-call progress using safe, bounded, human-readable operation labels instead of exposing raw tool arguments, tool output, transcripts, hidden prompts, pairing codes, raw messenger destination identifiers, or secrets.

#### Scenario: Bash progress shows command intent safely
- **WHEN** a running paired session emits a bash tool call and the receiving binding is eligible for normal progress
- **THEN** the progress update includes a bounded redacted summary of the command intent, such as the first command line
- **AND** the update does not include command output, hidden prompts, full transcripts, bot tokens, or unredacted secret-pattern matches

#### Scenario: File tools show target paths without content
- **WHEN** a running paired session emits read, edit, or write tool calls and the receiving binding is eligible for progress
- **THEN** the progress update identifies the relevant target file path or safe basename when available
- **AND** the update does not include file contents, replacement text, patches, or unbounded arguments

#### Scenario: Search/list tools show query or path intent safely
- **WHEN** a running paired session emits grep, rg, find, or ls style tool calls and the receiving binding is eligible for progress
- **THEN** the progress update includes a bounded redacted search pattern, query, or target path when available
- **AND** unknown or unsafe fields are omitted rather than serialized generically

#### Scenario: Unknown tools remain conservative
- **WHEN** a running paired session emits an unknown or custom tool call
- **THEN** normal-mode progress identifies only the sanitized tool name or a conservative generic label
- **AND** it does not serialize arbitrary tool arguments

### Requirement: Tool progress is aggregated by turn
The system SHALL aggregate current-turn tool progress by stable tool-call identity and tool kind so repeated tool events produce a compact live status rather than many generic completion messages.

#### Scenario: Repeated tool calls collapse into counts
- **WHEN** a running paired session completes multiple tool calls of the same kind within the progress window
- **THEN** the progress update includes a bounded aggregate count such as `bash×2` or `read×4`
- **AND** it does not send a separate messenger message for every individual completion when the adapter can coalesce or edit live progress

#### Scenario: Active and recent tools are shown compactly
- **WHEN** one or more tool calls are active or recently completed during a running paired turn
- **THEN** the progress update prioritizes the current active tool summaries and the most recent completed or failed summaries within the configured progress length limit
- **AND** older repeated activity is represented by aggregate counts rather than unbounded rows

#### Scenario: Failed tools are visible without leaking output
- **WHEN** a tool call fails during a running paired turn and the receiving binding is eligible for progress
- **THEN** the progress update marks that tool as failed using the safe tool label
- **AND** it does not include raw stack traces, command output, or unbounded error payloads in normal mode

#### Scenario: Approval-gated tools are published only after authorization
- **WHEN** a tool execution lifecycle starts before its blockable approval-gate check completes
- **THEN** PiRelay may stage safe local progress state but does not publish the tool as active before the gate allows execution
- **AND** denied, expired, undeliverable, or unauthorized approval requests do not leave active or failed tool-progress rows

#### Scenario: Tool progress resets on turn boundaries
- **WHEN** a Pi turn starts, completes, fails, aborts, unregisters, or the runtime restarts
- **THEN** current-turn tool progress state is reset or discarded
- **AND** later turns do not display stale tool rows or counts from previous turns

### Requirement: Progress modes govern tool reporting
The system SHALL apply existing progress-mode semantics to improved tool reporting for every messenger binding independently.

#### Scenario: Normal mode receives low-noise tool summaries
- **WHEN** a binding is configured for normal progress and a running paired session emits tool activity
- **THEN** the binding receives coalesced safe tool summaries and aggregate counts
- **AND** it does not receive generic duplicate `Processed tool result` or repeated `Tool completed — <tool>` messages for the same activity

#### Scenario: Verbose mode remains bounded and safe
- **WHEN** a binding is configured for verbose progress and a running paired session emits tool activity
- **THEN** the binding may receive additional safe technical tool lifecycle detail
- **AND** the output remains redacted, bounded, coalesced, and free of raw tool output or arbitrary argument serialization

#### Scenario: Completion-only excludes ordinary tool progress
- **WHEN** a binding is configured for completion-only progress and a running paired session emits ordinary tool activity
- **THEN** the binding does not receive the ordinary tool progress update
- **AND** terminal completion output and allowed compaction notifications continue to follow their existing policies

#### Scenario: Quiet suppresses all tool progress
- **WHEN** a binding is configured for quiet progress and a running paired session emits tool activity
- **THEN** the binding receives no tool progress update

### Requirement: Tool progress delivery preserves adapter parity
The system SHALL deliver improved tool progress through the same shared progress pipeline for Telegram direct runtime, Telegram broker runtime, Slack runtime, Discord runtime, and future messenger adapters.

#### Scenario: Telegram updates live tool progress in place when possible
- **WHEN** Telegram can edit the live progress message and the tool-progress card changes
- **THEN** PiRelay updates the existing live progress message instead of posting a new message for every tool call
- **AND** if editing fails, PiRelay falls back to bounded coalesced snapshots without exposing unsafe data

#### Scenario: Slack and Discord use coalesced snapshots
- **WHEN** Slack or Discord receives improved tool progress
- **THEN** PiRelay sends bounded coalesced snapshots using the same safe summaries and progress-mode filtering as Telegram
- **AND** authorization, paused/revoked binding checks, and destination scoping remain enforced before delivery

#### Scenario: Broker and in-process runtimes match
- **WHEN** equivalent tool progress is emitted through the in-process runtime and broker-owned Telegram runtime
- **THEN** both paths produce equivalent safe tool summary content and progress-mode behavior
- **AND** neither path persists raw tool args, tool outputs, or secret-bearing semantic keys

53 changes: 50 additions & 3 deletions openspec/specs/relay-broker-topology/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@
Defines the local and federated PiRelay broker topology for route registration, ingress ownership, peer communication, failover, and duplicate-bot safety across machines and sessions.
## Requirements
### Requirement: Machine-local broker supervisor
The system SHALL run at most one authoritative PiRelay broker per machine for a configured PiRelay state directory.
The system SHALL run at most one authoritative PiRelay broker per machine for a configured broker scope consisting of the PiRelay state directory, bot/account token hash, and optional broker namespace.

#### Scenario: First Pi session starts on a machine
- **WHEN** a Pi session starts with PiRelay enabled and no local broker is running for the configured state directory
- **WHEN** a Pi session starts with PiRelay enabled and no local broker is running for the configured broker scope
- **THEN** the system starts one local broker and registers the session route with that broker

#### Scenario: Additional Pi sessions start on the same machine
- **WHEN** another Pi session starts on the same machine with the same PiRelay state directory
- **WHEN** another Pi session starts on the same machine with the same broker scope
- **THEN** it connects to the existing local broker instead of starting another broker

#### Scenario: Concurrent Pi sessions start on the same machine
- **WHEN** two or more Pi sessions with the same broker scope attempt to start PiRelay while the local broker socket is not ready
- **THEN** broker startup is serialized with an inter-process supervisor lock
- **AND** only one broker process is spawned for that broker scope
- **AND** all sessions connect to that broker and register their routes there

#### Scenario: Stale broker socket exists
- **WHEN** the local broker socket or pid file exists but the broker is not alive
- **THEN** the system safely removes the stale local coordination file and starts a new broker without losing persisted bindings

#### Scenario: Live pid exists while socket is not ready
- **WHEN** a broker pid for the configured broker scope is live but the socket is not yet accepting connections
- **THEN** later Pi sessions wait for the socket to become ready instead of spawning a competing broker
- **AND** startup failure is reported as a secret-safe diagnostic if readiness times out

### Requirement: Broker hosts all enabled messenger instances
The system SHALL let the machine-local broker own lifecycle and ingress for every enabled local messenger instance that it is allowed to operate.

Expand Down Expand Up @@ -339,3 +350,39 @@ Broker topology SHALL keep shared-room delegation execution state local to the m
- **THEN** federation messages must preserve the same task identity, peer trust, authorization, expiry, approval, and loop-prevention rules as messenger-visible coordination
- **AND** they must not send bot tokens, hidden prompts, full transcripts, raw tool inputs, or file bytes unless a separate safe file-transfer capability explicitly allows it

### Requirement: Broker clients re-register routes after broker recovery
Broker clients SHALL re-register every live local session route after connecting or reconnecting to the authoritative broker for their broker scope.

#### Scenario: Broker socket is recreated
- **WHEN** a Pi session has an in-memory route and reconnects after the broker socket is recreated
- **THEN** the client re-registers that route with the broker before reporting the route as synchronized

#### Scenario: Multiple clients reconnect to the same recovered broker
- **WHEN** multiple Pi sessions reconnect after a broker restart or socket recovery
- **THEN** each client registers its own route with the same authoritative broker
- **AND** the broker session list contains all online routes from those clients

#### Scenario: A replacement client registers before the previous socket closes
- **WHEN** a live session route is re-registered on a replacement client socket
- **AND** the previous socket later unregisters or disconnects
- **THEN** the broker retains the replacement socket's route registration
- **AND** the session remains online in broker-backed session lists

#### Scenario: Re-registration contains stale binding metadata
- **WHEN** a reconnecting client re-registers a route whose binding metadata is stale relative to persisted binding authority
- **THEN** the broker applies binding authority before delivery or persisted binding updates
- **AND** stale metadata does not resurrect revoked or moved bindings

### Requirement: Broker scope diagnostics are secret-safe
Broker startup, recovery, and singleton diagnostics SHALL identify the broker scope without exposing tokens, pairing codes, hidden prompts, tool internals, or transcripts.

#### Scenario: Duplicate startup is prevented
- **WHEN** the supervisor prevents a concurrent broker startup for an existing scope
- **THEN** diagnostics may report the state directory category, non-secret namespace, and token hash prefix
- **AND** diagnostics MUST NOT print the bot/account token or full persisted state

#### Scenario: Stale coordination files are cleaned
- **WHEN** stale pid, socket, or lock files are removed
- **THEN** diagnostics describe the cleanup using secret-safe path categories and broker scope labels
- **AND** persisted bindings remain intact

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading