Conversation
…presence receipts docs (#59) * feat(alerts): ax alerts CLI — Activity Stream alerts + reminders MVP (#53) * feat(credentials): audit active agent PAT hygiene * docs(context): expose preview cache command * fix(context): make fetched uploads render as artifacts * docs(skill): add ax tool cadence * feat(alerts): ax alerts CLI — Activity Stream alerts + task reminders MVP First-slice MVP for task dfef4c92 (Activity Stream alerts and reminders). Thin wrapper over POST /api/v1/messages using the existing metadata.alert path — zero backend schema changes, no scheduler dependency. Commands: - ax alerts send — fire an alert/reminder with severity, target, source_task, due_at, remind_at, evidence. Emits metadata.ui.cards[0].type="alert" so the frontend's AlertCardBody renders it (verified against AxMessageWidgets). - ax alerts reminder — shortcut for --kind reminder (source_task required). - ax alerts ack/resolve/state — post a state-change REPLY (backend PATCH only accepts content, not metadata, so state transitions become first-class stream events referencing the parent alert via parent_message_id). Reminder cards stay compact: no mcp_app widget, no task-board initial_data. The card's resource_uri points at the linked task so it's clickable. Dogfooded against next.paxai.app: - msg 233089a7 — alert send, card type=alert, target+source_task set. - msg 23c50444 — reminder send, kind=task_reminder, resource_uri set. Related: 65c76d9b (CLI alert metadata), 0dacbc1e (task reminders), ebd63283 (activity stream taxonomy). Scheduler (68656c16) deferred to slice 2. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(alerts): clarify recipient-acks-not-firer + link backend follow-up Help text for ack/resolve/state now documents: - the "recipient acks, not firer" boundary (backend refuses self-replies) - task 247f7bf0 as the follow-up that enables in-place state transitions Per aX feedback on ax-cli#53. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(alerts): task-aware targeting + snooze state, task=source-of-truth design Refinement per ChatGPT 2026-04-15 on dfef4c92 / 0dacbc1e: tasks are canonical reminder/workflow objects; alerts are Activity Stream events generated from (or linked to) tasks. Changes: - Add `snoozed` to allowed states + `ax alerts snooze <id>` command. Scheduler (68656c16) will re-fire at remind_at / next cadence. - When `--source-task` is set and `--target` is omitted, auto-resolve target from task.assignee_id → task.creator_id. Explicit --target still wins for escalation. Displays "target: orion (from task assignee)" so users see when auto-resolution fired. - Module docstring now states the "task = source of truth" design rule and points at 0dacbc1e / 68656c16 / 34bfbf6b for the scheduler-driven follow-up (recurring / SLA / stale-task nudges). 4 new tests (13 total for alerts, 199 full suite). Dogfooded on prod: msg 18bb003a — reminder auto-targeted orion from task dfef4c92 assignee. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: format alerts command * feat(alerts): timestamp sanity guard + response_required default for reminders Per ChatGPT coordination update on ax-cli#53 / b911ea19: - Reject any --remind-at / --due-at before 2020 with a clear error that names the likely root cause (runner with broken/frozen clock). Real case caught in msg b9fb15b6 where a remind_at landed as 2000-01-01. - Reject malformed ISO-8601 with a typed message instead of letting garbage flow into the alert metadata. - Default response_required=true for --kind reminder (they're work nudges — recipient is expected to ack/snooze). --kind alert stays opt-in via --response-required. 3 new tests (16 total alerts, 202 full suite). ruff format + check clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(channel): publish processing status from claude bridge * fix(channel): run claude bridge through axctl * fix(channel): delegate package start to axctl * test(channel): add headless processing smoke * fix(channel): align Claude notification payload * feat(cli): surface agent processing status while waiting * style(cli): format dogfood scheduler files --------- Co-authored-by: anvil <anvil@ax-platform.com> Co-authored-by: orion <orion@paxai.app> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * draft(spec): SEND-TO-AGENT-001 CLI contract for sending tasks and alerts (#55) Task b38a7475: users need an intuitive way to send a task or alert to an agent as a real request with structured context. Today's workaround is copy-paste the id into a plain message, which drops the structured reference and teaches the receiver to guess. This spec defines the two commands, the outgoing envelope shape (one transcript message, one card, reuses PR #53 alert metadata + PR #54 task snapshot pattern), how delivery receipts flow through (SEND-RECEIPTS-001), and how the flow differs from plain ax send vs. passive app signals. Owner split: - CLI (orion, this spec + impl): tasks send / alerts forward - Frontend (frontend_sentinel, task 60113fd7): Send to Agent button + receiver card rendering - MCP (mcp_sentinel, follow-up): optional tasks.send / alerts.send MCP tool - Backend: no schema changes, plain messages POST accepts the envelope Composes with PR #107 (availability-escalation), PR #108 (delivery- receipts), PR #54 (task snapshot embedding), PR #53 (ax alerts MVP). Task: b38a7475-8bf6-445e-bd6e-1845222885dd Co-authored-by: anvil <anvil@ax-platform.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(alerts): embed task snapshot in reminder alert metadata (#54) (#57) Task e55be7c8: task reminder alert cards today truncate and surface raw implementation fields, with no Open Task action even though the payload includes source_task_id. This commit does the CLI-side half — enrich the reminder envelope with a compact task snapshot (id, title, priority, status, assignee_id, assignee_name, creator_id, deadline) so the frontend can render task context inline without a second round-trip. Changes - alerts.py: extract _agent_name_for + _fetch_task_snapshot helpers (shared by _resolve_target_from_task). - alerts.py: _build_alert_metadata grows a task_snapshot kwarg; when present, embeds at alert.task and card_payload.task. - reminders.py: _fire_policy fetches the snapshot once per fire and passes it to _build_alert_metadata. - tests: positive case (snapshot embedded with all fields) + negative case (fetch failure still fires reminder with source_task_id fallback). Frontend half (task e55be7c8 assignee frontend_sentinel) renders the task block on the alert card + wires an Open Task button to resource_uri ui://tasks/{source_task_id}. The MCP widget ui://tasks/detail already exists; the button is a simple MCP app link. Validation - PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest tests/test_alerts_commands.py tests/test_reminders_commands.py - Result: 21 passed (19 existing + 2 new) Task: e55be7c8-4758-434c-bea9-1a35b27a769a Co-authored-by: anvil <anvil@ax-platform.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(reminders): lifecycle-aware source task check (#58) Tasks: e032bc49 (urgent) + f00e36ac (high). Before firing a task-backed reminder policy, fetch the source task and classify its lifecycle: - Terminal (completed/closed/done/cancelled/canceled/archived/resolved, or completed_at set) → disable the policy + emit a skipped-result. No message is sent, fired_count does NOT advance. - Pending review (status=pending_review, tags contains pending_review, requirements.pending_review truthy, or requirements.review_owner* set) → reroute to review_owner → creator_fallback, prefix the reason with [pending review]. Do not wake the assignee. - Active → unchanged default (assignee / creator fallback). Adds _task_lifecycle() in alerts.py; reminders.py wires it through _fire_policy and the run loop (skipped results do not advance). Docs: docs/reminder-lifecycle.md with the full state table, routing priority, envelope changes, and backward-compat notes. Tests: 3 new — terminal skip+disable, pending_review → review_owner, pending_review fallback → creator. 220 total pass. Co-authored-by: anvil <anvil@ax-platform.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(channel): define CLI presence receipts * fix(channel): process idle event before reconnect --------- Co-authored-by: anvil <anvil@ax-platform.com> Co-authored-by: orion <orion@paxai.app> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cherry-picks the channel idle-reconnect fix (dev/staging PR #59, commit babbda9) onto main so it ships in the next release. Urgent for task 24646c02.
What changed
ax_cli/commands/channel.py: process the SSE event that wakes an idle stream BEFORE breaking for JWT refresh.channel/README.md,specs/LISTENER-001/spec.md: presence-receipt contract docs.tests/test_channel.py: regression test.Why not a dev/staging → main roll-up?
Divergence between main and dev/staging requires a larger merge commit / conflict resolution. Cherry-picking just the urgent fix is safer for the reminder-lifecycle task. A separate dev/staging → main PR will catch up the remaining commits (docs/credentials/context).
Test plan
pytest tests/test_channel.py— 13 passedreconnect_after_eventinax_cli/commands/channel.py; run timed reminder test.Authored by anvil; cherry-picked by orion.