Context
protoWorkstacean#482 tracks a downstream feature blocked on this: when a Linear issue is filed via the Linear → protoMaker board bridge (`LinearProtoMakerBridgePlugin`), the filing close-the-loop is automatic (protoMaker's response routes back as a Linear comment via the existing reply.topic plumbing). What's missing: a "feature done" close-the-loop so that when a board feature is later transitioned to a terminal state, a comment is automatically posted on the originating Linear issue.
This requires protoMaker to publish lifecycle events on the workstacean bus that downstream consumers can subscribe to.
What's needed
A bus event family on the protoMaker side that fires whenever a board feature transitions to a terminal state (done / cancelled / archived). Suggested shape:
```ts
bus.publish("protomaker.feature.completed", {
payload: {
featureId: "...",
projectSlug: "...",
title: "...",
completedAt: ,
transitionedBy: "auto-mode" | "user" | "agent",
// Echo the meta we received on creation (manage_feature dispatches set
// sourceLinearIssueId, sourceLinearIdentifier, etc.) so consumers
// reconstruct lineage without a second query.
sourceMeta: { ... },
},
});
```
For symmetry / completeness, also emit:
- `protomaker.feature.cancelled`
- `protomaker.feature.archived` (or whatever terminal states the board supports)
Why on the bus, not via polling
Polling protoMaker for feature state from the consumer side requires the bridge to track every `featureId → linearIssueId` mapping in persisted state, plus a polling loop, plus retry/backoff, plus restart recovery. Pub/sub is the right shape — protoMaker already knows the moment a transition happens.
What lands when this ships
In protoWorkstacean (`lib/plugins/linear-protomaker-bridge.ts`), the done-loop becomes a ~10-line subscriber:
```ts
bus.subscribe("protomaker.feature.completed", "linear-protomaker-bridge", (msg) => {
const linearIssueId = msg.payload?.sourceMeta?.sourceLinearIssueId;
if (!linearIssueId) return;
bus.publish(`linear.reply.${linearIssueId}`, {
payload: { text: `Board feature ${msg.payload.featureId} completed.` },
...
});
});
```
The Linear plugin's existing outbound subscriber posts the comment automatically (and now publishes a `linear.reply.result.${cid}` confirmation event so the bridge knows landing state — see protoLabsAI/protoWorkstacean#486).
Acceptance
Cross-references
Context
protoWorkstacean#482 tracks a downstream feature blocked on this: when a Linear issue is filed via the Linear → protoMaker board bridge (`LinearProtoMakerBridgePlugin`), the filing close-the-loop is automatic (protoMaker's response routes back as a Linear comment via the existing reply.topic plumbing). What's missing: a "feature done" close-the-loop so that when a board feature is later transitioned to a terminal state, a comment is automatically posted on the originating Linear issue.
This requires protoMaker to publish lifecycle events on the workstacean bus that downstream consumers can subscribe to.
What's needed
A bus event family on the protoMaker side that fires whenever a board feature transitions to a terminal state (done / cancelled / archived). Suggested shape:
```ts
bus.publish("protomaker.feature.completed", {
payload: {
featureId: "...",
projectSlug: "...",
title: "...",
completedAt: ,
transitionedBy: "auto-mode" | "user" | "agent",
// Echo the meta we received on creation (manage_feature dispatches set
// sourceLinearIssueId, sourceLinearIdentifier, etc.) so consumers
// reconstruct lineage without a second query.
sourceMeta: { ... },
},
});
```
For symmetry / completeness, also emit:
Why on the bus, not via polling
Polling protoMaker for feature state from the consumer side requires the bridge to track every `featureId → linearIssueId` mapping in persisted state, plus a polling loop, plus retry/backoff, plus restart recovery. Pub/sub is the right shape — protoMaker already knows the moment a transition happens.
What lands when this ships
In protoWorkstacean (`lib/plugins/linear-protomaker-bridge.ts`), the done-loop becomes a ~10-line subscriber:
```ts
bus.subscribe("protomaker.feature.completed", "linear-protomaker-bridge", (msg) => {
const linearIssueId = msg.payload?.sourceMeta?.sourceLinearIssueId;
if (!linearIssueId) return;
bus.publish(`linear.reply.${linearIssueId}`, {
payload: { text: `Board feature ${msg.payload.featureId} completed.` },
...
});
});
```
The Linear plugin's existing outbound subscriber posts the comment automatically (and now publishes a `linear.reply.result.${cid}` confirmation event so the bridge knows landing state — see protoLabsAI/protoWorkstacean#486).
Acceptance
Cross-references