Skip to content

docs(product): Linear Agent Session responder design (RIG-2717) - #625

Merged
mattwilkinsonn merged 3 commits into
mainfrom
compass-server/rig-2717-responder-design
Aug 26, 2026
Merged

docs(product): Linear Agent Session responder design (RIG-2717)#625
mattwilkinsonn merged 3 commits into
mainfrom
compass-server/rig-2717-responder-design

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

This PR is part of a stack containing 2 PRs:

  1. main
  2. docs(concepts): capture the comms model (threads vs session log) (RIG-2717) #624
  3. "docs(product): Linear Agent Session responder design (RIG-2717)" (this PR)

Production design record for making the installed Compass Linear app (RIG-2682) a live Linear Agent App: receive Agent Session webhooks, route a delegated issue to the right stable Compass Manager, carry the conversation as a topic in that Manager's home channel, and link the Linear session back out to Compass.

Stacked on #624 (the comms-model concept doc), which this record's premise cites.

All ten open questions were ruled by Matt on 2026-08-25 (RIG-2729); this record folds every ruling in and freezes with no live open questions.

The premise this record is built on

Matt's steer, captured in #624 and load-bearing here: Compass's comms model is deliberate, and Linear's Agent Session model is what it rejects. Compass has stable agents (Managers + peers) each with a home channel; communication rides Zulip-style threads (channel → named topics) and the agent's work stays out of the threads in a side-panel session log. Linear's Agent Session is the opposite — one ephemeral flat activity log per issue, no stable agent, no threads. So the Linear session is a doorway, not a home.

The decision — Option B (dumb link), Matt ruled RIG-2729

A hard constraint forces the mapping-depth choice: Linear's Agent Activity vocabulary is a fixed, server-validated set of five types (thought/action/elicitation/response/error) with no extension point, so Compass's typed comms blocks (a structured ask with discrete options) cannot round-trip through a Linear session.

  • Option A — full relay (bidirectional). Mirror the Compass conversation into the Linear session. Richest, but shows a degraded conversation. Off-table until Linear makes the activity format configurable.
  • Option B — dumb link (chosen). On created, emit one thought + an externalUrls "Open in Compass" deep link to the resolved Manager's home channel; all real interaction happens in Compass. Deletes the entire return relay.
  • Option C — hybrid (ratified follow-up). Dumb link + a coarse one-way status back, no message-level mirroring.

What the bridge does

  1. Receive — a plain POST /webhooks http.Handler on the network TLS door, fail-closed HMAC-SHA256 signature check (bad/missing → 400; stale-but-valid timestamp → 200-with-drop, never a retry-burning 400), ack 200 before any async work.
  2. Route (Matt ruled routing is in scope, OQ-3) — resolve the delegated issue to a stable Manager keyed on Compass's recorded forge ownership index (forge_authored_artifacts, DL-055/DL-205), never a header parsed from forge text (DL-050/DL-094 forbid that reaching a routing decision). An unstamped issue routes to the supervisor via a dedicated routing channel, which decides the lane and stamps it.
  3. Map (Matt ruled not 1-1, OQ-4) — the prompt lands in an issue-named comms topic in the Manager's home channel (sessions on one issue coalesce), delivered as @linear-authored messages on the durable deliver rail, deduped by PostAsAccount's client_request_id on the Linear-Delivery UUID. The deep link targets the home channel, not the topic.
  4. Link back — the two created emits (the ack thought + the session external URL) are the whole return path. No relay, no settle observation, no session-lifecycle machine.

The public base URL (webhook host + deep-link base) is per-deployment (Matt ruled OQ-2): managed = compass.rigel.build, self-host = its own URL, dev/tailnet deploys need their own ingress.

Resolved decisions (all ten OQs, Matt 2026-08-25)

OQ-1 Option B (C follow-up, A off-table) · OQ-2 network door + per-deployment public URL · OQ-3 routing in scope, keyed on the recorded ownership index · OQ-4 not 1-1, link to the home channel · OQ-5 secret names as designed · OQ-6/8/9/10 dissolve under B (no relay → no streaming cadence, no Linear elicitation, no settle-edge observability, no session-lifecycle machine) · OQ-7 production, not a spike.

Ledger-impact

Adds DL-254 (webhook receiver on the network door + per-deployment URL), DL-255 (routing keyed on the recorded ownership index, never a parsed header), and DL-256 (Option-B dumb-link return path + not-1-1 topic mapping) to docs/designs/DECISIONS.md at freeze. Highest row on current main is DL-253; the driver re-verifies the next-free id at freeze.

Spec-impact: none.
Refs RIG-2717.
Co-authored-by: Matt Wilkinson matt@rigel.build

@linear-code

linear-code Bot commented Aug 25, 2026

Copy link
Copy Markdown

RIG-2717

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown

Compass engineering docs preview: https://compass-server-rig-2717-resp.compass-eng-docs.pages.dev

Deployed from compass-server/rig-2717-responder-design at af39c93.

Changed pages:

@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-responder-design branch from a33cd21 to acb8dac Compare August 25, 2026 21:21
…-2717)

Capture Compass's comms model as a first-class `concepts/` doc: **threads for conversation, the session log for work**.

## Why

The premise is load-bearing and already frozen across the ledger (DL-098 Zulip threading, DL-099 streamed-turn-writes-nothing-to-comms, DL-088 log-and-trace are two projections of one artifact, DL-158 workspace = home channel + session trace) — but it lived only in those scattered design records, never stated as one discoverable idea in the `concepts/` layer whose charter is exactly "the load-bearing ideas the code and prompts assume you already hold."

The gap bites when bridging an external agent-session protocol in: the reflex is to adopt that system's flat single-session-per-task-with-everything-in-one-log shape, which is precisely the model Compass's threads/log split exists to reject. This doc states the premise plainly so an integration maps onto the Compass model rather than replacing it.

## What

- New `docs/concepts/comms-model.md`: the two surfaces (session log = work; channels/threads = communication), why the split is structural not a prompting convention, stable agents with home channels, typed comms blocks (`ask` and planned kinds), and the explicit contrast an external-session bridge must respect.
- `docs/concepts/README.md`: new "The comms model" section, placed before "The tools" (which references it).

Spec-impact: none.
Ledger-impact: none.

Refs RIG-2717.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-comms-model-concept branch from 1a5ece4 to 88e08df Compare August 25, 2026 21:56
@rigel-mintaka rigel-mintaka changed the title docs(product): Linear Agent Session responder spike design (RIG-2717) docs(product): Linear Agent Session responder design (RIG-2717) Aug 25, 2026
@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-responder-design branch 2 times, most recently from 6cfcd60 to b0dd959 Compare August 25, 2026 22:05
rigel-mintaka and others added 2 commits August 25, 2026 18:12
Production **design record** for making the installed `Compass` Linear app (RIG-2682) a live Linear Agent App: receive Agent Session webhooks, route a delegated issue to the right stable Compass Manager, carry the conversation as a topic in that Manager's home channel, and link the Linear session back out to Compass.

Stacked on #624 (the comms-model concept doc), which this record's premise cites.

All ten open questions were ruled by Matt on 2026-08-25 (RIG-2729); this record folds every ruling in and freezes with no live open questions.

## The premise this record is built on

Matt's steer, captured in #624 and load-bearing here: **Compass's comms model is deliberate, and Linear's Agent Session model is what it rejects.** Compass has stable agents (Managers + peers) each with a home channel; communication rides Zulip-style threads (channel → named topics) and the agent's *work* stays out of the threads in a side-panel session log. Linear's Agent Session is the opposite — one ephemeral flat activity log per issue, no stable agent, no threads. So the Linear session is a doorway, not a home.

## The decision — Option B (dumb link), Matt ruled RIG-2729

A hard constraint forces the mapping-depth choice: **Linear's Agent Activity vocabulary is a fixed, server-validated set of five types** (`thought`/`action`/`elicitation`/`response`/`error`) with no extension point, so Compass's typed comms blocks (a structured `ask` with discrete options) cannot round-trip through a Linear session.

- **Option A — full relay (bidirectional).** Mirror the Compass conversation into the Linear session. Richest, but shows a degraded conversation. **Off-table** until Linear makes the activity format configurable.
- **Option B — dumb link (chosen).** On `created`, emit one `thought` + an `externalUrls` "Open in Compass" deep link to the resolved Manager's home channel; all real interaction happens in Compass. Deletes the entire return relay.
- **Option C — hybrid (ratified follow-up).** Dumb link + a coarse one-way status back, no message-level mirroring.

## What the bridge does

1. **Receive** — a plain `POST /webhooks` `http.Handler` on the network TLS door, fail-closed HMAC-SHA256 signature check (bad/missing → 400; stale-but-valid timestamp → 200-with-drop, never a retry-burning 400), ack 200 before any async work.
2. **Route** (Matt ruled routing is in scope, OQ-3) — resolve the delegated issue to a stable Manager keyed on Compass's **recorded** forge ownership index (`forge_authored_artifacts`, DL-055/DL-205), **never** a header parsed from forge text (DL-050/DL-094 forbid that reaching a routing decision). An unstamped issue routes to the supervisor via a dedicated routing channel, which decides the lane and stamps it.
3. **Map** (Matt ruled not 1-1, OQ-4) — the prompt lands in an issue-named comms topic in the Manager's home channel (sessions on one issue coalesce), delivered as `@linear`-authored messages on the durable deliver rail, deduped by `PostAsAccount`'s `client_request_id` on the `Linear-Delivery` UUID. The deep link targets the **home channel**, not the topic.
4. **Link back** — the two `created` emits (the ack `thought` + the session external URL) are the whole return path. No relay, no settle observation, no session-lifecycle machine.

The public base URL (webhook host + deep-link base) is **per-deployment** (Matt ruled OQ-2): managed = `compass.rigel.build`, self-host = its own URL, dev/tailnet deploys need their own ingress.

## Resolved decisions (all ten OQs, Matt 2026-08-25)

OQ-1 Option B (C follow-up, A off-table) · OQ-2 network door + per-deployment public URL · OQ-3 routing in scope, keyed on the recorded ownership index · OQ-4 not 1-1, link to the home channel · OQ-5 secret names as designed · OQ-6/8/9/10 dissolve under B (no relay → no streaming cadence, no Linear elicitation, no settle-edge observability, no session-lifecycle machine) · OQ-7 production, not a spike.

## Ledger-impact

Adds DL-254 (webhook receiver on the network door + per-deployment URL), DL-255 (routing keyed on the recorded ownership index, never a parsed header), and DL-256 (Option-B dumb-link return path + not-1-1 topic mapping) to `docs/designs/DECISIONS.md` at freeze. Highest row on current main is DL-253; the driver re-verifies the next-free id at freeze.

Spec-impact: none.
Refs RIG-2717.
Co-authored-by: Matt Wilkinson <matt@rigel.build>
@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-comms-model-concept branch from 689cdd8 to 3ae8486 Compare August 25, 2026 22:13
@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-responder-design branch from b0dd959 to af39c93 Compare August 25, 2026 22:13
Base automatically changed from compass-server/rig-2717-comms-model-concept to main August 26, 2026 02:45
@mattwilkinsonn
mattwilkinsonn merged commit ca5310a into main Aug 26, 2026
12 checks passed
@mattwilkinsonn
mattwilkinsonn deleted the compass-server/rig-2717-responder-design branch August 26, 2026 02:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants