Skip to main content
Released September 28, 2026 · Stable · View on GitHub 0.9.1 is a patch release on top of 0.9.0, published the same day with 20 merged PRs. Most of it is security work: OAuth app management and consent now require a real sign-in session, PKCE is enforced where authorization codes are issued and redeemed, and a path-traversal hole in the record convert API is closed. It also fixes a Kafka consumer that could skip messages after a temporary failure, and permission-checks the related records that graph enrichment adds to a chat prompt. Upgrade from 0.9.0 is recommended. The 1.7.0 SDKs for TypeScript, Python and Go, released on October 12, 2026, are compatible with 0.9.1. They contain breaking changes; the fix for each one, in each language, is in the SDK section below.

Highlights

OAuth app management and the consent endpoints accepted OAuth access tokens and personal access tokens. A token with any scope could create an app with broader scopes, read or regenerate client secrets, or approve a consent request for itself. Every /oauth-clients/* and /personal-access-tokens/* route, the consent POST /oauth2/authorize, and the device-flow /device/verify and /device/consent routes now require the user’s interactive session JWT, and answer 403 to OAuth access tokens and PATs. PAT scopes are capped at the instance’s MCP_SCOPES (#3626 — @rish664).

PKCE enforced where the code is issued and redeemed

PKCE was checked only on GET /oauth2/authorize, which returns consent data, not the code. A caller that skipped the GET could get a public-client code without a challenge and redeem it with no verifier and no client secret, and the plain method let a caller send its own challenge back as the verifier. A public client now must send a code_challenge to the consent POST, only S256 is accepted, and discovery advertises only S256 (#3630 — @rish231294).

Record convert API: no more writes outside the temp folder

POST /api/v1/record/buffer/convert built its temp file path from the unsanitized upload filename, so an absolute path or ../ in the name let any signed-in user write a file anywhere the connectors service could write. The filename is no longer trusted for the path (#3628 — @rish231294).

Breaking changes & upgrade notes

  • OAuth app, personal access token, consent and device-flow routes reject OAuth access tokens and PATs with 403. This covers /oauth-clients/*, /personal-access-tokens/*, POST /oauth2/authorize, /device/verify and /device/consent. Scripts that manage OAuth apps, mint PATs or approve a device login with a token must use a user’s sign-in session instead (#3626).
  • PKCE plain is rejected with 400. Public clients must send an S256 code_challenge on both the authorize GET and the consent POST; without it the consent redirects with error=invalid_request and no code. Confidential clients may still omit PKCE (#3630).
  • The service-account email domain is reserved. A person can no longer be given an address in service.pipeshub.internal, through invites, user creation or an email change (#3612).
  • SDK users: the 1.7.0 SDKs contain breaking changes. See the next section.

SDKs — 1.7.0 (TypeScript, Python, Go)

The TypeScript, Python and Go SDKs move from 1.6.0 to 1.7.0, released on October 12, 2026, and are compatible with PipesHub 0.9.1: @pipeshub-ai/sdk (v1.7.0 release), pipeshub-sdk (v1.7.0 release) and pipeshub-sdk-go (v1.7.0 release), all by @rish664.
1.7.0 is a minor version, but it contains breaking changes. Read the list for your language before you upgrade.

TypeScript

Renaming a conversation no longer returns messages

updateConversationTitle returns only the updated conversation fields. Read the messages with a second call.

Deleting an agent conversation: conversation can be empty

conversation is now a stored conversation, an empty object, or null. Check it before you read a field.

Some type names changed

Use the new name. The data inside is the same. The UpdateConversationTitle* message types are removed, because renaming a conversation no longer returns messages.

Two errors have a new error class

A 500 from knowledgeBase.uploadRecords is now thrown as ErrorResponse. A 410 from userAccount.authenticate is no longer an ErrorResponse. Both classes extend PipeshubError, so catch the parent class and check the status code.

Behavior notes (not breaking)

  • A user token on 22 endpoints. OAuth apps, personal access tokens, user info, org auth config and reset password now send only the user token. If you set up only an app token, add a user token:
  • Stream event data stays a string. Code that calls JSON.parse(event.data) keeps working.

Python

Renaming a conversation no longer returns messages

update_conversation_title returns only the updated conversation fields. Read the messages with a second call.

Deleting an agent conversation: conversation can be empty

conversation is now a stored conversation, an empty object, or None. Your code runs as before, but type checkers need a check before you read a field.

Some type names changed

Use the new name. The data inside is the same. All names are in pipeshub_sdk.models. The UpdateConversationTitle* message types are removed, because renaming a conversation no longer returns messages.

Two errors have a new error class

A 500 from knowledge_base.upload_records is now raised as ErrorResponse. A 410 from user_account.authenticate is now PipeshubDefaultError, not ErrorResponse. Both classes extend PipeshubError, so catch the parent class and check the status code.

A citation can have two shapes

A message citation is now a CitationReference or a PopulatedCitationReference. Your code runs as before, but type checkers need a check before you read a field.

Behavior notes (not breaking)

  • A user token on 22 endpoints. OAuth apps, personal access tokens, user info, org auth config and reset password now send only the user token. If you set up only an app token, add a user token:
  • Conversation streams work. data on ConversationStreamSSEEvent and ConversationMessageStreamSSEEvent is typed Any, as on the other stream models. The SDK decodes each event’s JSON before validation, so the old str type rejected those events.

Go

Go 1.26.8 or newer is required

go.mod now declares go 1.26.8 (it was go 1.22). Upgrade Go, or keep the default GOTOOLCHAIN=auto so that Go downloads the toolchain.

Renaming a conversation no longer returns messages

UpdateConversationTitle returns only the updated conversation fields. Read the messages with a second call.

Deleting an agent conversation: Conversation can be empty

Conversation is now a *components.ConversationUnion, which can be nil, a stored conversation, or an empty object.

Some type names changed

Use the new name. The data inside is the same. Enum constants take the new prefix too, for example operations.IsArchivedTrue becomes operations.ListAgentConversationsIsArchivedTrue. The operations.UpdateConversationTitle* message types are removed, because renaming a conversation no longer returns messages.

Two errors have a new error type

A 500 from KnowledgeBase.UploadRecords is now returned as *apierrors.ErrorResponse. A 410 from UserAccount.Authenticate is now the default *apierrors.APIError, not *apierrors.ErrorResponse. Check for both types.

Success is always true

On the delete-record, reindex-record, reindex-record-group and knowledge-hub-nodes responses, Success is no longer a public field. A 200 already means success, so you can drop the check, or use the getter.

A citation can have two shapes

A message citation is now a components.CitationUnion: a CitationReference or a PopulatedCitationReference. Read the citation through its wrapper.

Behavior notes (not breaking)

  • A user token on 22 endpoints. OAuth apps, personal access tokens, user info, org auth config and reset password now send only the user token. If you set up only an app token, add a user token:
  • Stream event data stays a string. Code that reads *ev.Data keeps working.

Agents & AI

  • Graph enrichment respects permissions. The parents, children and attachments that enrichment adds to search results (Jira, Confluence, Linear) are now permission-checked in one batch, and their number is capped, so names, URLs and summaries of records a user cannot open no longer reach the prompt. A new filter_accessible_record_ids provider method backs it on Neo4j and ArangoDB (#3590 — @darshangodase).
  • Agent tools — behaviour tests for the GitHub, Jira and ClickUp tools, and fixes for the bugs they found (#3582); the agent answers from the workspace’s data when the Acme Corp demo is its only knowledge (#3609) — @shekharkadyan.

Fixes

  • Kafka — the Kafka consumer used by the connectors and query services no longer loses messages after a temporary handler failure. The indexing consumer was not affected (#3515).
  • Google — the personal Drive and Gmail connectors keep the fresher OAuth token after the library refreshes it, and save refreshed tokens to settings, which ends a refresh loop (#3571).
  • Web — stored ETag and Last-Modified values are read from the file record (#3622).
  • Frontend — three wordings the locale pass changed are restored (#3610).
All by @shekharkadyan.

Security & authentication

  • Service accounts — a person can no longer be given an address in the reserved service-account domain, on any of the four paths that set an email, and the service-account routes get the same rate limit as the token and OAuth app routes (#3612 — @shekharkadyan).
  • Toolset OAuth callback — a failed agent access check is answered with JSON instead of a redirect to a caller-supplied address, which the Node API used to follow on the server (#3611 — @shekharkadyan).
  • S3 — the bucket name and region are matched literally when a stored file URL is read back, so a bucket such as my.bucket no longer also matches myxbucket (#3608 — @shekharkadyan).

Developer experience & infrastructure

  • AWS EKS — S3 on EKS gets a SigV4 preload config map in the Helm chart, EKS values and docs updates, and a bucket purge test (#3634 — @abhishekgml1991).
  • Tests and CI — a weekly sustained-load test for search and chat that fails on errors and p95 regressions (#3614); a frontend unit-test coverage minimum (#3577); the shared “test” logger is no longer silenced for later tests (#3613); storage tokens are minted for the user the test client acts as (#3623); chat stream mocks really end or stay open (#3624); a missing SMB folder reads as an empty listing in the integration tests (#3620) — all @shekharkadyan.

Full commit-level detail: GitHub release · Compare view