Documentation
adrs/060-linear-notification-system.md
ADR-060: Linear Notification System for Agent Sessions
Status
Accepted
Context
Agent sessions in the Dynaplex system are one-directional with respect to Linear: agents post comments and update issues, but have no mechanism to receive feedback. When a human (or another agent) comments on an issue, the assigned agent only learns about it if explicitly told — e.g., "hey, check SWE-123."
This gap means:
- Human feedback on agent work goes unseen until the next manual check
- Agents cannot self-correct based on comments like "don't do this" or "try a different approach"
- Cross-agent coordination via Linear comments is invisible to the recipient
- The communication loop between humans and agents is fundamentally broken
We considered several approaches:
- Linear MCP server push notifications — Not supported. The MCP server is read/write for issues and comments but has no subscription or webhook mechanism.
- Linear webhooks via Cortex — Linear's API supports webhooks (including auto-provisioning via OAuth apps), but Cortex must be accessible from the internet to receive them.
- Polling via GraphQL API at session start — The Linear GraphQL API is fully accessible with the per-agent OAuth tokens already stored in
~/.dplx/linear-tokens.json. - Polling via Linear MCP tools mid-session — MCP tools are available within agent sessions and can query the same data.
Decision
Implement a two-phase notification system:
Phase 1: Polling (Implemented)
- A shell script (
.claude/hooks/linear-notifications.sh) queries the Linear GraphQL API directly duringSessionStartto show agents what they missed since their last session. - The script reads the agent's token from
~/.dplx/linear-tokens.json, queries for recent comments on assigned/created issues (excluding the agent's own), and queries for newly assigned issues. - A companion skill (
/linear-notifications) uses Linear MCP tools for mid-session on-demand checking. - Both mechanisms share a persistent state file (
.claude/state/linear-last-checked) that tracks the last-checked timestamp across sessions. - The script fails silently on any error (missing token, API timeout, malformed response) to never block session start.
Phase 2: Webhooks via Cortex (Designed, Not Yet Implemented)
- Add a
/api/webhooks/linearendpoint to the Cortex server. - Configure the OAuth app's webhook URL to point to Cortex.
- Cortex receives
Commentevents, resolves the target agent by issue assignee/creator, and writes notification JSON files to the agent's worktree (.claude/state/linear-notifications/). - The
SessionStarthook reads and clears these files alongside polling results. - This provides real-time event capture even when agents are offline — notifications accumulate and are presented at next session start.
Phase 2 requires Cortex to be accessible from the internet (tunnel for dev, Azure for prod). Phase 1 works regardless and serves as a reliable fallback even after Phase 2 is deployed.
Why GraphQL direct queries (not MCP tools) for the hook
The SessionStart hook runs as a shell script before the agent session is fully initialized — MCP tools are not available at that point. The GraphQL API is accessible via curl with the same OAuth tokens, making it the natural choice for the hook. Mid-session, MCP tools are preferred because they're already available and don't require managing raw HTTP requests.
Why polling first
- Zero infrastructure dependencies — works with existing tokens and API access
- Simple to implement, test, and debug
- The 48-hour default window catches all meaningful activity between sessions
- Webhook infrastructure (Cortex accessibility) is not yet consistently available
Consequences
Positive
- Agents now see human and cross-agent feedback at session start without being told
- The communication loop between humans and agents becomes bidirectional
- Silent failure ensures the notification system never degrades the session start experience
- The two-phase design provides an upgrade path without disrupting the working system
- Per-agent state files enable independent notification tracking
Negative
- Polling has inherent latency — activity during a session is only visible via the
/linear-notificationsskill (manual invocation) until Phase 2 webhooks are implemented - Two GraphQL API calls per session start add ~2-4 seconds of latency (within the 30s hook timeout budget)
- The script depends on the
~/.dplx/linear-tokens.jsonfile format remaining stable - Phase 2 requires Cortex internet accessibility, which adds operational complexity
References
- SWE-369: Implement Linear notification system for agent sessions
- FSD: Linear Notification System