fix(linearbot): Prevent Linearbot from marking issues as "done" when it just put a PR up - #959
Merged
goksu merged 2 commits intoJul 16, 2026
Conversation
0xdiid
marked this pull request as ready for review
July 8, 2026 02:18
…w-done-1783467238
goksu
approved these changes
Jul 16, 2026
czxtm
added a commit
to darkmatter/centaur
that referenced
this pull request
Jul 24, 2026
* fix: preserve postgres proxy credentials on resume (paradigmxyz#1099) * feat: Make the chat agent platform-aware (Slack/Discord/Linear/Github) (paradigmxyz#704) * fix(linearbot): don't start an assignment turn when the bot assigns itself (paradigmxyz#945) * fix(linearbot): Prevent Linearbot from marking issues as "done" when it just put a PR up (paradigmxyz#959) Co-authored-by: Gerard <289036782+splits-gerard@users.noreply.github.com> * fix(harness-server): downscale oversized image attachments before the model (paradigmxyz#1077) * fix: omit Slack client secret for PKCE login (paradigmxyz#1100) * fix: use confidential Slack OIDC login (paradigmxyz#1101) * fix(console): separate chat discovery from access (paradigmxyz#1102) Keep the sidebar and default chat selection scoped to chats owned by the signed-in user. Allow users to continue public and explicitly shared chats when the existing access policy permits them. * feat: add LLM message override strategy (paradigmxyz#1096) * feat: add LLM message override strategy * fix: log LLM message override failures * fix: classify overrides from Slack prompt text * Revert "fix: classify overrides from Slack prompt text" This reverts commit 0f553e6. * chore: bump Helm chart version * fix: avoid logging override response bodies * fix: map OpenAI key for Slackbot overrides * fix: make Slackbot OpenAI key optional * fix: align LLM sonnet model alias * fix: support explicit sonnet 5 override * fix: keep Slack override retries idempotent * fix: log successful override strategy responses * fix: reduce slack override strategy log noise (paradigmxyz#1104) * fix: reduce slack override strategy log noise * refactor: accept full logger for slack override strategy * feat: render attached images in console chat (paradigmxyz#1105) * fix(console): clean up chat detail rows (paradigmxyz#1108) * feat: add workflow-scoped principals (paradigmxyz#1107) * feat: add workflow-scoped principals * feat: add workflow host sandbox helm value * chore: bump centaur chart * fix: default workflow host sandbox chart value off * fix: fail closed for workflow principals * fix: label workflow principals by kind * fix: simplify workflow principal labels * fix(console): speed up chat loading (paradigmxyz#1109) * feat(slackbotv2): dispatch Block Kit actions (paradigmxyz#1110) Closes paradigmxyz#1070 * fix: update vulnerable console sanitizers (paradigmxyz#1118) * fix: attach Laminar traces to thread roots (paradigmxyz#1106) * fix: attach Laminar traces to thread roots * fix: use thread root for Codex OTLP fallback * ci: run console gem audit on main (paradigmxyz#1119) * feat(sandbox): install Google Cloud CLI (paradigmxyz#1124) * fix: install workflow analytics dependencies (paradigmxyz#1125) * fix: install workflow analytics dependencies * fix: avoid apt packaging uninstall in workflow images * chore: bump iron-proxy image (paradigmxyz#1126) * fix(session-runtime): avoid redacting sk inside words (paradigmxyz#1132) Co-authored-by: Osraka <98612432+Osraka@users.noreply.github.com> * feat(console): add system theme option (paradigmxyz#1131) * fix: clarify slackbot claude model selection (paradigmxyz#1133) * fix: clarify slackbot claude model selection * fix: support claude opus 4.7 strategy selection * fix: increase message override timeout --------- Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com> * fix(console): show current theme in selector (paradigmxyz#1134) * feat: add native Nanocodex harness (paradigmxyz#1130) * feat: add native nanocodex harness * feat(harness): expose nanocodex child agents * test(slackbot): preserve default around nanocodex opt-in * fix(ci): avoid no-op chart change * fix: harden native nanocodex integration * fix(slackbotv2): preserve pinned thread harness (paradigmxyz#1135) * Make Nanocodex commentary and subagents explicit (paradigmxyz#1136) * Render Nanocodex commentary as Slack progress (paradigmxyz#1137) * fix: surface Granola MCP tool errors (paradigmxyz#1121) Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com> * feat: support gsuite full-text Drive search (paradigmxyz#1142) * fix: use X search pagination token (paradigmxyz#1143) * feat: expose quote and retweet lookups (paradigmxyz#1150) Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com> * feat: add per-proxy labels (paradigmxyz#1141) * feat: add per-proxy labels * fix: satisfy rust proxy label clippy * chore: revert schema dump changes * chore: keep proxy labels in schema dump * fix: harden proxy label sync paths * fix: preserve proxy labels across reuse * refactor: simplify proxy config snapshots * refactor: remove obsolete proxy config paths * Fix Twitter API response handling (paradigmxyz#1157) fix twitter API response handling * fix: support proxy labels in pg dsn form (paradigmxyz#1158) * fix: append mounted overlay system prompts (paradigmxyz#1161) * fix: append mounted overlay system prompts * fix: make sandbox commit hook portable * Increase Codex project instruction limit to 128 KiB (paradigmxyz#1162) fix: increase Codex project instruction limit Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com> * fix: implement Python workflow event waits (paradigmxyz#1163) Bridge WorkflowContext.wait_for_event through the Python host to Absurd's durable event primitive and support paired event emission. Closes paradigmxyz#990 * fix: label observable iron-proxy resources (paradigmxyz#1164) Closes paradigmxyz#1046 Closes paradigmxyz#1024 Co-authored-by: Taren Marsaw <tarenitup@Tarens-iMac.local> Co-authored-by: blok <37964165+blokboy@users.noreply.github.com> * feat: support client credentials broker refresh (paradigmxyz#1165) * chore: configure dependabot updates (paradigmxyz#1166) * chore(deps): bump the ruby-dependencies group in /services/console with 6 updates (paradigmxyz#1168) chore(deps): bump the ruby-dependencies group Bumps the ruby-dependencies group in /services/console with 6 updates: | Package | From | To | | --- | --- | --- | | [tailwindcss-rails](https://github.com/rails/tailwindcss-rails) | `4.4.0` | `4.6.0` | | [lograge](https://github.com/roidrage/lograge) | `0.14.0` | `0.15.0` | | [solid_queue](https://github.com/rails/solid_queue) | `1.4.0` | `1.5.0` | | [solid_cable](https://github.com/rails/solid_cable) | `4.0.0` | `4.0.2` | | [thruster](https://github.com/basecamp/thruster) | `0.1.21` | `0.1.23` | | [selenium-webdriver](https://github.com/SeleniumHQ/selenium) | `4.44.0` | `4.46.0` | Updates `tailwindcss-rails` from 4.4.0 to 4.6.0 - [Release notes](https://github.com/rails/tailwindcss-rails/releases) - [Changelog](https://github.com/rails/tailwindcss-rails/blob/main/CHANGELOG.md) - [Commits](rails/tailwindcss-rails@v4.4.0...v4.6.0) Updates `lograge` from 0.14.0 to 0.15.0 - [Changelog](https://github.com/roidrage/lograge/blob/master/CHANGELOG.md) - [Commits](roidrage/lograge@v0.14.0...v0.15.0) Updates `solid_queue` from 1.4.0 to 1.5.0 - [Release notes](https://github.com/rails/solid_queue/releases) - [Commits](rails/solid_queue@v1.4.0...v1.5.0) Updates `solid_cable` from 4.0.0 to 4.0.2 - [Release notes](https://github.com/rails/solid_cable/releases) - [Commits](rails/solid_cable@v4.0.0...v4.0.2) Updates `thruster` from 0.1.21 to 0.1.23 - [Changelog](https://github.com/basecamp/thruster/blob/main/CHANGELOG.md) - [Commits](basecamp/thruster@v0.1.21...v0.1.23) Updates `selenium-webdriver` from 4.44.0 to 4.46.0 - [Release notes](https://github.com/SeleniumHQ/selenium/releases) - [Changelog](https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES) - [Commits](SeleniumHQ/selenium@selenium-4.44.0...selenium-4.46.0) --- updated-dependencies: - dependency-name: tailwindcss-rails dependency-version: 4.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: ruby-dependencies - dependency-name: lograge dependency-version: 0.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: ruby-dependencies - dependency-name: solid_queue dependency-version: 1.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: ruby-dependencies - dependency-name: solid_cable dependency-version: 4.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: ruby-dependencies - dependency-name: thruster dependency-version: 0.1.23 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: ruby-dependencies - dependency-name: selenium-webdriver dependency-version: 4.46.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: ruby-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the api-rs-dependencies group in /services/api-rs with 25 updates (paradigmxyz#1170) * chore(deps): bump the api-rs-dependencies group Bumps the api-rs-dependencies group in /services/api-rs with 25 updates: | Package | From | To | | --- | --- | --- | | [anyhow](https://github.com/dtolnay/anyhow) | `1.0.102` | `1.0.104` | | [async-trait](https://github.com/dtolnay/async-trait) | `0.1.89` | `0.1.91` | | [aws-smithy-types](https://github.com/smithy-lang/smithy-rs) | `1.5.0` | `1.6.1` | | [bytes](https://github.com/tokio-rs/bytes) | `1.11.1` | `1.12.1` | | [clap](https://github.com/clap-rs/clap) | `4.6.1` | `4.6.4` | | [cron](https://github.com/zslayton/cron) | `0.16.0` | `0.17.0` | | [crossterm](https://github.com/crossterm-rs/crossterm) | `0.28.1` | `0.29.0` | | [base64](https://github.com/marshallpierce/rust-base64) | `0.22.1` | `0.23.0` | | [hmac](https://github.com/RustCrypto/MACs) | `0.12.1` | `0.13.0` | | [jiff](https://github.com/BurntSushi/jiff) | `0.2.28` | `0.2.34` | | [k8s-openapi](https://github.com/Arnavion/k8s-openapi) | `0.27.1` | `0.28.0` | | [kube](https://github.com/kube-rs/kube) | `3.1.0` | `4.2.0` | | [serde](https://github.com/serde-rs/serde) | `1.0.228` | `1.0.229` | | [serde_json](https://github.com/serde-rs/json) | `1.0.150` | `1.0.151` | | [sha2](https://github.com/RustCrypto/hashes) | `0.10.9` | `0.11.0` | | [ratatui](https://github.com/ratatui/ratatui) | `0.29.0` | `0.30.2` | | [rustls](https://github.com/rustls/rustls) | `0.23.40` | `0.23.42` | | [thiserror](https://github.com/dtolnay/thiserror) | `2.0.18` | `2.0.19` | | [time](https://github.com/time-rs/time) | `0.3.47` | `0.3.54` | | [tokio](https://github.com/tokio-rs/tokio) | `1.52.3` | `1.53.1` | | [tokio-util](https://github.com/tokio-rs/tokio) | `0.7.18` | `0.7.19` | | [toml](https://github.com/toml-rs/toml) | `0.8.23` | `1.1.3+spec-1.1.0` | | [tower-http](https://github.com/tower-rs/tower-http) | `0.6.11` | `0.7.0` | | [uuid](https://github.com/uuid-rs/uuid) | `1.23.3` | `1.24.0` | | [futures](https://github.com/rust-lang/futures-rs) | `0.3.32` | `0.3.33` | Updates `anyhow` from 1.0.102 to 1.0.104 - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](dtolnay/anyhow@1.0.102...1.0.104) Updates `async-trait` from 0.1.89 to 0.1.91 - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](dtolnay/async-trait@0.1.89...0.1.91) Updates `aws-smithy-types` from 1.5.0 to 1.6.1 - [Release notes](https://github.com/smithy-lang/smithy-rs/releases) - [Changelog](https://github.com/smithy-lang/smithy-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/smithy-lang/smithy-rs/commits) Updates `bytes` from 1.11.1 to 1.12.1 - [Release notes](https://github.com/tokio-rs/bytes/releases) - [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md) - [Commits](tokio-rs/bytes@v1.11.1...v1.12.1) Updates `clap` from 4.6.1 to 4.6.4 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](clap-rs/clap@clap_complete-v4.6.1...clap_complete-v4.6.4) Updates `cron` from 0.16.0 to 0.17.0 - [Release notes](https://github.com/zslayton/cron/releases) - [Commits](https://github.com/zslayton/cron/commits) Updates `crossterm` from 0.28.1 to 0.29.0 - [Release notes](https://github.com/crossterm-rs/crossterm/releases) - [Changelog](https://github.com/crossterm-rs/crossterm/blob/master/CHANGELOG.md) - [Commits](https://github.com/crossterm-rs/crossterm/commits/0.29) Updates `base64` from 0.22.1 to 0.23.0 - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](marshallpierce/rust-base64@v0.22.1...v0.23.0) Updates `hmac` from 0.12.1 to 0.13.0 - [Commits](RustCrypto/MACs@hmac-v0.12.1...hmac-v0.13.0) Updates `jiff` from 0.2.28 to 0.2.34 - [Release notes](https://github.com/BurntSushi/jiff/releases) - [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md) - [Commits](BurntSushi/jiff@jiff-static-0.2.28...jiff-static-0.2.34) Updates `k8s-openapi` from 0.27.1 to 0.28.0 - [Release notes](https://github.com/Arnavion/k8s-openapi/releases) - [Changelog](https://github.com/Arnavion/k8s-openapi/blob/master/CHANGELOG.md) - [Commits](Arnavion/k8s-openapi@v0.27.1...v0.28.0) Updates `kube` from 3.1.0 to 4.2.0 - [Release notes](https://github.com/kube-rs/kube/releases) - [Changelog](https://github.com/kube-rs/kube/blob/main/CHANGELOG.md) - [Commits](kube-rs/kube@3.1.0...4.2.0) Updates `serde` from 1.0.228 to 1.0.229 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](serde-rs/serde@v1.0.228...v1.0.229) Updates `serde_json` from 1.0.150 to 1.0.151 - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](serde-rs/json@v1.0.150...v1.0.151) Updates `sha2` from 0.10.9 to 0.11.0 - [Commits](RustCrypto/hashes@sha2-v0.10.9...sha2-v0.11.0) Updates `ratatui` from 0.29.0 to 0.30.2 - [Release notes](https://github.com/ratatui/ratatui/releases) - [Changelog](https://github.com/ratatui/ratatui/blob/main/CHANGELOG.md) - [Commits](ratatui/ratatui@v0.29.0...ratatui-v0.30.2) Updates `rustls` from 0.23.40 to 0.23.42 - [Release notes](https://github.com/rustls/rustls/releases) - [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md) - [Commits](rustls/rustls@v/0.23.40...v/0.23.42) Updates `thiserror` from 2.0.18 to 2.0.19 - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](dtolnay/thiserror@2.0.18...2.0.19) Updates `time` from 0.3.47 to 0.3.54 - [Release notes](https://github.com/time-rs/time/releases) - [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md) - [Commits](time-rs/time@v0.3.47...v0.3.54) Updates `tokio` from 1.52.3 to 1.53.1 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](tokio-rs/tokio@tokio-1.52.3...tokio-1.53.1) Updates `tokio-util` from 0.7.18 to 0.7.19 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](tokio-rs/tokio@tokio-util-0.7.18...tokio-util-0.7.19) Updates `toml` from 0.8.23 to 1.1.3+spec-1.1.0 - [Commits](toml-rs/toml@toml-v0.8.23...toml-v1.1.3) Updates `tower-http` from 0.6.11 to 0.7.0 - [Release notes](https://github.com/tower-rs/tower-http/releases) - [Commits](tower-rs/tower-http@tower-http-0.6.11...tower-http-0.7.0) Updates `uuid` from 1.23.3 to 1.24.0 - [Release notes](https://github.com/uuid-rs/uuid/releases) - [Commits](uuid-rs/uuid@v1.23.3...v1.24.0) Updates `futures` from 0.3.32 to 0.3.33 - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/main/CHANGELOG.md) - [Commits](rust-lang/futures-rs@0.3.32...0.3.33) --- updated-dependencies: - dependency-name: anyhow dependency-version: 1.0.104 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: async-trait dependency-version: 0.1.91 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: aws-smithy-types dependency-version: 1.6.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: bytes dependency-version: 1.12.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: clap dependency-version: 4.6.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: cron dependency-version: 0.17.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: crossterm dependency-version: 0.29.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: base64 dependency-version: 0.23.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: hmac dependency-version: 0.13.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: jiff dependency-version: 0.2.34 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: k8s-openapi dependency-version: 0.28.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: kube dependency-version: 4.2.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: api-rs-dependencies - dependency-name: serde dependency-version: 1.0.229 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: serde_json dependency-version: 1.0.151 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: sha2 dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: ratatui dependency-version: 0.30.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: rustls dependency-version: 0.23.42 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: thiserror dependency-version: 2.0.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: time dependency-version: 0.3.54 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: tokio dependency-version: 1.53.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: tokio-util dependency-version: 0.7.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies - dependency-name: toml dependency-version: 1.1.3+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: api-rs-dependencies - dependency-name: tower-http dependency-version: 0.7.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: uuid dependency-version: 1.24.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: api-rs-dependencies - dependency-name: futures dependency-version: 0.3.33 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: api-rs-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * fix: adapt api-rs dependency updates --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthew Slipper <me@matthewslipper.com> * chore(deps): bump the harness-server-dependencies group in /crates/harness-server with 9 updates (paradigmxyz#1169) * chore(deps): bump the harness-server-dependencies group Bumps the harness-server-dependencies group in /crates/harness-server with 9 updates: | Package | From | To | | --- | --- | --- | | [allocative](https://github.com/facebookexperimental/allocative) | `0.3.4` | `0.3.6` | | [base64](https://github.com/marshallpierce/rust-base64) | `0.22.1` | `0.23.0` | | [clap](https://github.com/clap-rs/clap) | `4.6.1` | `4.6.4` | | [serde](https://github.com/serde-rs/serde) | `1.0.228` | `1.0.229` | | [serde_json](https://github.com/serde-rs/json) | `1.0.150` | `1.0.151` | | [sha2](https://github.com/RustCrypto/hashes) | `0.10.9` | `0.11.0` | | [thiserror](https://github.com/dtolnay/thiserror) | `2.0.18` | `2.0.19` | | [tokio](https://github.com/tokio-rs/tokio) | `1.52.3` | `1.53.1` | | [uuid](https://github.com/uuid-rs/uuid) | `1.23.2` | `1.24.0` | Updates `allocative` from 0.3.4 to 0.3.6 - [Release notes](https://github.com/facebookexperimental/allocative/releases) - [Commits](https://github.com/facebookexperimental/allocative/commits) Updates `base64` from 0.22.1 to 0.23.0 - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](marshallpierce/rust-base64@v0.22.1...v0.23.0) Updates `clap` from 4.6.1 to 4.6.4 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](clap-rs/clap@clap_complete-v4.6.1...clap_complete-v4.6.4) Updates `serde` from 1.0.228 to 1.0.229 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](serde-rs/serde@v1.0.228...v1.0.229) Updates `serde_json` from 1.0.150 to 1.0.151 - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](serde-rs/json@v1.0.150...v1.0.151) Updates `sha2` from 0.10.9 to 0.11.0 - [Commits](RustCrypto/hashes@sha2-v0.10.9...sha2-v0.11.0) Updates `thiserror` from 2.0.18 to 2.0.19 - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](dtolnay/thiserror@2.0.18...2.0.19) Updates `tokio` from 1.52.3 to 1.53.1 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](tokio-rs/tokio@tokio-1.52.3...tokio-1.53.1) Updates `uuid` from 1.23.2 to 1.24.0 - [Release notes](https://github.com/uuid-rs/uuid/releases) - [Commits](uuid-rs/uuid@v1.23.2...v1.24.0) --- updated-dependencies: - dependency-name: allocative dependency-version: 0.3.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: harness-server-dependencies - dependency-name: base64 dependency-version: 0.23.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: harness-server-dependencies - dependency-name: clap dependency-version: 4.6.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: harness-server-dependencies - dependency-name: serde dependency-version: 1.0.229 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: harness-server-dependencies - dependency-name: serde_json dependency-version: 1.0.151 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: harness-server-dependencies - dependency-name: sha2 dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: harness-server-dependencies - dependency-name: thiserror dependency-version: 2.0.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: harness-server-dependencies - dependency-name: tokio dependency-version: 1.53.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: harness-server-dependencies - dependency-name: uuid dependency-version: 1.24.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: harness-server-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * fix: keep harness allocative compatible --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthew Slipper <me@matthewslipper.com> * chore(deps): bump the docs-dependencies group in /docs with 5 updates (paradigmxyz#1167) * chore(deps): bump the docs-dependencies group in /docs with 5 updates Bumps the docs-dependencies group in /docs with 5 updates: | Package | From | To | | --- | --- | --- | | [react](https://github.com/react/react/tree/HEAD/packages/react) | `19.2.6` | `19.2.8` | | [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `19.2.6` | `19.2.8` | | [waku](https://github.com/wakujs/waku/tree/HEAD/packages/waku) | `1.0.0-alpha.6` | `1.0.0-beta.7` | | [typescript](https://github.com/microsoft/TypeScript) | `5.9.3` | `7.0.2` | | [wrangler](https://github.com/cloudflare/workers-sdk/tree/HEAD/packages/wrangler) | `4.102.0` | `4.114.0` | Updates `react` from 19.2.6 to 19.2.8 - [Release notes](https://github.com/react/react/releases) - [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/react/react/commits/v19.2.8/packages/react) Updates `react-dom` from 19.2.6 to 19.2.8 - [Release notes](https://github.com/react/react/releases) - [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/react/react/commits/v19.2.8/packages/react-dom) Updates `waku` from 1.0.0-alpha.6 to 1.0.0-beta.7 - [Release notes](https://github.com/wakujs/waku/releases) - [Changelog](https://github.com/wakujs/waku/blob/main/CHANGELOG.md) - [Commits](https://github.com/wakujs/waku/commits/v1.0.0-beta.7/packages/waku) Updates `typescript` from 5.9.3 to 7.0.2 - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/commits) Updates `wrangler` from 4.102.0 to 4.114.0 - [Release notes](https://github.com/cloudflare/workers-sdk/releases) - [Commits](https://github.com/cloudflare/workers-sdk/commits/wrangler@4.114.0/packages/wrangler) --- updated-dependencies: - dependency-name: react dependency-version: 19.2.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: docs-dependencies - dependency-name: react-dom dependency-version: 19.2.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: docs-dependencies - dependency-name: waku dependency-version: 1.0.0-beta.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: docs-dependencies - dependency-name: typescript dependency-version: 7.0.2 dependency-type: direct:development update-type: version-update:semver-major dependency-group: docs-dependencies - dependency-name: wrangler dependency-version: 4.114.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: docs-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * fix: keep docs waku version compatible --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthew Slipper <me@matthewslipper.com> * fix: preserve applied migration versions Keep the product branch's SQLx checksums stable and append the incoming OMP and ownership schema changes after version 47. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: zhygis <5236121+Zygimantass@users.noreply.github.com> Co-authored-by: diid <123841842+0xdiid@users.noreply.github.com> Co-authored-by: Gerard <289036782+splits-gerard@users.noreply.github.com> Co-authored-by: Akshaan Kakar <akshaan.crackers@gmail.com> Co-authored-by: Goksu Toprak <19259594+goksu@users.noreply.github.com> Co-authored-by: Matthew Slipper <me@matthewslipper.com> Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com> Co-authored-by: Osraka <98612432+Osraka@users.noreply.github.com> Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Perry Dime <svc_ai@paradigm.xyz> Co-authored-by: Taren Marsaw <tarenitup@Tarens-iMac.local> Co-authored-by: blok <37964165+blokboy@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: cooper <cooper@darkmatter.io>
0xdiid
added a commit
to 0xSplits/centaur
that referenced
this pull request
Aug 1, 2026
* docs: add vmetrics deployment prompt guidance (#839)
* feat: persist session titles (#837)
Generate a short GPT-backed title when the first user message is appended.
Store titles on sessions and expose them in session context responses.
* Remove legacy agent API leftovers (#836)
Closes paradigmxyz/centaur#640
Co-authored-by: Amp <amp@ampcode.com>
* feat: auto-reload repo-cache tools in sandboxes (#840)
* [codex] default sandbox lifecycle cleanup (#739)
* fix: default sandbox timeout policy
* fix: rely on sandbox max lifetime reaping
* docs: clarify sandbox lifecycle timers
* fix: prune stale warm sandboxes before replenishing
* fix: prune stale warm sandboxes across workloads
* fix: preserve idle pause deadlines after restart
* refactor: simplify idle cleanup candidate query
* feat: add live activity summaries
* feat: add sandbox capacity manager (#812)
* fix: stop syncing tool secrets to infra role (#845)
* fix: gate activity summary status rendering (#846)
* Guide crypto tool usage away from bad raw endpoints (#847)
Co-authored-by: Centaur AI <ai@centaur.local>
* fix: handle attachment refs in sandbox prompt
* fix: lease session stdout ownership (#851)
* feat(chart): add console.slackOauth flag for Slack console sign-in (#862)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: restrict non-observability sandbox egress (#858)
* fix: restrict non-observability sandbox egress
* fix: whitelist observable cluster egress explicitly
* fix: allow in-cluster database egress
* fix: tighten restricted sandbox egress review gaps
* fix: use configured control plane network peer
* fix: keep restricted blocklist observability scoped
* fix: allow direct victoria observability egress
* fix: configure sandbox observability egress explicitly
* fix: derive observability egress from endpoints
* fix: avoid hardcoded observability endpoints
* fix: allow sandbox egress to api pods
* fix: label observable sandboxes for egress (#864)
* fix: improve activity summary quality (#850)
* fix: steer activity summaries to current step, not session goal (#870)
Replayed the summary pipeline over five real threads (stg + prd) and
found the deployed prompt produces one vague goal-restating status per
thread: it steers the model toward the session goal, and the specific
summaries it does write usually land at 46-52 characters, where
sanitize_summary silently discards them (19 of 35 attempts).
Two prompt changes, validated by replaying the same threads:
- Describe the current step or latest finding instead of the overall
session goal, with concrete example phrasings.
- Target 40 characters and state the 45-character hard limit so the
model cuts words instead of overflowing.
Published summaries went from 14/35 attempts to 27/35, too-long
discards from 19 to 3, and the output narrates actual progress
("I found forge-std is vendored, not submodule", "I'm blocked on
tempo-obs metrics 502") instead of repeating "I'm checking X".
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* [codex] Add MCP tool host sandboxes (#841)
* feat: add MCP tool host sandboxes
* chore: bump chart version
* fix: address MCP tool-host review findings
- Always validate the requested method against the parsed client method
list; previously tools with zero public methods (methods == [help])
skipped validation and shipped unknown methods to the sandbox
- Keep the timed_out result when the sandbox-id lookup fails instead of
masking the timeout with a store error
- Serialize register_mcp_tool_host_principal under the same per-principal
lock as run_tool_host_call so concurrent registrations cannot interleave
with session setup, and evict idle lock entries after each call
- Cache the discovered tool catalog for 10s so bursts of MCP requests do
not redo directory scans and metadata parsing; drop the redundant
client.py re-read in the help path
- Extract tool_host_session_metadata and reuse tool_host_thread_key
instead of duplicating both constructions
- Derive SandboxBootMode inside ensure_session_sandbox from the thread
key and iron-control principal instead of threading it as a parameter
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: improve MCP tool errors and method discoverability
- tools/list and method=help now expose full method signatures parsed
from the tool's client.py (e.g. search_tweets(query, limit=10)) so
agents pass correct keyword arguments instead of guessing
- CALL_RUNNER binds keyword arguments against the target signature
before invoking and returns a short 'invalid arguments for
method(signature): ...' error instead of a TypeError traceback
- Failed tool calls reduce Python tracebacks to the final exception
message and append a hint to call method=help for usage
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* [codex] Add console MCP OAuth JWT auth for tool hosts (#842)
* feat: add console MCP OAuth JWT auth
* fix: revoke MCP OAuth tokens for inactive users
* fix: require approval for MCP OAuth clients
* fix: harden MCP OAuth issuer and loopback checks
* fix: address MCP OAuth review findings
- Fail closed in resolve_requested_resource: reject authorize requests
when no canonical MCP resource URL is configured instead of minting
tokens bound to caller-supplied audiences
- Validate JWT iat is not unreasonably in the future per RFC 0004
- Add missing apiRs.mcpPublicUrl / slackbotv2.mcpPublicUrl entries to
values.schema.json
- Share header_value between routes.rs and mcp.rs instead of duplicating
- Extract HashedTokenLookup concern for the OAuth code/refresh-token
models' SHA-256 hash-and-lookup pattern
- Cache static env configuration (signing secret, public URLs) in
OnceLock instead of re-reading per request
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore: bump chart version
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: avoid api attachment downloads from sandbox (#859)
* feat: add console threads view (#843)
* feat: add console threads view
* fix: stabilize console threads ci
* fix: center console thread content
* fix: make console threads read-only
* fix: scope console thread direct-selection to the owner (#854)
* fix: harden console markdown rendering and thread-title metadata (#855)
* fix: remove passwordless ?auth= console sign-in backdoor (#857)
* fix: transcript ordering, sidebar query scope, and session DB fallback (#856)
* fix: relax console Slack thread scope to team-when-present (#861)
* feat(slackbotv2): link first Slack message to Console session (#860)
* feat: console threads split view and thinking traces (#863)
* feat: always show the model on Console session links and thread header (#865)
* style: show model before harness and uppercase model names (#867)
* feat: console chats naming, empty state, and chat-not-found 404 (#866)
* chore: bump chart version to 0.1.86
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: hand off in-flight executions on shutdown (#872)
* feat: hand off in-flight executions on shutdown
api-rs runs as PID 1 in its container and installed no SIGTERM handler,
so Kubernetes pod terminations never reached the graceful shutdown
path: every rollout burned the full termination grace period and ended
in SIGKILL, killing stdout pumps mid-turn. The orphaned executions'
stdout-owner leases then lingered until their 45s TTL expired, and
nothing before the next deploy re-scanned to adopt them.
Changes:
- Handle SIGTERM (alongside Ctrl-C) as a shutdown signal.
- On shutdown, wait up to --shutdown-execution-drain-timeout-secs
(default 20, under the chart's 35s grace period) for this process's
in-flight executions to finish naturally — pumps keep running while
we wait — then release the remaining stdout-owner leases in one
statement and record a session.stdout_owner_released event per
execution. A peer control plane's adoption scan can then claim the
executions immediately instead of waiting out the lease TTL; turn
output produced after the release is recovered from the sandbox
backend's recorded output during adoption.
Verified end to end: the built server exits cleanly on SIGTERM and
logs the handoff, where main hangs until SIGKILL.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: address review findings on the shutdown handoff
- Fence new stdout-owner claims once the handoff begins (new
SessionRuntimeError::ShuttingDown, mapped to 503): an execution
accepted mid-drain would otherwise claim a lease that outlives the
process and strand the turn until the lease TTL expires.
- Clamp the drain deadline against Instant overflow, bound the flag to
0..=600 seconds, and put a 5s timeout on the handoff's count/release
queries so a hung database cannot push the release past SIGKILL
silently.
- Pin the release's owner scoping with a bystander lease in the sqlx
test, assert the drain-wait test's completer actually terminalized
the execution, and cover the claim fence.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: retry workflow host database connections (#874)
* fix: retry workflow host database connections
* fix: hardcode workflow host database retry settings
* feat: periodically re-scan for orphaned executions (#871)
* feat: periodically re-scan for orphaned executions
The orphaned-execution adoption scan ran once at process startup, and
its lease-deferral path retried only 'on next startup' — i.e. at the
next deploy. That misses the common rollout race: the new pod's startup
scan runs while the old pod is still alive and pumping (stdout-owner
lease active), then the old pod hits its termination grace period
mid-turn. The execution is orphaned seconds after the only scan that
could have rescued it, and the finished answer sits unread in the
sandbox pod logs until the next deploy. This exact sequence lost a
completed turn in stg (thread orphaned 25s after the startup scan).
Changes:
- Re-run the adoption scan on an interval (default 60s,
--session-execution-adoption-interval-secs / 0 disables). The
stdout-owner lease (45s TTL, renewed every 10s) already makes
adoption safe against live owners: scans defer while the lease is
active and claim it atomically once it expires.
- Skip queued executions younger than a 120s grace window instead of
failing them. Executions are queued only for the instant between
create_execution and the running transition, but a periodic scan (or
a startup scan racing another pod's live execute_session during
rollout overlap) could observe that window and kill a healthy row.
- Record the session.execution_adoption_deferred event and info log
only on the first deferral per execution, so a long turn owned by a
live peer does not accumulate one event per tick.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: address review findings on the periodic adoption scan
- Check the stdout-owner lease before touching the session row or the
sandbox backend: executions owned by this process are skipped
silently (no spurious adoption-deferred events on healthy turns, no
per-tick kube status calls), and live peers' executions defer without
any backend probes. The conditional claim remains the sole authority
on ownership.
- Restrict the queued-row grace window to periodic scans. A one-shot
scan (interval 0) has no later tick to revisit skipped rows, so it
fails queued orphans immediately as before — otherwise a young queued
orphan could wedge its thread until the next deploy.
- Keep deferral-dedup entries across transient per-execution scan
errors so kube/DB flaps do not re-emit the deferred event.
- Make the lease-expiry test deterministic (force expiry in SQL instead
of racing a 200ms TTL), cover the self-owned-execution skip and the
spawned periodic loop, and assert the backdate helper touches a row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: default the adoption re-scan interval to 15s
The interval bounds how long a turn handed off by a terminating pod
stays frozen before a peer adopts it: leases released at
SIGTERM+drain (~20s) wait for the next tick, so 60s meant a worst case
of ~80s of stalled thread during every rollout. Since the scan skips
lease-held executions before any session or sandbox reads, a
steady-state tick is a single SELECT over the handful of active
executions — scanning at 15s is negligible load and cuts the worst
case to ~35s. Crash recovery stays bounded by the 45s lease TTL either
way.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: grant console Slack thread visibility to Slack SSO identities (#875)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: restrict console Control and Data Sync sections to admins (#876)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: expose full Gmail message content (#877)
* fix: support path-backed Drive uploads (#878)
* feat: search OAuth Google Docs in company context (#881)
feat: search oauth google docs in company context
* feat: add company context lookup metrics (#880)
* fix: restore Slack DM context visibility (#882)
* fix(console): thread rendering — markdown tables, generated titles, thinking traces (#879)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Add interview prep tool (#886)
Co-authored-by: Centaur AI <ai@centaur.local>
* Revert interview prep tool from core (#888)
Revert "Add interview prep tool (#886)"
This reverts commit 35ce829bc39c19e332d05d825c978080b8077aad.
* feat(console): remove SSO approval requirement — users land on the console after login (#885)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(slackbotv2): rename console link to "Open chat in Console" (#889)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: gate sandbox API access by capability (#884)
* feat: gate sandbox API access by capability
* fix: preserve sandbox API ingress during rollout
* chore: bump chart version
* fix: harden sandbox API capability rollout
* fix: default session API capability to enabled
* fix: keep session API capability nullable
* fix: narrow sandbox API rollout compatibility
* fix: omit API label when disabled
* fix: satisfy sandbox API label clippy
* fix: remove sandbox capability stamp label
* feat(console): command/tool traces in transcripts with activity-summary previews (#890)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: capture Slack app message content and unfreeze busy-channel ETL sync (#887)
* fix: capture Slack app message content and unfreeze busy-channel ETL sync
Two coupled Slack ETL defects, both verified on a live deployment:
1) Content loss: SlackEtlClient._serialize_message allowlists keys and
dropped 'attachments'/'blocks' — bot integrations (e.g. the GitHub
app) post with empty top-level text and all content in legacy
attachments, so their messages were stored content-free (915/916 rows
in one live channel), invisible to the FTS index over text and to
company_context_documents. Pass both keys through into raw_payload
and synthesize text from attachment fallback (else
pretext/title/text) only when top-level text is empty.
2) Busy-channel deadlock: conversations.history anchors at 'oldest'
when only 'oldest' is passed (verified empirically — the page holds
the OLDEST slice, though the code labeled it order:desc). With a
backlog wider than one page the incremental tick re-read the same
oldest page forever, the watermark froze at the channel's density
fixed point (six live channels frozen for weeks), and the hourly
continuation re-enqueue clobbered the backfill worker's cursor
progress via enqueue_backfill_job's unconditional ON CONFLICT
overwrite (status->pending, attempts->0, stale cursor restored).
Fixes: (a) when the window page overflows, probe the live head with
a default newest-first fetch and take a monotonic max for the
checkpoint watermark (never regress); (b) refresh_pending=False for
periodic enqueuers so pending/running jobs are never rewritten —
continuations now genuinely drain and complete; (c) claim jobs
orphaned in 'running' after a stale interval, since the accidental
rescue-via-clobber is gone.
No schema changes; frozen checkpoints self-heal on the first tick after
deploy, and re-ingesting historical pages repairs raw_payload/text via
the existing upsert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* review fixes: probe resilience, stable continuation key, reclaim race, serializer polish
- Head probe is best-effort and gated on SLACK_BACKFILL_ENABLED: a probe
failure (rate limit, likeliest on exactly the busy channels that probe)
no longer discards the fetched window page, and the watermark is never
jumped past a backlog nothing will drain.
- The standing incremental continuation uses one stable job_key per
channel: keying on the window's oldest (which now advances with the
watermark) minted a new ~fully-overlapping job every tick.
- touch_backfill_job_started re-stamps last_started_at as the worker
reaches each claimed job, so a slow-but-alive run's tail jobs aren't
reclaimed as stale by a concurrent run.
- _sync_etl_channel_history never returns a watermark below the one it
was given (monotonic at the source, not just in the sync handler).
- Attachment fallback text goes through _resolve_mentions like the
primary path; blocks are persisted only for bot/empty-text messages
(human rich_text blocks just mirror text — jsonb bloat otherwise).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Akshaan Kakar <akshaan.crackers@gmail.com>
* fix: gate sandbox observability egress (#898)
* fix: gate sandbox observability egress
* chore: bump chart version
* fix: preserve sandbox api netpol name
* feat: add principal create and delete UI (#896)
* feat: allow deleting principals from console
* feat: add console principal creation
* chore: titlecase principal add button
* fix: handle newline after model override (#900)
* fix: complete Claude turns on assistant end_turn (#903)
fix: complete claude turns on assistant end_turn
Co-authored-by: Centaur AI <ai@centaur.local>
* Trigger image publish for harness-server changes (#904)
fix: publish images for harness server changes
Co-authored-by: Centaur AI <ai@centaur.local>
* Use nightly for Rust fmt and clippy instructions (#908)
* feat: interrupt process through slackbot stop (#911)
* fix(console): correct light table dividers (#914)
* fix: tighten slack stop command detection (#915)
* fix: include harness-server source in sandbox image cache key (#905)
Co-authored-by: Centaur AI <ai@centaur.local>
* feat(slackbotv2): gauge open session event stream connections (#916)
Amp-Thread-ID: https://ampcode.com/threads/T-019f3913-b24f-72d7-b4a1-2efb316d97d3
Co-authored-by: Amp <amp@ampcode.com>
* Revert Claude end-turn completion fallback (#918)
Revert "fix: complete claude turns on assistant end_turn"
This reverts commit 791bd244a0d6d692719970b64e9386c07f374108.
Co-authored-by: Centaur AI <ai@centaur.local>
* fix: release session event stream connections after terminal events (#920)
* fix: complete harness turns on terminal assistant stops (#921)
* fix: complete harness turns on terminal assistant stops
* fix: settle claude terminal stops and unblock turn completion
Three interacting fixes for claude/fable turns hanging as "thinking":
- Copy harness child stderr through the unlocked handle: the claude CLI
outlives each turn, so holding the StderrLock for the copy's lifetime
deadlocks any eprintln! at turn completion (e.g. OTLP export failures),
leaving the execution running after the answer already streamed.
- Replace the immediate terminal-stop completion with a settle window:
the native result still completes the turn when it arrives, the stop
completes it when the stream goes quiet without one, and stale trailing
output is drained before the next turn's input so a late result cannot
instantly terminate the following turn. Amp keeps a zero window (its
stream has no result event).
- Drop Task subagent sidechain events (parent_tool_use_id) so a
subagent's end_turn cannot complete or pollute the parent turn.
* chore: format otel rust code (#922)
* fix(discordbot): port live activity summaries; unstick answer-only streaming (#925)
4c17d8b8 (live activity summaries) moved reasoning/'Thinking' task
synthesis out of the shared renderer and adapted slackbotv2 and
linearbot, but not discordbot. Two regressions:
- Discord's narrator built its -# reasoning blurbs from the removed
Thinking tasks, so runs narrated nothing. Port: forward
session.activity_summary session events (previously dropped by
discordbot's SSE whitelist) and route renderer.status to a new
DiscordNarrator.status(), the Discord analog of Slack's assistant
status (dedupes consecutive repeats, drops the end-of-run clear).
- The synthetic starting item no longer primes the renderer's task
state, and the pre-stream grace check is event-driven, so an
answer-only turn's deltas sat buffered until the next event or stream
end. Fix: make the grace configurable (preStreamGraceMs, default
500ms unchanged) and pass 0 in discordbot, which streams answer text
into its own append-only messages and has no card to wait for.
Tests: new activity-summary blurb test; stale blurb expectations
updated to the server-side model; the failing-edit test now waits for
the first post so the tail must land as an edit (previously the deltas
could coalesce into the initial post and skip the path under test);
mock gains hasStream(threadKey) because streamCount counts live
streams across all threads and a lingering stream from the previous
test could satisfy a bare count wait.
These failures were invisible on main: the discordbot CI job is
path-filtered and 4c17d8b8 landed without a PR run.
Co-authored-by: Centaur AI <ai@centaur.local>
* fix(slackbotv2): preserve paragraph breaks in Slack plain-text extraction (#924)
* fix(slackbotv2): preserve paragraph breaks in Slack plain-text extraction
The @chat-adapter/slack SlackFormatConverter built message.text by
flattening the parsed mrkdwn AST with mdast-util-to-string, which joins
sibling block nodes with no separator. A message like
--claude --model=fable
examine <PR link> ...
reached extractMessageOverrides as '--claude --model=fableexamine ...',
so the harness was started with the nonexistent model 'fableexamine'.
The newline-boundary regex fix from #900 was correct but ran on input
whose paragraph breaks had already been destroyed upstream — and every
Slack message with a blank line had its paragraphs glued together in
the text forwarded to the agent.
Extend the @chat-adapter/slack patch to override extractPlainText with
a block-aware conversion: paragraphs join with a blank line, list items
and blockquote lines with a newline. Add pipeline regression tests that
run the real converter output through extractMessageOverrides.
* test: exercise patched paragraph-break handling end to end
The sticky-overrides emulation test now sends --model=fable followed by
a paragraph break — the exact production shape that selected the
nonexistent model fableexamine — covering the patched extractPlainText
through the full webhook pipeline.
---------
Co-authored-by: Centaur AI <ai@centaur.local>
* fix(slackbotv2): retry retryable handoff failures in-process instead of relying on Slack redelivery (#931)
* fix(console): serve stale proxy sync snapshots while one session rebuilds
Every iron-proxy polls /api/v1/proxy/sync on a 5s cadence. When a
principal's snapshot went stale (10min TTL) or its cache version was
bumped (e.g. broker credential refresh fans out to every referencing
principal), all of that principal's proxies stampeded into
PrincipalSyncConfigSnapshot.build_for and queued on the principal row
lock, each holding a Puma thread and DB connection for the full
effective_config rebuild. With one busy Slack channel principal shared
by 30+ sandboxes, every invalidation wave saturated all console
threads, starved the /up probe, and kubelet killed all replicas at
once (prd-centaur-na outage, 2026-07-07).
fetch_for is now stale-while-revalidate: exactly one caller rebuilds
under a non-blocking FOR UPDATE SKIP LOCKED row lock; concurrent
callers are served the stale current-version snapshot, or the newest
previous-version snapshot after a cache bump. Serving stale is safe:
iron-proxy treats the config hash as an ETag and re-applies on its
next poll. Only a cold start (no snapshot at any version) still
blocks.
Also fixes a rebuild-churn bug the new tests exposed: a rebuild that
produced a byte-identical payload no-op'd on save!, so updated_at
never advanced, the snapshot stayed permanently stale, and every poll
re-ran the expensive effective_config rebuild. build_within_lock now
touches the row to restart the TTL.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3cf4-8484-71a8-a459-5286174dc20b
Co-authored-by: Amp <amp@ampcode.com>
* fix(slackbotv2): retry retryable handoff failures in-process instead of relying on Slack redelivery
Slack only redelivers webhook events when the handler fails within ~3s,
so the old design (return 503, clear dedupe, wait for redelivery) silently
dropped prompts whenever a retryable session API failure surfaced after a
slow create/load — as seen during centaur-console instability.
Retryable handoff failures now schedule local retries (5s/30s/120s) while
Slack gets an immediate 200. The assistant status stays visible through
the retry window; exhaustion renders the visible error notice. If another
mention starts an execution before a retry fires, the retry conflates into
it (the message is already appended to the session), matching healthy-path
semantics for near-simultaneous mentions.
Replaces slackbotv2_webhook_retry_requests_total with
slackbotv2_handoff_retries_total{outcome}.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3cd5-b870-7386-8c36-e28a23ec5808
Co-authored-by: Amp <amp@ampcode.com>
---------
Co-authored-by: Amp <amp@ampcode.com>
* Revert "fix(slackbotv2): retry retryable handoff failures in-process instead of relying on Slack redelivery" (#934)
Revert "fix(slackbotv2): retry retryable handoff failures in-process instead …"
This reverts commit a503b4b069d0a3aad2863fafb24f96cf022a56b8.
* fix(slackbotv2): retry retryable handoff failures in-process instead of relying on Slack redelivery (reland) (#935)
fix(slackbotv2): retry retryable handoff failures in-process instead of relying on Slack redelivery
Slack only redelivers webhook events when the handler fails within ~3s,
so the old design (return 503, clear dedupe, wait for redelivery) silently
dropped prompts whenever a retryable session API failure surfaced after a
slow create/load — as seen during centaur-console instability.
Retryable handoff failures now schedule local retries (5s/30s/120s) while
Slack gets an immediate 200. The assistant status stays visible through
the retry window; exhaustion renders the visible error notice. If another
mention starts an execution before a retry fires, the retry conflates into
it (the message is already appended to the session), matching healthy-path
semantics for near-simultaneous mentions.
Replaces slackbotv2_webhook_retry_requests_total with
slackbotv2_handoff_retries_total{outcome}.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3cd5-b870-7386-8c36-e28a23ec5808
Co-authored-by: Amp <amp@ampcode.com>
* Add sandbox commit-msg hook (#909)
* Add sandbox commit message hook
* fix: enforce conventional commit messages
* feat: add console workflows dashboard (#912)
* feat(console): admin self-descope to operator permissions (#936)
feat(console): let admins temporarily descope to operator permissions
Adds a per-session "View as operator" toggle for admins:
- session[:descoped] flag with acting_admin?/descoped? helpers; require_admin
and the default landing path now go through acting_admin?
- Console::DescopesController (POST pauses admin perms, DELETE restores);
descope route is a singular resource under /console
- Admin-only nav (Control, Data Sync, Workflows, Users tab) hides while
descoped; account menu gains a View as operator item
- Persistent high-contrast amber banner while descoped with a Restore admin
button
- Light mode only: amber notice boxes (thread-DB unavailable, managed secret)
get the same solid amber treatment via a shared .console-amber-note class
Descope is self-healing: the flag is dropped automatically if the user is no
longer an admin, so it can never outlive the privileges it pauses.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3d7c-9cab-726b-9753-92eb40d7fe61
Co-authored-by: Amp <amp@ampcode.com>
* fix(console): serve stale proxy sync snapshots while one session rebuilds (#930)
Every iron-proxy polls /api/v1/proxy/sync on a 5s cadence. When a
principal's snapshot went stale (10min TTL) or its cache version was
bumped (e.g. broker credential refresh fans out to every referencing
principal), all of that principal's proxies stampeded into
PrincipalSyncConfigSnapshot.build_for and queued on the principal row
lock, each holding a Puma thread and DB connection for the full
effective_config rebuild. With one busy Slack channel principal shared
by 30+ sandboxes, every invalidation wave saturated all console
threads, starved the /up probe, and kubelet killed all replicas at
once (prd-centaur-na outage, 2026-07-07).
fetch_for is now stale-while-revalidate: exactly one caller rebuilds
under a non-blocking FOR UPDATE SKIP LOCKED row lock; concurrent
callers are served the stale current-version snapshot, or the newest
previous-version snapshot after a cache bump. Serving stale is safe:
iron-proxy treats the config hash as an ETag and re-applies on its
next poll. Only a cold start (no snapshot at any version) still
blocks.
Also fixes a rebuild-churn bug the new tests exposed: a rebuild that
produced a byte-identical payload no-op'd on save!, so updated_at
never advanced, the snapshot stayed permanently stale, and every poll
re-ran the expensive effective_config rebuild. build_within_lock now
touches the row to restart the TTL.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3cf4-8484-71a8-a459-5286174dc20b
Co-authored-by: Amp <amp@ampcode.com>
* feat(console): add user-facing Integrations page with OAuth start links (#937)
Adds a /console/integrations page listing every enabled OauthApp as a card
with the provider's brand logo (Google, Slack, GitHub; falls back to a text
badge for unknown providers) and a Connect button pointing at the public
consent start link /oauth/<slug>/start.
Unlike the rest of the console Control section this page is not admin-gated:
the whole point of the well-known consent links is that regular team members
click them, so the Integrations nav item is visible to every signed-in user.
Only non-sensitive fields are rendered (slug, provider, description).
Also seeds dev/test databases with sample google/slack/github OAuth apps so
the page has content out of the box.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3d8c-1fbe-77cb-aa0e-9e405ac50b52
Co-authored-by: Amp <amp@ampcode.com>
* feat(console): redirect OAuth callback to Integrations and show connected state (#938)
* feat(console): redirect the OAuth callback to the Integrations page on success
A successful consent now lands the user back on /console/integrations with a
flash notice ("<slug> connected as <email>.") instead of the standalone
result page, so they end up where they started with the full list of
integrations in front of them. Denied and error outcomes keep the standalone
result page with its retry link, since those can occur outside a console
session.
* feat(console): show connected state on Integrations cards
An integration whose BrokerCredential carries the signed-in user's email
(provider_email, the only link the unauthenticated consent flow records back
to a console user) now shows a Connected badge and a secondary Reconnect
button instead of Connect. Dead credentials show "Needs reconnecting" so a
broken connection is not presented as healthy.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3d8c-1fbe-77cb-aa0e-9e405ac50b52
Co-authored-by: Amp <amp@ampcode.com>
---------
Co-authored-by: Amp <amp@ampcode.com>
* fix(console): recolor first divide-y divider in light mode (#940)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(console): reflect fresh connections on Integrations after the callback redirect (#941)
* fix(console): link minted credentials to the consenting console user
After the callback redirected back to Integrations, the card often stayed on
"Connect": the page matched credentials only by provider_email, so consenting
with a provider account whose email differs from the console login (e.g.
dev@iron.local logging into a personal Google account) never flipped the state.
The callback now records created_by from the browser's console session when
one exists (never overwritten, so the first linked user keeps the credential),
and the Integrations page matches created_by first with provider_email as the
fallback for consents made without a session.
* test(console): cover the Slack no-email consent end to end
Slack's OAuth v2 token response carries no email in authed_user (enrichment
fills provider_email in later), which is the actual case the created_by link
exists for: sign in, consent to Slack, land on Integrations, see Reconnect.
Amp-Thread-ID: https://ampcode.com/threads/T-019f3d8c-1fbe-77cb-aa0e-9e405ac50b52
Co-authored-by: Amp <amp@ampcode.com>
---------
Co-authored-by: Amp <amp@ampcode.com>
* feat: Add Meta model support (#942)
* fix: label company context lookup metrics (#946)
* feat: add public repo cache access (#943)
* fix: migrate sandbox repo-cache setting
* feat: implement public repo cache access
* feat: expose public overlay capabilities
* fix: satisfy repo cache access ci checks
* fix(iron-proxy): deny cluster upstream cidrs (#949)
* fix(iron-proxy): deny cluster upstream cidrs
* fix(iron-proxy): render managed upstream deny config
* Revert "fix(iron-proxy): render managed upstream deny config"
This reverts commit 94dfc03e8b75243b1d9af2acbaa905f73092671e.
---------
Co-authored-by: Centaur AI <ai@centaur.local>
* fix(harness): make codex attach Responses item ids for the Meta (--meta) provider (#951)
fix(harness): make codex attach Responses item ids for the Meta provider
Long --meta turns fail with `input[N] missing required field id`:
codex serializes Responses input items with their ids stripped and only
re-attaches them (attach_item_ids) for providers detected as Azure.
Meta's Responses endpoint requires ids on replayed history items, so any
turn long enough to round-trip prior reasoning/tool items 400s.
Naming the provider "azure" opts it into codex's Azure workaround
(store: true + attach_item_ids). Durable fix is codex >= 0.142.0 with
the item_ids feature.
Co-authored-by: Centaur AI <ai@centaur.local>
* ci: rebuild images for harness config changes (#952)
* fix(iron-proxy): bump base image to 0.46.0 (#954)
Co-authored-by: Centaur AI <ai@centaur.local>
* fix(tools): migrate allium to renamed MCP tools and surface tool errors (#955)
Allium renamed its MCP tool surface: explorer_run_sql/explorer_search_schemas/
explorer_fetch_schema no longer exist. The live server now exposes
run_sql_query (async, returns run_id) + get_query_run_results, and
search_schemas handles both query search and per-id schema fetch.
- run_sql: call run_sql_query, then poll get_query_run_results until the
run completes; raise on failed runs and timeouts
- search_schemas/fetch_schema: use the new search_schemas tool (id= fetches
a single entry with markdown content)
- _mcp_call: raise RuntimeError on tool-level errors (isError + text
content). Previously 'Unknown tool' and 'Not authenticated' were parsed
as empty result lists, so every failure printed 'No results' / 'N/A' and
'allium health' reported ok:true with the error buried in details
- describe: render markdown schema content when structured columns are absent
Co-authored-by: Centaur AI <ai@centaur.local>
* feat: GitHub client (#956)
* feat(githubbot): GitHub ingress bot (conversational + review-on-request)
Add services/githubbot, a standalone bot modeled on linearbot and built on
the official @chat-adapter/github adapter, authenticating as a GitHub teammate
via PAT.
Behavior (v1):
- @-mention in a PR/issue comment or PR review comment -> answer in that thread.
PR conversation is one session thread; each code-comment thread is its own,
with the anchored file/line/diff hunk injected into the turn.
- Non-mention follow-ups in an active thread are appended as context.
- Requesting the bot's review (review_requested) -> a review turn on a dedicated
isolated, per-PR thread (re-review aware); the agent posts inline comments and
a summary via gh. Review methodology ships as a standalone default and is fully
replaceable via GITHUBBOT_REVIEW_PROMPT[_FILE].
Wiring: pnpm workspace, gated CI job, Helm Deployment/Service + NetworkPolicy +
ingress route, and bootstrap secrets (GITHUBBOT_TOKEN kept distinct from the
sandbox tool token). Typecheck clean; 28 unit tests pass.
feat(githubbot): v2 PR self-management (fix CI, address review, merge)
Add a PR manager that drives PRs the bot owns (authored by it, or carrying the
managed label) toward merge by reacting to PR/review/CI lifecycle webhooks.
- Fix CI: fires only once *all* checks for a head SHA are settled and red, then
runs a bounded fix turn (agent diagnoses + pushes via gh); resets on green,
backs off human-authored commits, and escalates to a tagged human after the
attempt cap.
- Address review: one holistic turn per submitted review (changes coherently,
replies per thread, resolves, re-requests review).
- Merge: deterministic — when GitHub reports mergeable_state clean the bot merges
directly (branch protection is the source of truth); dirty -> conflict turn,
behind -> branch update. On by default for owned PRs, with a global kill-switch,
a per-PR hold label, and draft respect.
Agentic flows run on a dedicated github-manage:{owner}/{repo}:{n} thread. Scope
is same-repo PRs on repos we control. Config plumbed through options/env and the
Helm chart. Pure decision logic (CI evaluation, ownership, merge gating) is unit
tested; typecheck clean, 41 tests pass.
feat(githubbot): route owned-PR conversation mentions to the management session
When the bot owns a PR, an @-mention in its conversation (or a review-comment
thread) now runs in that PR's management session (github-manage:…) so it answers
with the context of the CI fixes and review work the bot has been doing — while
the rendered reply still posts back to the comment thread.
- runSessionTurn gains sessionThreadKey, decoupling the session/sandbox key from
the posting thread (and reaction/dedup target).
- Ownership is resolved with a cached octokit lookup (isPrOwned) and remembered on
the conversation thread (managementSessionKey) so follow-ups skip the lookup and
append into the same session.
Typecheck clean, 41 tests pass.
feat(githubbot): assignment-based ownership + issue work on assignment
Make PR ownership purely an assignment mechanism: the bot manages a PR
iff it's assigned to the bot account (dropping author==bot and the
managed label). Being assigned triggers an immediate takeover that
forces past the human-commit CI back-off.
Add issue work on assignment: assigning an issue to the bot runs an
autonomous work turn on an isolated session that reads the issue,
implements a fix, and opens a self-assigned PR. The issue-work
methodology is a bundled default fully replaceable via
GITHUBBOT_ISSUE_PROMPT / _FILE, mirroring the review prompt override.
fix(githubbot): instant reaction acks for review/issue turns + hoist the working react
The conversational 👀 only fired inside the turn, after a state write,
subscribe, and a live ownership lookup — so it lagged. Fire it up front
in the webhook handler instead, before that setup work.
Review requests and issue assignments have no triggering comment to
react to, so they got no feedback at all. Ack on the PR/issue itself
(👀 → 🚀/😕) via a shared best-effort helper.
feat(githubbot): chart support for review/issue prompt overrides via mounted files
Add githubbot.reviewPrompt / issuePrompt values: when set, the chart
writes each into a ConfigMap, mounts it as a file, and points the bot at
it via GITHUBBOT_REVIEW_PROMPT_FILE / _ISSUE_PROMPT_FILE — the file path
the server already supports. A checksum annotation rolls the pods when a
prompt changes. Unset (default) keeps the bundled defaults, with no
ConfigMap or volume rendered. Lets a deployment supply its own review or
issue-work methodology without a large inline env var.
fix: handle githubbot PR lifecycle edge cases
fix(githubbot): close concurrency, durability, authz, and parity gaps from review
Hardens the new GitHub bot against the issues a multi-agent review surfaced,
concentrated on the autonomous lifecycle surface.
- Concurrency: switch the chat handler from the deprecated onLockConflict
"force" to concurrency "drop" so a redelivered or near-simultaneous comment
can't slip past the read-modify-write dedup and double-reply, and serialize
turns targeting the same session so a conversation mention and a CI-fix turn
can't interleave git/push in one sandbox.
- Durability: drain in-flight turns on SIGTERM (bounded) so a deploy doesn't
silently drop running work that its own claim would then suppress, and only
hold the merge claim once the merge actually succeeds so a transient failure
retries instead of stranding a clean PR.
- Authorization: gate the comment-mention path on author_association (safe
default, "*" to open) so an untrusted commenter can't steer the write-capable
agent; lifecycle paths stay gated by GitHub permissions.
- Parity: act on review requests aimed at a team the bot belongs to, and on an
@-mention written into a freshly-opened issue/PR body.
- Perf: stop re-serializing every attachment's payload once per attachment.
- Config: deployments can prepend their own guidance to management turns.
Adds tests for the CI-fix counter/escalation, merge-claim release, the author
gate, the serialization queue, team requests, and body mentions, plus chart and
README wiring for the new knobs.
* chore: bump chart
---------
Co-authored-by: Will Drach <drach@splits.org>
* fix(allium): update Hyperliquid queries to current table schemas (#957)
fix(allium): update to renamed MCP tools and current Hyperliquid schemas
The Allium MCP server renamed its tools, breaking the allium CLI:
- explorer_run_sql -> run_sql_query (now async: submit returns a run_id
that must be polled via get_query_run_results)
- explorer_search_schemas -> search_schemas
- explorer_fetch_schema -> search_schemas with id argument
Also surface MCP tool errors (isError) instead of silently returning
'No results', and fix stale Hyperliquid column references:
- dex.trades: size -> amount, buyer/seller -> buyer_address/seller_address,
usd_amount for notional, no side column (use buyer_crossed/seller_crossed)
- metrics.overview: day -> activity_date
- raw.orders: price -> limit_price, "user" -> "USER"
- raw.builder_fills join: builder_labels.address -> builder_code, quoted
"USER", cast builder_fee to float
Co-authored-by: Centaur AI <ai@centaur.local>
* fix(console): hide admin redirect alert (#939)
* fix: limit default infra secrets to model providers (#960)
* fix: limit default infra secrets to providers
* fix: keep static infra fragment credential-free
* feat(console): grant oauth credentials and user-mcp role to console-user MCP principals (#932)
* feat(console): grant oauth credentials and user-mcp role to console-user MCP principals
Console-user principals minted by the MCP OAuth flow previously received
no roles or credentials, making per-user MCP effectively useless.
- Generalize PrincipalCredentialReconciliation to all OAuth providers and
match console-user principals to their verified user emails, so a user's
own OAuth credentials are auto-granted to their MCP principal.
- Seed a shared user-mcp role onto newly minted console-user principals.
Admins attach tool secrets to this role to define the default toolset
every MCP user gets. Seeded on create only, so removals stick (mirrors
SessionRegistrar's infra-role semantics for session principals).
Amp-Thread-ID: https://ampcode.com/threads/T-019f3cb0-b3e7-772e-b463-6f2882f4d362
Co-authored-by: Amp <amp@ampcode.com>
* fix(console): tighten console-user matching and make role seeding atomic
Review follow-ups:
- Console-user principals now match credentials only through their User
record (primary email + verified identity emails). Mutable principal
labels (email, google_email, slack_email) and provider-subject labels
no longer participate, and provider identity labels are never synced
onto console-user principals. Closes the stale/tampered-label path and
the recycled-email edge.
- Principal creation and user-mcp role seeding now share a transaction,
so a transient seeding failure can no longer commit a principal that
create-only semantics would leave unseeded forever. The RecordNotUnique
retry moved outside the transaction (a unique violation aborts the
enclosing Postgres transaction).
Amp-Thread-ID: https://ampcode.com/threads/T-019f3cb0-b3e7-772e-b463-6f2882f4d362
Co-authored-by: Amp <amp@ampcode.com>
* docs(console): note when to optimize per-principal credential reconciliation
Amp-Thread-ID: https://ampcode.com/threads/T-019f3cb0-b3e7-772e-b463-6f2882f4d362
Co-authored-by: Amp <amp@ampcode.com>
---------
Co-authored-by: Amp <amp@ampcode.com>
* fix(iron-proxy): restore GITHUB_TOKEN and SLACK_BOT_TOKEN infra secrets (#967)
#960 removed the non-model secret transforms from the static infra
fragment, but the sandbox placeholder env is derived from that same
fragment, so new sandboxes stopped receiving GITHUB_TOKEN=GITHUB_TOKEN
and SLACK_BOT_TOKEN placeholders. gh/git decide they are unauthenticated
locally and never send the Authorization header iron-proxy would
rewrite, breaking gh, git-over-HTTPS, and the slack tool in every
sandbox created after the rollout.
Restore the replace-mode GITHUB_TOKEN (github.com, api.github.com) and
SLACK_BOT_TOKEN (*.slack.com) entries. The other #960 removals
(XAI_API_KEY, GEMINI_API_KEY, AMP_API_KEY) stay removed.
* fix: inject sandbox token placeholders outside fragments (#968)
* feat(console): add Granola OAuth provider (#964)
* feat(console): add Granola OAuth provider
Targets Granola's MCP OAuth server for the console consent flow, with identity extracted from the OIDC id_token and refresh-token support requested through offline_access.
Granola does not expose a classic static third-party app dashboard; operators mint the OAuth client once via dynamic client registration at https://mcp-auth.granola.ai/oauth2/register and store that client_id/client_secret on the OauthApp.
* feat(console): add Granola provider logo to Integrations page
Embeds the Granola mark (single currentColor path, 32x32 viewBox)
in oauth_provider_logo and makes the SVG viewBox per-provider so
non-24x24 marks render correctly.
* feat(console): add Attio OAuth provider (#966)
* feat(console): add Attio OAuth provider
Add an Attio provider strategy for the console's generic OAuth consent flow. Attio scopes are configured in the Attio developer dashboard, so the provider has no identity scopes and treats token response scopes as optional.
Attio returns long-lived workspace-scoped access tokens without refresh_token or expires_in, so the provider is non-refreshable and uses the existing default expiry handling for callback persistence. Workspace identity is enriched asynchronously from /v2/self and may collide intentionally by (app, workspace_id).
* feat(console): default Attio seed scopes to user_management read + read-write for core resources
* feat(console): add Attio provider logo to Integrations page
Embeds the official Attio mark (two currentColor paths, 31x26 viewBox)
in oauth_provider_logo and makes the SVG viewBox per-provider so
non-24x24 marks render correctly.
* feat(console): add Linear OAuth provider (#965)
Linear token responses do not include account identity, so the callback mints a deterministic pending identity and a follow-up enrichment job queries the Linear GraphQL viewer to replace it.
Linear refresh tokens rotate on use; the provider is marked refreshable and refresh requests preserve the granted scopes.
* feat(console): workflows dashboard cleanup — grouping, filters, pagination, force-start, debugging (#958)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: add Slack file proxy API (#961)
* feat: add Slack file proxy API
* feat: support Slack upload metadata
* fix: harden Slack file proxy responses
* feat: add scoped Slack search proxy
* refactor: rename Slack proxy module
* fix: drop Slack search and harden file proxy
Remove the Slack search endpoints entirely while keeping the Slack file upload and download proxy.
Harden the remaining file proxy path with stricter download validation, shared timeout-aware Slack client setup, content type validation, case-insensitive bearer auth, safer response headers, and shared JWT/env configuration.
* docs: add GitHub, Granola, Linear, and Attio to the OAuth Apps page (#969)
* docs: document console OAuth integrations
* docs: replace end-to-end flow and provider tables with short Console setup how-to
* docs: fold new OAuth providers into existing OAuth Apps page, drop duplicate integrations page
* docs: simplify OAuth Apps page to a short UI-only guide
* docs: add Granola dynamic client registration to provider-specific setup
* fix: read workflow output watermark (#972)
* feat: generate API server JWTs for sandbox proxy sync (#971)
* feat: generate API server JWTs for sandbox proxy sync
* fix: reject whitespace JWT signing secrets and jitter token rotation windows
Restore the blank? guard the HS256 extraction narrowed to empty?, so a whitespace-only CENTAUR_JWT_SIGNING_SECRET fails closed again. Offset each principal's 15-minute rotation window by a deterministic per-oid jitter so snapshot rebuilds and config_hash flips spread across the window instead of stampeding at every global boundary.
* fix: gate API JWT credentials on sandbox capability
* fix(slackbotv2): detect stop commands in Chat-SDK-normalized mention text (#970)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: expose slack client jwt on healthz (#973)
* fix: wire centaur api url into console chart (#974)
* chore: update iron-proxy to 0.47.0 (#977)
* fix: revert iron-proxy to 0.46.0 (#978)
* fix: batch company context projection windows
* fix: batch company context projection windows
* fix: bump centaur chart version
* chore: update iron-proxy to v0.48.0 (#979)
* fix(slack): resolve user IDs and @usernames to DM channels in read paths (#981)
_resolve_channel only matched channel IDs and bot channel names, so
get_channel_history, get_thread_replies, and other read methods could
not read the bot's DMs even though send_message/send_dm could open
them. Resolve U.../<@U...> and @username references to the one-on-one
DM conversation via conversations.open, reusing _open_dm_channel.
* fix: wire slack bot token into api-rs chart (#982)
* feat: add scoped slack search proxy (#983)
* feat: add scoped slack search proxy
* fix: keep slack search claims channel scoped
* fix: strip all slack search channel filters
* fix: resolve slack search scopes
* fix: update websocket driver advisory
* fix: route slack proxy searches to requested channels
* fix: simplify slack proxy fallback flow
* feat: add slack proxy search command
* fix: scope slack proxy search to current channel
* Revert "feat: add scoped slack search proxy (#983)" (#985)
* Revert "feat: add scoped slack search proxy (#983)"
This reverts commit e0af368859343016f002a16e53191352a6f11a11.
* restore websocket-driver fix
* feat: index private Slack channels behind flag (#986)
* feat: index private Slack channels behind flag
* fix: keep Slack user directory readonly visibility
* test: derive private Slack RLS fixture
* chore: bump chart version
* granola: add MCP backend with REST fallback (#994)
* fix(slack): resolve user IDs and @usernames to DM channels in read paths
_resolve_channel only matched channel IDs and bot channel names, so
get_channel_history, get_thread_replies, and other read methods could
not read the bot's DMs even though send_message/send_dm could open
them. Resolve U.../<@U...> and @username references to the one-on-one
DM conversation via conversations.open, reusing _open_dm_channel.
* granola: add MCP backend with REST fallback
The Centaur console OAuth flow mints user-scoped Granola MCP tokens
(mcp.granola.ai), but the tool only spoke the Enterprise REST API
(public-api.granola.ai, workspace API key). Add a GranolaMcpClient
speaking Streamable HTTP JSON-RPC with the same method surface,
normalized to REST note shapes.
_client() tries MCP first (cheap get_account_info probe) and falls back
to REST; GRANOLA_BACKEND=mcp|rest overrides. The proxy injects the
OAuth Bearer for mcp.granola.ai from the console grant, so the tool
never handles the token; GRANOLA_MCP_TOKEN supports local dev.
New CLI commands: whoami, query (natural-language Q&A with citations),
folders.
* feat: proxy Slack history and files (#1001)
* fix: proxy sandbox api traffic (#1002)
* fix: proxy sandbox api traffic
* test: cover iron-proxy api capability labels
* chore: change codex default model to gpt-5.6-sol (#1005)
* Add Granola sync workflow (#987)
feat: add granola sync workflow
* feat: add Attio sync workflow
Adds scheduled Attio meeting/transcript ingest and projects synced meetings into company context documents.
* fix: sync slack labels for mcp principals
* feat: add MPP fallback discovery (#1007)
* feat: add MPP service discovery (#1006)
* fix: label MCP principals from Slack SSO (#1010)
* fix: sync slack labels for mcp principals
* fix: label MCP principals from Slack SSO
* fix: default slack file and thread tools to api routes (#1009)
* fix: default slack file and thread tools to api routes
* test: assert slack etl uses direct slack routes
* fix: avoid stale api-rs build artifacts (#1012)
Co-authored-by: Centaur AI <ai@centaur.local>
* fix: gate readonly DM access by Slack identity (#1011)
* feat: make the console an installable PWA (#980)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(proxy): allowlist Datadog auth headers for the agent Datadog tool (#944)
* fix: wire console slack bot token (#1013)
* feat: add Slack channel claims to principals
* refactor: rename Slack channel claims
* fix: wire console slack bot token
* fix: backfill slack channel permissions
* chore: fix slack permission lint
* fix: address slack permission review
* refactor: simplify slack permission replacement
* refactor: simplify slack permission cache updates
* fix: harden slack permission inputs
* refactor: use form params for slack permissions
* refactor: simplify slack permission inputs
* refactor: move slack channel option formatting to helper
* fix: seed slack permissions during session registration (#1017)
* fix: grant slack dm permissions for user principals
* fix: restrict slack dm permissions to user principals
* fix: seed slack permissions from session registration
* test: trim slack permission negative coverage
* fix: harden slack permission upserts
* fix: match slack dm ids case-insensitively
* chore: agents.md cleanup (#1021)
* fix: grace executions awaiting sandbox assignment (#1020)
* fix: upsert slack dm permissions for existing principals (#1022)
* feat: proxy slack channel listing (#1023)
* feat: proxy slack channel listing
* fix: harden slack channel enrichment
* fix(sandbox): bump Codex for gpt-5.6-sol (#1016)
fix(sandbox): support gpt-5.6-sol
Co-authored-by: ecejas <15933097+ecejas@users.noreply.github.com>
* chore: move the PWA install CTA into the account menu (#1026)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(sandbox): avoid Centaur AI co-author attribution as it is non-existent account (#1015)
* feat: support 5.6 max Codex reasoning effort (#1027)
* fix: proxy Slack file listing (#1025)
* fix: proxy Slack file listing
* feat: add direct Slack file search command
* fix: correct Slack files list pagination
* fix: require channel for Slack file proxy
* fix: require channel for Slack file search
* fix: update Slack file search callers
* docs: clarify model and harness switching (#1028)
* feat: expose Slack file and member proxies (#1029)
* feat: expose Slack file info proxy
* refactor: share Slack file info helpers
* fix: authorize Slack file info before config
* feat: proxy Slack channel members
* fix: make Attio sync resilient to detail failures (#1031)
* fix: use host Slack team for principals (#1032)
* fix: use host Slack team for principals
* fix: stop scoping Slack channel principals by requester team
The prior approach threaded the host Slack team through a request
context so channel principals would use it. That is unnecessary: a
Slack channel id is globally unique, so channel principals never need
a team in scope. Scoping them by the message-derived team (introduced
in #882) let a Slack Connect requester's external workspace fork a
separate principal from the host channel's.
Derive channel principals without any team scope, keeping the DM
metadata-team folding from #882 intact, and revert the request-context
plumbing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com>
Co-authored-by: Matthew Slipper <me@matthewslipper.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: manage sandbox defaults in console (#1036)
* feat: configure default sandbox capabilities
* feat: manage sandbox defaults in console
* feat: manage sandbox defaults in console
* refactor: simplify sandbox default application
* refactor: rely on sandbox setting validation
* refactor: remove redundant sandbox default constants
* fix: preserve explicit sandbox repo-cache labels
* refactor: store sandbox repo cache as enum
* refactor: require repo cache label for principals
* fix: prefer principal repo cache setting over label
* fix: reject sandbox repo cache label input
* fix: validate sandbox repo cache label consistency
* refactor: always project sandbox repo cache label
* fix: gate otlp egress on observability (#1037)
* fix: gate otlp egress on observability
* chore: bump helm chart version
* fix: always label api-rs for observability
* fix(slackbotv2): resolve trigger bot identities (#1043)
* fix(slackbotv2): resolve trigger bot identities
* fix(slackbotv2): match webhook bots by app identity
* refactor(slackbotv2): allowlist bot members only
* feat(console): chat composer: start and continue chats from the console (#984)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(console): preserve optimistic chat messages (#1047)
* docs: fix company context latest-date guidance (#1049)
* feat: batch company context projections (#1055)
* fix(slackbotv2): support scoped trigger bot IDs (#1051)
fix(slackbotv2): support scoped trigger bot ids
Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com>
* fix: include API controllers in console request logs (#1056)
* fix: remove company context size metric (#1057)
* fix(console): keep composer model picker menu inside the viewport (#1053)
* fix(console): preserve requester attribution for PRs (#1054)
* feat: add Airtable record write operations (#1058)
* fix: allow hosted MCP OAuth redirects (#1059)
* fix: allow hosted MCP OAuth redirects
* test: update MCP redirect rejection case
* fix: fall back to direct Slack threads (#1061)
* feat: sync Granola via user OAuth (#1060)
* feat: sync Granola via user OAuth
* fix: satisfy Granola sync CI checks
* feat: add Airtable identity health check (#1062)
* feat: expose sandbox permission query (#1039)
* feat: expose sandbox permission query
* fix: expose console URL to sandboxes
* refactor: clarify sandbox console URL wiring
* fix: require explicit API server proxy hosts
* chore: bump chart version to 0.1.99
* fix: require configured sandbox entitlement host
* feat: add centaur console permissions tool (#1065)
* feat: project Granola notes into context (#1063)
* feat: project Granola notes into context
* test: provision Granola RLS source table
* test: provision Granola RLS identity helpers
* fix(slackbot): trigger on rich message mentions (#1048)
* feat: harden console public login (#1072)
* feat: harden console public login
* refactor: simplify console SSO domain parsing
* chore: bump chart version
* fix: require console login for oauth credential minting (#1074)
* fix: harden console public access controls (#1076)
* feat: ingest private Slack channels from OAuth (#1079)
* feat: ingest private Slack channels from OAuth
* fix: remove private channel membership expiry
* refactor: rename private Slack tables
* feat: add console chat privacy controls (#1078)
* feat(console): make the operator console responsive on mobile (#1084)
* fix(console): scope while-running transcript refresh to the active panel (#1083)
* feat: expose sandbox oauth connection discovery (#1086)
* feat(slackbotv2): show Codex effort and speed (#1085)
Closes paradigmxyz/centaur#1068
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
* feat(slackbotv2): default model and reasoning effort per Slack channel (#1075)
* feat(workflows): plumb model and reasoning effort through ctx.agent_turn (#1073)
* docs: clarify cron weekday numbering (#1089)
Closes paradigmxyz/centaur#1040
Co-authored-by: Anđelo Kandić <andelo.kandic@gmail.com>
* fix: support non-rotating Slack OAuth tokens (#1088)
* fix: support non-rotating Slack OAuth tokens
* fix: preserve Slack OAuth token expiry semantics
* fix: preserve Granola projection document IDs (#1091)
fix: preserve granola projection document ids
* fix: label Slack DM principals with email (#1092)
* fix: label Slack principal kinds (#1093)
* fix: log console JWT rejection reasons (#1090)
* fix: preserve console return path on login (#1094)
* fix: preserve console return path on login
* fix: avoid verb confusion in login return path
* fix(slackbotv2): hide Codex effort and speed (#1095)
* fix(console): use GitHub login for PR attribution (#1087)
* fix: improve console dropdown labels (#1097)
* fix: preserve postgres proxy credentials on resume (#1099)
* feat: Make the chat agent platform-aware (Slack/Discord/Linear/Github) (#704)
* fix(linearbot): don't start an assignment turn when the bot assigns itself (#945)
* fix(linearbot): Prevent Linearbot from marking issues as "done" when it just put a PR up (#959)
Co-authored-by: Gerard <289036782+splits-gerard@users.noreply.github.com>
* fix(harness-server): downscale oversized image attachments before the model (#1077)
* fix: omit Slack client secret for PKCE login (#1100)
* fix: use confidential Slack OIDC login (#1101)
* fix(console): separate chat discovery from access (#1102)
Keep the sidebar and default chat selection scoped to chats owned by
the signed-in user.
Allow users to continue public and explicitly shared chats when the
existing access policy permits them.
* feat: add LLM message override strategy (#1096)
* feat: add LLM message override strategy
* fix: log LLM message override failures
* fix: classify overrides from Slack prompt text
* Revert "fix: classify overrides from Slack prompt text"
This reverts commit 0f553e6b2a500978732056077539803f6836ca72.
* chore: bump Helm chart version
* fix: avoid logging override response bodies
* fix: map OpenAI key for Slackbot overrides
* fix: make Slackbot OpenAI key optional
* fix: align LLM sonnet model alias
* fix: support explicit sonnet 5 override
* fix: keep Slack override retries idempotent
* fix: log successful override strategy responses
* fix: reduce slack override strategy log noise (#1104)
* fix: reduce slack override strategy log noise
* refactor: accept full logger for slack override strategy
* feat: render attached images in console chat (#1105)
* fix(console): clean up chat detail rows (#1108)
* feat: add workflow-scoped principals (#1107)
* feat: add workflow-scoped principals
* feat: add workflow host sandbox helm value
* chore: bump centaur chart
* fix: default workflow host sandbox chart value off
* f…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When just a PR is up, Linear will typically handle moving the PR from "in review" to "done" when the PR is reviewed and merged. The Centaur bot was marking things as done as soon as it got put in review, which means that it often got lost as a "completed" task when the PR wasn't actually merged. This should fix that by not moving past review unless the bot explicitly does so itself.