Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ NEXTCLOUD_CONNECTOR_PORT=4014
PAPERLESS_CONNECTOR_PORT=4015
GOOGLE_ADS_CONNECTOR_PORT=4016
DARWINBOX_CONNECTOR_PORT=4017
WINDSHIFT_CONNECTOR_PORT=4018

# Public URL of the Windshift instance this Omni install talks to.
# Reachable from the user's browser for OAuth consent. One Omni install = one
# Windshift instance in v1. Set WINDSHIFT_INTERNAL_BASE_URL below when the
# connector container needs a different route to that instance.
WINDSHIFT_BASE_URL=https://windshift.example.com
# Optional connector-only URL for local/private networking. OAuth URLs and
# token audience still use WINDSHIFT_BASE_URL.
WINDSHIFT_INTERNAL_BASE_URL=

# Sandbox Port
SANDBOX_PORT=8090
Expand Down Expand Up @@ -92,7 +102,7 @@ DOCLING_MEMORY=2g
#
# Enable connectors you want to run by adding their profile to ENABLED_CONNECTORS (comma-separated).
# Available connector names:
# google, google_ads, slack, atlassian, web, github, notion, hubspot, fireflies, microsoft, filesystem, imap, linear, clickup, nextcloud, paperless, darwinbox
# google, google_ads, slack, atlassian, web, github, notion, hubspot, fireflies, microsoft, filesystem, imap, linear, clickup, nextcloud, paperless, darwinbox, windshift
#
# Example: ENABLED_CONNECTORS=google,slack
#
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
linear-connector: ${{ steps.filter.outputs.linear-connector }}
nextcloud-connector: ${{ steps.filter.outputs.nextcloud-connector }}
paperless-connector: ${{ steps.filter.outputs.paperless-connector }}
windshift-connector: ${{ steps.filter.outputs.windshift-connector }}
docling: ${{ steps.filter.outputs.docling }}
deployment: ${{ steps.filter.outputs.deployment }}
cli: ${{ steps.filter.outputs.cli }}
Expand Down Expand Up @@ -220,6 +221,11 @@ jobs:
- 'sdk/python/**'
- '.github/workflows/ci.yml'
- '.github/workflows/build-connector.yml'
windshift-connector:
- 'connectors/windshift/**'
- 'sdk/typescript/**'
- '.github/workflows/ci.yml'
- '.github/workflows/build-connector.yml'
deployment:
- 'docker/docker-compose.yml'
- 'docker/docker-compose.gpu.yml'
Expand Down Expand Up @@ -533,6 +539,15 @@ jobs:
connector-type: typescript
secrets: inherit

build-windshift-connector:
needs: detect-changes
if: needs.detect-changes.outputs.is-tag != 'true' && needs.detect-changes.outputs.windshift-connector == 'true'
uses: ./.github/workflows/build-connector.yml
with:
connector-name: windshift
connector-type: typescript
secrets: inherit

# ---------------------------------------------------------------------------
# Release: build all images from scratch on tag push
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -633,6 +648,8 @@ jobs:
connector-type: python
- connector-name: linear
connector-type: typescript
- connector-name: windshift
connector-type: typescript
uses: ./.github/workflows/build-connector.yml
with:
connector-name: ${{ matrix.connector-name }}
Expand Down
1 change: 1 addition & 0 deletions connectors/atlassian/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl Connector for AtlassianConnector {
"required": ["type"]
}),
mode: ActionMode::Read,
required_scopes: None,
source_types: Vec::new(),
admin_only: true,
hidden: false,
Expand Down
1 change: 1 addition & 0 deletions connectors/darwinbox/src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,7 @@ fn action(
description: description.to_string(),
input_schema,
mode,
required_scopes: None,
source_types: source_types.to_vec(),
admin_only,
hidden: false,
Expand Down
1 change: 1 addition & 0 deletions connectors/filesystem/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ impl Connector for FileSystemConnector {
},
"required": ["base_path"]
}),
required_scopes: None,
source_types: Vec::new(),
admin_only: false,
hidden: false,
Expand Down
4 changes: 4 additions & 0 deletions connectors/google/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,7 @@ impl Connector for GoogleConnector {
},
"required": ["file_id"]
}),
required_scopes: None,
source_types: vec![SourceType::GoogleDrive, SourceType::Gmail],
admin_only: false,
hidden: false,
Expand All @@ -879,6 +880,7 @@ impl Connector for GoogleConnector {
},
"required": []
}),
required_scopes: None,
source_types: vec![SourceType::GoogleDrive, SourceType::GoogleChat],
admin_only: true,
hidden: false,
Expand All @@ -903,6 +905,7 @@ impl Connector for GoogleConnector {
},
"required": ["schema"]
}),
required_scopes: None,
source_types: vec![SourceType::GoogleDrive, SourceType::Gmail],
admin_only: false,
hidden: false,
Expand Down Expand Up @@ -955,6 +958,7 @@ impl Connector for GoogleConnector {
},
"required": ["service", "resource", "method"]
}),
required_scopes: None,
source_types: vec![SourceType::GoogleDrive, SourceType::Gmail],
admin_only: false,
hidden: false,
Expand Down
2 changes: 2 additions & 0 deletions connectors/imap/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl Connector for ImapConnector {
// Setup/util action with no chat-facing use: hidden from every
// chat/MCP tool surface, admins included, but still in the
// manifest (Read mode) and dispatchable by name.
required_scopes: None,
source_types: Vec::new(),
admin_only: false,
hidden: true,
Expand All @@ -115,6 +116,7 @@ impl Connector for ImapConnector {
// Setup/util action with no chat-facing use: hidden from every
// chat/MCP tool surface, admins included, but still in the
// manifest (Read mode) and dispatchable by name.
required_scopes: None,
source_types: Vec::new(),
admin_only: false,
hidden: true,
Expand Down
2 changes: 2 additions & 0 deletions connectors/nextcloud/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ impl Connector for NextcloudConnector {
description: "Verify that the provided Nextcloud credentials are valid".into(),
input_schema: json!({}),
mode: omni_connector_sdk::ActionMode::Read,
required_scopes: None,
source_types: Vec::new(),
admin_only: false,
hidden: false,
Expand All @@ -138,6 +139,7 @@ impl Connector for NextcloudConnector {
"required": ["file_id"]
}),
mode: omni_connector_sdk::ActionMode::Read,
required_scopes: None,
source_types: Vec::new(),
// Internal action with no chat-facing use: hidden from every
// chat/MCP tool surface, admins included, but still in the
Expand Down
17 changes: 17 additions & 0 deletions connectors/windshift/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM node:24-slim AS builder
WORKDIR /build

COPY sdk/typescript/ /sdk/typescript/
RUN cd /sdk/typescript && npm ci && npm run build

COPY connectors/windshift/package.json connectors/windshift/package-lock.json connectors/windshift/tsconfig.json /build/
RUN npm ci --install-links
COPY connectors/windshift/src/ /build/src/
RUN npm run build

FROM node:24-slim
WORKDIR /app
COPY --from=builder /build/dist /app/dist
COPY --from=builder /build/node_modules /app/node_modules
ENV NODE_ENV=production
CMD ["node", "dist/main.js"]
46 changes: 46 additions & 0 deletions connectors/windshift/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Windshift Connector

Indexes Windshift work items, descriptions, and comments into Omni and exposes
Windshift's MCP tools as Omni actions.

## Configuration

Set `WINDSHIFT_BASE_URL` to the externally reachable Windshift base URL. If
Windshift uses a context path, include it in the URL. Enable Windshift's MCP
server with `MCP_ENABLED=true`.

For local or private networking, `WINDSHIFT_INTERNAL_BASE_URL` may point the
connector container at the same Windshift instance through a different route.
Browser authorization, resource binding, and document links still use
`WINDSHIFT_BASE_URL`; server-side client registration, token exchange, user-info,
sync, and MCP requests use the internal route.

No OAuth client ID or secret is configured manually. Omni dynamically registers
as a public client, uses S256 PKCE, and requests tokens bound to
`${WINDSHIFT_BASE_URL}/mcp`. Windshift 0.8.4 or newer is required.

Each user connects Windshift from **My Integrations**. The initial authorization
grants read access for that user's sync and read-only MCP tools. Write and
destructive tools request expanded authorization when first used. Access tokens
are refreshed automatically; rotated refresh tokens are persisted under the same
per-credential database lock.

## Data model

| Windshift | Omni document |
| -------------------------- | ------------------------------------------ |
| Item ID | `external_id = windshift:item:<id>` |
| Title | Document title |
| Description and comments | Markdown content |
| Workspace | `attributes.workspace` |
| Status | `attributes.status` |
| Priority | `attributes.priority` |
| Assignee | `attributes.assignee` and `assignee_email` |
| Created/updated timestamps | Document metadata |

Full sync walks visible workspaces and items while capturing each workspace's
change watermark. Incremental sync then reads Windshift's ordered item change
log, including comment activity and deletions. Optional `workspace_keys`
restricts sync to specific Windshift workspaces. Windshift is a personal source
in Omni: every user has an independent sync backed by their own OAuth
credential, and indexed items are visible only to that Omni user.
Loading