Skip to content

feat: wire chat lifecycle hooks into chatd#27275

Closed
ibetitsmike wants to merge 21 commits into
mike/chat-hooks/backendfrom
mike/chat-lifecycle-hooks
Closed

feat: wire chat lifecycle hooks into chatd#27275
ibetitsmike wants to merge 21 commits into
mike/chat-hooks/backendfrom
mike/chat-lifecycle-hooks

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Stack Context

Second of a 2-PR stack adding chat lifecycle hook webhooks. #27401 landed the standalone backend (dispatcher package coderd/x/chathooks, codersdk/agenthooks wire contract, chat_hook_dispatches table, config knobs, docs). This PR activates it.

What?

Wires lifecycle hook dispatch into chatd and the chat API, letting one globally configured external HTTP consumer observe and control chat agent lifecycles across seven events: session_start, user_prompt_submit, pre_tool_use, post_tool_use, stop, pre_compact, and post_compact.

Requires both the hook configuration and the agent-lifecycle-hooks experiment (CODER_EXPERIMENTS=agent-lifecycle-hooks, excluded from *), all introduced in #27401.

How it works

Responses can deny or rewrite prompts and tool inputs, inject model context, surface user notices, restrict the tool set, end a chat, or request one continuation nudge per turn. Dispatch is fail-closed: hook outages surface as HTTP 502 on gated API requests or move the chat to an error state, and no gated action proceeds unreviewed.

  • coderd constructs the dispatcher only when hooks are configured and the experiment is on; a configured-but-ungated deployment logs a startup warning and stays inert. Defense in depth: chatd.New also refuses an injected dispatcher without the experiment.
  • chatd integration: user_prompt_submit gates sends, queued sends, edits, and chat creation before persistence; pre_tool_use rewrites or denies tool calls before the assistant step persists; post_tool_use runs before tool results commit and its fail-closed error lands atomically with the step; stop supports a single continuation nudge; compaction hooks dispatch before the compaction commit so their effects land atomically with the step.
  • chats.hook_allowed_tools (migration 000552) persists tool restrictions and intersects with future tool exposure, and an active policy injects a system notice so the model does not fabricate calls to stripped tools; chat_messages.turn_id identifies the user message that started each turn. Send and edit responses return every inserted message (hook notices included) so client caches never miss lower-ID rows.
  • Frontend: chat send/edit mutations upsert the full returned message batch and surface ended-chat and hook-notice states.

NOTE: Migration 000552 adds chats.hook_allowed_tools, chat_messages.turn_id, and chat_queued_messages.{turn_id,hook_prefix,hook_allowed_tools}, and recreates the chats_expanded view. The chat_hook_dispatches table landed in #27401.

This PR was authored by Mux (AI agent) working on Mike's behalf.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Docs preview

Check off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here.

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: bb5ad536d0

ℹ️ 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 coderd/x/chatd/chathooks/dispatcher.go Outdated
Comment thread coderd/exp_chats.go Outdated
Comment thread codersdk/agenthooks/http.go Outdated
Comment thread site/src/api/queries/chats.ts
Comment thread coderd/x/chatd/chatstate/transitions.go Outdated
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: 4c3deb6255

ℹ️ 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 coderd/database/dbauthz/dbauthz.go Outdated
Comment thread coderd/x/chatd/chatstate/transitions.go Outdated
Comment thread site/src/api/typesGenerated.ts Outdated
Comment thread coderd/x/chatd/generation.go Outdated
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: da9e31ed4c

ℹ️ 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 coderd/x/chatd/chatd.go Outdated
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: 8775de5b78

ℹ️ 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 coderd/x/chatd/generation.go Outdated
Comment thread coderd/x/chatd/chatd.go
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: c833f11a2e

ℹ️ 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 coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go Outdated
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: 45d4b5796f

ℹ️ 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 coderd/x/chatd/chatd.go
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: fa8e9fe012

ℹ️ 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 coderd/x/chatd/hooks.go
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: c363878f35

ℹ️ 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 coderd/x/chatd/hooks.go Outdated
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: 35526b5c9f

ℹ️ 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 coderd/x/chatd/chatd.go
Comment thread coderd/exp_chats.go
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: ae7ab19b96

ℹ️ 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 coderd/x/chatd/chatd.go
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: 48d613f3f3

ℹ️ 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 coderd/x/chatd/generation.go Outdated
Comment thread coderd/x/chatd/generation.go Outdated
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

Posted by Mux on behalf of Mike.

@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: 7f8cd31e8c

ℹ️ 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 codersdk/agenthooks/http.go
Comment thread coderd/x/chatd/generation_preparer.go
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

Posted by Mux on behalf of Mike.

@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: d06b97ccd7

ℹ️ 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 coderd/x/chatd/chatstate/transitions.go Outdated
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

Posted by Mux on behalf of Mike.

@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: 4060962c72

ℹ️ 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 coderd/x/chatd/hooks.go
Comment thread site/src/pages/AgentsPage/AgentChatPage.tsx

// endDescendantChats uses nested machines so descendant snapshots and publications
// share the outer transaction. ID order follows the family lock order.
func (tx *Tx) endDescendantChats(chat database.Chat) ([]database.Chat, error) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

instead of forcing ending on all the children, could we go down the route of dispatching the end for all children of the root agent?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Restructured in 4b2efba: the multi-chat entry is now EndChatFamily, an explicit orchestrator that dispatches the single-chat EndChat transition per descendant through nested machines (per-chat lock, per-chat matrix validation, shared publish buffer, one outer transaction). That is the dispatch-per-child model, kept inside one transaction so a partial family end cannot commit.

Posted by Mux on behalf of Mike.

Comment thread coderd/x/chatd/subagent.go Outdated
}
if overridden {
prompt = override
// Avoid deriving titles from the prompt that policy replaced.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

the prompt should already be redacted before we reach this point

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

There is no earlier redaction on this path: pre_tool_use can override the spawn_agent input, but nothing guarantees it, and the user_prompt_submit override lands exactly here. The real defect was deriving the title from the original prompt before the hook ran, which forced this recompute. Fixed in f47c86b: the fallback title is now derived once, after hooks settle the final prompt.

Posted by Mux on behalf of Mike.

Comment thread coderd/x/chatd/subagent.go Outdated
if err != nil {
return database.Chat{}, err
}
// With no child to archive, end_chat refuses the spawn.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

subagent should never have a child chat

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The synthetic chat here is the prospective child itself (the spawn target), not a child of a subagent; spawn parents are validated root-only. Since the hook fires before the row exists, end_chat has nothing to archive and denies the spawn. Reworded the comment in f47c86b to say that directly.

Posted by Mux on behalf of Mike.

const (
TransitionCreateChat Transition = "CreateChat"
TransitionSetArchived Transition = "SetArchived"
TransitionEndChat Transition = "EndChat"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

is this transition absolutely necessary considering we are intending to archive the chat on chat_end

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

EndChat transition violates a central assumption about the chat state machine: a state machine transition only changes the state of one chat. EndChat affects multiple chats at the same time

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

EndChat is still needed because SetArchived cannot end active chats: it only allows idle/error states and preserves queue/ownership, while end_chat must end running chats, clear queue/worker/errors/deadlines, and synthesize tool cancellations. The single-transition-single-chat assumption is restored in 4b2efba: TransitionEndChat is validated and applied strictly per chat (applyEndChat touches only tx.chatID), and the multi-chat behavior moved to the named EndChatFamily orchestrator, which dispatches that single-chat transition per descendant inside the shared outer transaction.

Posted by Mux on behalf of Mike.

ALTER TABLE chat_queued_messages
ADD COLUMN turn_id uuid,
ADD COLUMN hook_prefix jsonb,
ADD COLUMN hook_allowed_tools jsonb;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we store this as a dedicated table instead? cc @spikecurtis

@ibetitsmike
ibetitsmike force-pushed the mike/chat-lifecycle-hooks branch from 76c6ef6 to 73e757f Compare July 22, 2026 15:35
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

Posted by Mux on behalf of Mike.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Unknown error
ℹ️ 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".

…subagent spawn

Reuse textFromParts instead of the duplicate promptText helper, move
UserPromptDeniedError next to its producer, inline the four trivial
per-event dispatch wrappers into dispatchLifecycleHook calls, and derive
the subagent fallback title once after hooks settle the final prompt.
… and family orchestration

Rename Tx.EndChat to Tx.EndChatFamily to make explicit that it
orchestrates the single-chat EndChat transition across the addressed
chat and its descendants. TransitionEndChat itself now only ever
changes one chat: applyEndChat archives exactly one chat, and
endDescendantChats dispatches it per descendant through nested
machines sharing the outer transaction and publish buffer.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

Posted by Mux on behalf of Mike.

@ibetitsmike
ibetitsmike force-pushed the mike/chat-lifecycle-hooks branch from 7424289 to 874d219 Compare July 22, 2026 15:52
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex 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: 874d2198f8

ℹ️ 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".

return s.finishSessionStartEnd(ctx, input, result)
}
input.HistoryVersion = result.Chat.HistoryVersion
continue

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 Return after applying session_start effects

When a session_start hook returns a user-visible or model-context message, applySessionStartResponse commits those rows and publishes a chat:update with a new history_version. The runner treats that history change as new work, cancels the active task, and spawns another generation task keyed to the new history; this task then mutates input.HistoryVersion and loops anyway, so both tasks can race until the generation-attempt fence aborts one. This can issue duplicate model/tool work for every session_start response that changes history; after applying the hook effects, let the runner-spawned task own the new history instead of continuing here.

Useful? React with 👍 / 👎.

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

Closing in favor of a restacked, smaller-PR version of this change. The tree at the top of the new stack is identical to this PR's final state (modulo folding the two migrations into a single 000551).

New stack (bottom to top):

All review feedback resolved here is incorporated in the new stack.

This comment was posted by Mux (AI agent) on Mike's behalf.

@github-actions github-actions Bot locked and limited conversation to collaborators Jul 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants