Skip to content

Follow up Linear triggers with Agent Sessions, team routing, and replies - #88

Open
michaelmwu wants to merge 21 commits into
getpaseo:mainfrom
voytravel:agent/linear-v2
Open

Follow up Linear triggers with Agent Sessions, team routing, and replies#88
michaelmwu wants to merge 21 commits into
getpaseo:mainfrom
voytravel:agent/linear-v2

Conversation

@michaelmwu

@michaelmwu michaelmwu commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

This is the single follow-up to the Linear trigger implementation merged in #84. It supersedes closed #59 and packages the remaining Linear capabilities together. It also incorporates the production-tested Agent Session and delivery contribution from @as-cto in voytravel#4 while preserving commit authorship.

Included

  • Native Linear Agent Sessions: signed created/prompted intake, runtime routing, bounded causal history, and explicitly opt-in OAuth scopes.
  • Complete session lifecycle behavior: accepted/failure/closing activities, question elicitation with choices, stop handling, completion after required replies, and deduplication when one delegation emits both session and comment events.
  • Project and team scope routing, with team IDs serving as deterministic route keys for projectless issues.
  • Thread-aware comments: reply-only and app-thread filters, replies anchored to the Linear thread root, and actionable provider delivery errors.
  • Delivery and persistence safeguards, including required-output failure propagation, serialized rotating-token refresh/rebind behavior, and durable ordering between session stops/delegations and delayed trigger creation.

Scope

This branch contains only the unmerged Linear follow-up work and remains cleanly mergeable with current main. It does not duplicate the initial Linear project-trigger implementation that landed in #84.

Validation

Current head 484ba99:

  • Focused Linear/lifecycle/configuration/Postgres acceptance tests: 149 passed.
  • Production Postgres atomic workflow-failure regression: passed.
  • Database migration application tests: 23 passed.
  • npm run typecheck
  • npm run lint
  • npm run format:check
  • npm run db:check
  • npm run build

CI is running against this exact head.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 29, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T20:37:13.429731Z c207080 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d6439afaed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/projects/panels.tsx
@michaelmwu michaelmwu closed this Aug 30, 2026
@michaelmwu
michaelmwu deleted the agent/linear-v2 branch August 30, 2026 09:34
@michaelmwu michaelmwu changed the title Add Linear V2 Agent Sessions, team routing, and replies Follow up Linear triggers with Agent Sessions, team routing, and replies Aug 30, 2026
@michaelmwu
michaelmwu restored the agent/linear-v2 branch August 30, 2026 09:39
@michaelmwu michaelmwu reopened this Aug 30, 2026
@michaelmwu michaelmwu closed this Aug 30, 2026
@michaelmwu
michaelmwu deleted the agent/linear-v2 branch August 30, 2026 09:40
@michaelmwu
michaelmwu restored the agent/linear-v2 branch August 30, 2026 09:41
@michaelmwu michaelmwu reopened this Aug 30, 2026
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@as-cto Could you review #88 when you have time? This is the single ready-for-review Linear follow-up after #59, and it includes the bounded causal history, corrected Linear cursor types, projectless team routing, reply-parent filtering, and connection-isolation regression coverage from your feedback. The focused regression set is green (60 tests). Thank you again for validating the earlier work against a real Linear workspace.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31428bcb33

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/triggers/linear/webhook.ts
@as-cto

as-cto commented Sep 1, 2026

Copy link
Copy Markdown

Reviewing #88 from a self-hosted deployment — thanks for the ping. filters.team routing and the DateTimeOrDuration history fix both work cleanly for us, and the compact-team-event hydration on the latest push closes the gap we'd have hit on projectless issues. We can drop our local equivalents.

Two things we'd like to align on, both about what a user actually sees in the session panel:

1. Live progress in the session. Today a session posts a single accept thought (onDispatchAccepted), then the final response, with an error on failure/termination — nothing in between. From the panel side it reads as "Working…" until the whole answer lands. The Linear layer here looks complete; the gap is upstream of it — the hub only receives coarse lifecycle events from the daemon (accepted / failed / terminated / final output), so there's no live agent output to forward as incremental thought/action activities. Is surfacing daemon-side progress (even coarse step markers) something you'd consider in scope, or is that squarely a daemon/protocol concern to track separately? For anything that runs more than a few seconds, the session currently reads as a black box.

2. Deduplicating a single delegation. A delegation emits both an agent_session event and a comment_created for us, so wiring both triggers fires two agents for one tag. We've worked around it by routing Linear solely through agent sessions and dropping the comment trigger, which is clean — but it means issue-thread replies (not typed into the session panel) only continue the session if Linear delivers them as prompted. Does #88 emit prompted for issue-thread replies on an issue with an active session, or only for messages sent through the session UI? Knowing that determines whether a comment trigger is still needed at all.

Happy to test any of this against our deployment.

@as-cto

as-cto commented Sep 1, 2026

Copy link
Copy Markdown

Follow-up from our self-hosted deployment, this time a concrete bug report on the boot migration in this branch (head 9639bb6), reproduced on a staging copy of our database.

What happens. On first boot, migrated project configurations to organization triggers archives the existing projects and creates one synthetic trigger-<id> project per trigger, with a fresh revision each. Those migrated revisions carry the daemon environment by slug only:

env0 = {"kind":"daemon","name":"target","daemon":"cs8-senspace-vps","cwd":"…"}   ← no daemonId

whereas revisions produced by configurations/install on the same build contain daemonId (resolved at compile time). Since toProjectConfiguration (src/configuration/store.ts) throws active configuration contains an uncompiled daemon reference when daemonId is missing, every event match fails with a 500 after the migration — webhooks and POST /api/v1/manual-runs alike (collectProviderMatches → match → getRevision → parseProjectConfiguration). The container stays healthy, so nothing surfaces unless you dispatch something.

Second effect. Manual runs addressed by the original project slug resolve to the archived project and throw manual project configuration unavailable; they only work when addressed to the synthetic trigger-<id> slug, which nothing tells the operator.

Workaround we use. Right after switching images, re-install every bundle by name: (that path restores archived projects and compiles daemonId), then prove dispatch with a manual check run. Rolling back to the previous image also works once the synthetic projects are archived (status='archived', archived_at, null revision — the projects_archive_shape_check constraint requires all three).

Suggested fix. Have the migration resolve daemon slugs to daemonId the same way the compiler does (or make parseProjectConfiguration tolerate a missing daemonId by resolving the slug at read time, failing only if the daemon is unknown). A boot-time self-check that dispatches nothing but at least parses every active revision and logs unparseable ones would have made this visible immediately.

Happy to test a patched build against our staging copy.

@as-cto

as-cto commented Sep 1, 2026

Copy link
Copy Markdown

Follow-up on the migration report above, after recovering a production hub running this branch.

Re-installing the archived projects by name: (which recompiles daemonId) brings event matching back, but every manual run kept returning 500 (manual project configuration unavailable) even with healthy, active projects. Cause: resolveManualRunProject (src/public-operations/database-adapter.ts) prefers an organization_triggers row of the same name over the project slug, and dispatches to its runtimeProjectId — the synthetic trigger-* project, which is archived after recovery. persistManual then finds no active project and throws. The migration leftovers therefore keep breaking manual runs after the projects themselves are fixed (event matching only reads project_trigger_routes, so it is unaffected).

What worked, verified on a copy of the database and then in production: delete from organization_triggers (revisions and routes cascade) while keeping project_trigger_migrations — without those markers the boot migration runs again on next start and re-archives the projects.

Two small suggestions: resolveManualRunProject could skip organization triggers whose runtime project is not active, and the boot migration could skip (or roll back) projects whose migrated revisions cannot be compiled (missing daemonId), instead of leaving the organization with routes that 500 on every match.

@michaelmwu

Copy link
Copy Markdown
Contributor Author

@as-cto Confirmed both reproductions and fixed them in c96e134.

  • The startup migration now resolves each synthetic runtime configuration through the organization compiler, so daemon environments persist with daemonId. If a project has an unresolved daemon target, that project remains active and no broken organization trigger is written.
  • Manual-run resolution now ignores a same-named organization trigger when its runtime project is no longer active, so it falls back to the active project slug after recovery.

Added migration, embedded persistence, and manual-resolution regressions. Focused migration/manual/configuration tests (26), typecheck, lint, format check, and production build pass locally. Thank you for the staging reproduction.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c96e134a3d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/triggers/linear/webhook.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7aece66b4c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/config/compiler.ts
@as-cto

as-cto commented Sep 2, 2026

Copy link
Copy Markdown

One more finding from production, on issue-comment replies (not agent sessions).

Linear threads are one level deep: commentCreate with a parentId that is itself a reply is rejected with Parent comment must be a top level comment. When creating a reply the parentId should be set to the same value as the comment you're replying to. A hub build that replied with parentId = triggering comment id therefore failed delivery for every reply to a nested comment (12 of 12 failed deliveries over four days matched this; all 24 successes targeted a root comment or a session). This branch avoids the error by posting comment replies without parentId, but that drops them out of the thread.

What we run now: the reply executor passes parentId = comment.parentId ?? comment.id (thread root), and the hub.reply tool error includes the provider message ("Provider said: …") so the agent knows why a delivery failed instead of retrying blindly. Also worth noting for the required-output logic: an execution whose linear.reply attempts all failed still ended as succeeded once the agent called finish_execution; we now end it as failed with output_delivery_failed.

Happy to open PRs for any of these if useful.

@as-cto

as-cto commented Sep 2, 2026

Copy link
Copy Markdown

Thanks for c96e134 — we merged the current head (7aece66) on top of our production patches with no conflicts, and the full suite is green on that combination (1239 tests, typecheck, lint, format). We have not yet booted that build against a copy of our recovered database, so the migration path itself is still verified only by your regressions on our side; we will report if the staging boot says otherwise.

As offered, the fixes we described above (thread-root replies, provider error forwarded to the agent, output_delivery_failed) plus the session lifecycle changes we run in production are now a single PR against this branch: voytravel#4. Summary of what it adds, beyond what is already in this thread:

  • the idle deadline only completes an execution once its required outputs were emitted, and completes right away once the reply is posted;
  • a workflow that ends without hub.reply gets an explicit closing response instead of leaving the session open;
  • hub.reply with kind: "question" and options becomes an elicitation activity with a select signal (session in awaitingInput);
  • the stop signal stops running and undispatched executions instead of opening a run;
  • thread_with_app: true comment filter, and a comment run superseded when the same comment also opens a session (commentId or sourceCommentId) — this is the deduplication from question 2 above.

It is one squashed commit with the per-topic history linked in the PR; glad to split it any way that suits the review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b408e017d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/providers/linear/client.ts Outdated
Comment thread src/daemons/lifecycle.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b40974bb91

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/daemons/lifecycle.ts
Comment thread src/triggers/linear/provider.ts Outdated
Comment thread src/triggers/linear/provider.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@as-cto Integrated voytravel#4 as fe71b2d with your authorship preserved. I also fixed the three current-head lifecycle findings in 3f84488: late idle completion now reports success, Stop survives trigger-revision changes, and multi-route stops emit one receipt-owned confirmation while stopping work in every routed project. The full combined suite passes (1,245 tests; 15 environment-gated skips), as do typecheck, lint, format, database drift, and build. Thank you for the production repros and contribution.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f8448819b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/db/trigger-acceptance.ts
@michaelmwu

Copy link
Copy Markdown
Contributor Author

@as-cto Closing the loop on your earlier session-panel questions: your voytravel#4 contribution is now integrated with authorship preserved, including session/comment delegation dedup and continuation behavior. I also confirmed that live incremental progress is a separate daemon/protocol concern: Hub currently receives lifecycle boundaries and final output, not truthful intermediate agent output to forward. I am deliberately keeping synthetic progress machinery out of this Linear follow-up rather than expanding an already broad PR.

@as-cto

as-cto commented Sep 2, 2026

Copy link
Copy Markdown

Two more findings from end-to-end runs against a real workspace on this branch (7aece66 + our patches), both reproducible, both also affecting main as far as the first one goes.

1. Comment history hydration always fails: $issueId: String! in an ID position. PaseoIssueCommentHistory (src/providers/linear/client.ts) declares $issueId: String! but uses it in issue: { id: { eq: $issueId } }, where IDComparator.eq expects ID. Linear rejects the query with Variable "$issueId" of type "String!" used in position expecting type "ID". Every comment run logs linear.issue.history.hydrate failed and the agent sees no thread history; replaying the query with $issueId: ID! succeeds. The same declaration is on main (with DateTime!), so #84 has it too. The PaseoComment mutation is fine: CommentCreateInput.issueId is a String.

2. Session threads are comment threads, so a human reply in a session fires twice. This answers question 2 above, from observation: Linear materializes each agent-session activity as a comment in the issue thread (root posted by the Linear bot, "This thread is for an agent session with …", agent responses as comments authored by the app user). Consequences:

Fix we are testing, to be folded into voytravel#4: exclude comment threads whose root is one of issue.agentSessions[].comment.id, and supersede the comment run on prompted as well, using agentActivity.sourceCommentId (the human comment that became the prompt; sourceComment.id in the API). With that, one human message in a session yields exactly one agent turn.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3175743e81

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/daemons/lifecycle.ts
Comment thread src/triggers/linear/provider.ts Outdated
Comment thread src/db/trigger-acceptance.ts
@as-cto

as-cto commented Sep 2, 2026

Copy link
Copy Markdown

Small operational note, unrelated to Linear itself: every execution on this branch logs a 500 on GET /agent-executions/<id>/mcp (the route only declares POST; the MCP client's SSE probe hits it, no effect on the run). #73 fixes exactly that with a 405 and Allow: POST, so we will not duplicate it here — merging #73 would clear those lines from self-hosted logs.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 484ba990d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 123 to +127
or(
isNull(schema.projectTriggerRoutes.resourceId),
eq(
schema.projectTriggerRoutes.resourceId,
resourceId === undefined ? "" : String(resourceId),
),
...(resourceIds.length === 0
? []
: [inArray(schema.projectTriggerRoutes.resourceId, resourceIds)]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route stops to projects with active session work

When a project with an active Agent Session activates a revision containing no Linear trigger, activateProjectConfigurationRevision deletes its prior project_trigger_routes, so this current-route-only lookup returns no rows, records no_project_route, and never reaches the provider's early stop handler. The existing execution can therefore continue after the operator presses Stop; preserve a cancellation route or also locate projects with matching active session work independently of the current launch configuration.

AGENTS.md reference: AGENTS.md:L26-L26

Useful? React with 👍 / 👎.

@as-cto

as-cto commented Sep 2, 2026

Copy link
Copy Markdown

Both findings above are now fixed and verified in production on our side; the commits are in voytravel#4 (details there), and the $issueId: ID half is also standalone against main as #105. After the switch: a reply typed in a session yields exactly one agent turn (comment receipt rejected, prompted runs), a mention in a legacy thread yields one visible answer (comment run superseded by the session), and no history.hydrate failed line remains.

michaelmwu and others added 21 commits September 3, 2026 05:22
…tions, honor stop; reply under thread roots and fail runs on lost deliveries

Squashed from the per-topic branches we run in production on a self-hosted hub
(image lineage linear-v5/v6, built on this PR's head).

Session lifecycle
- idle deadline: an execution is only completed at its idle deadline once its
  required outputs (linear.reply, required: true) were emitted; a session that
  already replied is completed, not left open.
- explicit close: when a workflow ends without hub.reply, the hub posts a short
  closing response itself instead of leaving the session open silently.
- questions: hub.reply accepts kind: "question" with options, delivered as a
  Linear elicitation activity with a select signal; the session goes to
  awaitingInput instead of complete. Choices are deduplicated.
- stop: the Linear stop signal no longer opens a run; it stops running and
  undispatched executions (stopped_by_user / agent_session_stopped).

Issue comments
- replies are posted under the thread root (comment.parentId ?? comment.id):
  Linear only accepts one level of nesting and rejects a parentId that is
  itself a reply ("Parent comment must be a top level comment").
- the provider error is forwarded to the agent in the hub.reply tool error
  ("Provider said: ...") instead of being swallowed.
- new comment filter thread_with_app: true keeps a reply only when the app
  already posted in that thread; complements replies_only.
- a comment run is superseded (superseded_by_agent_session) when the same
  comment also opens an agent session, by commentId or sourceCommentId, so a
  single delegation no longer fires two agents.

Executions
- a required output whose delivery attempts all failed ends the execution,
  step and run as failed (output_delivery_failed) at finish_execution instead
  of succeeded; on a session a short error activity is posted.
`PaseoIssueCommentHistory` declared `$issueId: String!` where the issue
filter expects an `ID`. Linear rejected every request, so comment runs
never received their thread history.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…supersede on prompted

Linear materializes an agent session as a comment thread: the root is a
bot comment, the user's prompts are their comments, and the app's
responses are comments authored by the app user. After the first
response every session thread therefore satisfied `thread_with_app`, so
a reply there started both an agent-session run (prompted) and a
comment run, and the user was answered twice.

- `readCommentThread` now also returns the root comment ids of the
  issue's agent sessions, read in the same request through the comment's
  issue. The normalized comment event carries `threadIsAgentSession`,
  which `thread_with_app` treats as disqualifying; `replies_only` alone
  is unaffected. The provider logs the skipped comment at debug level.
- A prompted agent session carries the comment behind the prompt as
  `agentSession.sourceCommentId` (read from the activity's
  `sourceCommentId`, nested `sourceComment`, or content). The provider
  supersedes the comment run started from that comment, as it already
  did for the comment that created a session. A prompt without a comment
  supersedes nothing.

The webhook order observed in production is what justifies superseding
on prompted too: for a reply in a session thread, Linear emits the
comment webhook first and the prompted agent-session webhook about
100 ms later, so a comment run may already exist when the prompt is
matched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c20708025f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

nodes { user { id } botActor { id } }
pageInfo { hasNextPage endCursor }
}
issue { agentSessions(first: 50) { nodes { comment { id } } } }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Paginate agent sessions before classifying the thread

When an issue has more than 50 Agent Sessions and the relevant thread root is outside this first page, agentSessionRootIds omits it and threadIsAgentSession is set to false. A thread_with_app comment trigger can then launch a duplicate run for a reply that Linear is already delivering as an Agent Session prompt; paginate this connection or query the root's session association directly before classifying the thread.

AGENTS.md reference: AGENTS.md:L24-L24

Useful? React with 👍 / 👎.

and(
eq(schema.projects.id, schema.triggerRuns.projectId),
eq(schema.projects.organizationId, organizationId),
eq(schema.projects.status, "active"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include archived projects when routing session stops

When a project is archived while an Agent Session execution is still running, archiveProject removes its trigger routes without terminating that execution, and this status = active join also excludes its running trigger run from cancellation routing. The Stop webhook is therefore recorded as no_project_route and never reaches stopLinearAgentSession, allowing the daemon to keep working after the user presses Stop; cancellation lookup should include archived projects that still have matching live work.

AGENTS.md reference: AGENTS.md:L26-L26

Useful? React with 👍 / 👎.

Comment on lines +709 to +713
await options.client?.createAgentActivity({
linearOrganizationId: event.organizationId,
agentSessionId,
content: { type: "response", body: "Stopped at your request." },
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Deduplicate stop confirmations across concurrent retries

When Linear retries the same Stop delivery before the first handler finishes, receipt replay returns the accepted routes because agent_session_stopped is not persisted until match returns. Both invocations consequently reach this mutation, and the route-ownership check allows both because they share the same first route, producing duplicate “Stopped at your request” activities; claim the confirmation at receipt/session level before posting it.

Useful? React with 👍 / 👎.

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