Skip to content

feat(composio): add Linear provider for Memory Tree ingest#2402

Merged
senamakel merged 7 commits into
tinyhumansai:mainfrom
justinhsu1477:feat/linear-memory-provider
May 23, 2026
Merged

feat(composio): add Linear provider for Memory Tree ingest#2402
senamakel merged 7 commits into
tinyhumansai:mainfrom
justinhsu1477:feat/linear-memory-provider

Conversation

@justinhsu1477
Copy link
Copy Markdown
Contributor

@justinhsu1477 justinhsu1477 commented May 21, 2026

Summary

  • Adds LinearProvider under src/openhuman/composio/providers/linear/, joining the existing gmail / notion / slack / clickup providers as the fifth toolkit with native Memory Tree ingest. Linear was previously exposed only as a catalog-only toolkit (LINEAR_CURATED in catalogs_productivity.rs) — tool-calling worked, but the connected workspace's issues never reached long-term memory.
  • Implementation follows the ClickUp provider's incremental-sync model 1:1 — branched directly off composio/providers/clickup/ as a structural template, with Linear-specific shape (Relay-style pagination via pageInfo.endCursor, ISO 8601 updatedAt, GraphQL viewer for user identity, workspace-prefixed identifier like OH-123 surfaced in the chunk title).
  • Privacy posture: only issues the user is assigned to are pulled, never the whole workspace's issue graph. Matches the "fetch-what-the-user-sees" stance gmail / notion / clickup already take.

Problem

composio/providers/ today has working memory-ingest providers for gmail, notion, slack, and clickup. For dev-shaped users, the equivalent center of gravity is Linear — and there's nothing pulling issues / comments / project context into the Memory Tree on the periodic sync path. Composio already brokers the credentials and exposes the relevant read actions (LINEAR_LIST_LINEAR_ISSUES, LINEAR_GET_LINEAR_ISSUE, etc.), so this is a "plug Linear into the existing pattern" PR, not a new architecture.

Solution

New module: src/openhuman/composio/providers/linear/ (5 files, ~1043 LOC):

mod.rs        — module wiring + re-exports                      (24)
provider.rs   — impl ComposioProvider for LinearProvider       (~450)
sync.rs       — payload-shape helpers (extract_issues /
                extract_issue_title / extract_issue_updated /
                extract_issue_identifier / extract_viewer_id /
                extract_pagination_end_cursor)                 (~290)
tools.rs      — LINEAR_CURATED, 22 actions migrated from
                catalogs_productivity + LINEAR_GET_VIEWER added (~115)
tests.rs      — 18 trait + helper unit tests                   (~165)

Five registration touchpoints (same shape ClickUp landed in #2291):

  1. composio/providers/mod.rs: pub mod linear;
  2. composio/providers/registry.rs::init_default_providers: one extra register_provider(...) line.
  3. composio/providers/mod.rs::has_native_provider: add "linear".
  4. composio/providers/mod.rs::native_provider_sync_interval: add "linear" => ....
  5. composio/providers/mod.rs::catalog_for_toolkit: repoint "linear" from catalogs::LINEAR_CURATED to linear::LINEAR_CURATED.

Plus the natural housekeeping:

  • composio/providers/descriptions.rs: Linear description updated to mention Memory Tree sync (matches the ClickUp description shape).
  • composio/providers/catalogs.rs + catalogs_productivity.rs: removed the now-superseded LINEAR_CURATED declaration. Stub comment in catalogs_productivity.rs points the next reader at the new home so the migration history is discoverable.

Sync model (mirroring ClickUp)

  1. SyncState::load("linear", connection_id) from the shared KV store.
  2. Daily request budget check (DEFAULT_DAILY_REQUEST_LIMIT = 500).
  3. Resolve viewer id via LINEAR_GET_VIEWER — Linear's LINEAR_LIST_LINEAR_ISSUES filter { assignee: { id: { eq: <viewer_id> } } } needs the connected user's id to scope to "my issues".
  4. Re-check budget between viewer probe and list-issues call — same discipline ClickUp got after feat(composio): add ClickUp provider for Memory Tree ingest #2291's CodeRabbit feedback, so the daily cap is honoured strictly even when entering the sync with one slot left.
  5. Page through LINEAR_LIST_LINEAR_ISSUES with orderBy: updatedAt, sortDirection: descending, first: <page_size>, after: <cursor>. Stop each pass early when an issue's updatedAt falls at or below the saved cursor (and the composite issue_id@updatedAt key is already in synced_ids), or when Linear's Relay-style pageInfo.hasNextPage reports false.
  6. Per issue, persist as one memory document via persist_single_item. Dedupe by composite issue_id@updatedAt so edited issues re-ingest (same trick Notion uses for last_edited_time and ClickUp uses for date_updated).
  7. Advance the cursor to the newest updatedAt seen, record last_sync_at_ms, save state.

Source-id convention

composio-linear-issue-<issue_uuid> — stable per issue across syncs so re-ingestion upserts rather than duplicates. Document title is "Linear <identifier>: <title>" (e.g. "Linear OH-123: Wire up tag write tool") so the workspace-prefixed identifier surfaces in search hits — that's how humans refer to Linear issues in conversation.

Curated tool catalog

LINEAR_CURATED exposes 22 Linear actions split across the standard scopes:

  • Read (11): identity (LINEAR_GET_VIEWER), issues (LIST_LINEAR_ISSUES, GET_LINEAR_ISSUE, SEARCH_ISSUES), workspace structure (teams / projects / states / cycles), users, labels.
  • Write (9): create / update issues + comments, create / update projects + labels, create attachments + issue relations.
  • Admin (2): destructive deletes (DELETE_LINEAR_ISSUE, REMOVE_ISSUE_LABEL).

LINEAR_GET_VIEWER is the one slug not already in the pre-migration LINEAR_CURATED — adding it because the sync path needs the authenticated user's id to build the assignee filter. The remaining 21 actions are migrated verbatim from catalogs_productivity::LINEAR_CURATED, just relocated next to the provider so the catalog and the impl live together (consistent with gmail / notion / clickup).

Submission Checklist

  • Tests added or updated — 18 new unit tests cover sync helpers (results / title / identifier / updated / viewer-id / pagination cursor extraction across raw and wrapped payload shapes), trait metadata stability (provider_metadata_is_stable, curated_tools_contains_core_read_surface), capability matrix registration (capability_matrix_includes_linear_as_native_memory_provider), and default_impl_matches_new (observable equivalence — caught a no-op test pattern in the ClickUp PR's CodeRabbit review and applied the fix proactively).
  • Diff coverage ≥ 80% — new code is overwhelmingly the sync() async happy path (covered behind a Composio ProviderContext the existing test harness doesn't stand up — same as the Notion / Slack / ClickUp tests don't exercise the live sync() end-to-end either). Helper layer is unit-tested directly.
  • N/A: Coverage matrix updated — extends the existing "Composio memory provider" capability row added with gmail / notion / slack / clickup; no new matrix feature row.
  • N/A: All affected feature IDs from the matrix are listed — extending an existing capability.
  • No new external network dependencies introduced — all Linear API access goes through the existing Composio backend / direct client.
  • N/A: Manual smoke checklist updated — no release-cut surface changes; new ingest path is feature-flagged behind "user has a Linear Composio connection".
  • Linked issue closed via Closes #2400 in ## Related.

Impact

  • Runtime/platform impact: desktop core only (Rust). No Tauri shell, no frontend changes.
  • Compatibility impact: strictly additive. The existing gmail / notion / slack / clickup providers, their SyncState KV namespaces, their registered tool catalogs, and all catalog-only toolkits are unchanged. The LINEAR_CURATED migration is source-internal — catalog_for_toolkit("linear") still returns the same actions to the meta-tool layer.
  • Performance impact: bounded — MAX_PAGES_PER_SYNC = 20, PAGE_SIZE = 50 steady-state (100 for the initial backfill), and the shared DailyBudget (500 req/day) caps total API churn the same way it does for the other providers.
  • Security impact: assignee-scoped fetch (assignee = viewer_id) prevents accidental ingest of other teammates' private issues. Composio handles credentials; no new secret-handling code.

Transparency notes

  • Composio action slugs not manually verified against a live tenant. The LINEAR_GET_VIEWER slug name is modelled on Composio's standard <TOOLKIT>_<ACTION> naming convention; the remaining 21 are migrated verbatim from the existing LINEAR_CURATED and were already in use by the meta-tool layer. If LINEAR_GET_VIEWER differs from the live catalog name (e.g. LINEAR_GET_AUTHENTICATED_USER), it's a one-line string change with no architectural impact — happy to amend on review.
  • Filter argument shape for LINEAR_LIST_LINEAR_ISSUES ({ assignee: { id: { eq: ... } } }) mirrors Linear's GraphQL filter pattern. Composio's wrapping may flatten this to a simpler shape (e.g. { assignee_id: ... }); if so, the change is also one line in provider.rs::sync().

Both are typical "first contact with a live Composio toolkit" risks and the same kind of issue that surfaced harmlessly on the ClickUp PR's first review pass.

Related


AI Authored PR Metadata

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: feat/linear-memory-provider
  • Commit SHA: (latest on the branch)
  • Base: upstream/main at fetch time

Validation Run

  • N/A: pnpm --filter openhuman-app format:check — Rust-only change.
  • N/A: pnpm typecheck — Rust-only change.
  • Focused tests: cargo test --lib composio::providers::linear (38/38 pass — combines 18 in tests.rs and 20 in sync.rs inline tests); cargo test --lib composio::providers (303/303 pass — no regression on gmail / notion / slack / clickup or any catalog-only toolkit).
  • Rust fmt/check: cargo fmt --check clean; cargo check --lib clean (pre-existing warnings only); cargo clippy --lib --no-deps no new warnings in composio/providers/linear/.
  • N/A: Tauri fmt/check — no app/src-tauri/src/** changes.

Validation Blocked

  • N/A

Behavior Changes

  • Intended behavior change: users with a Composio-connected Linear account now have their assigned issues periodically ingested into the Memory Tree on the existing 30-minute scheduler cadence, with initial backfill triggered by the ConnectionCreated hook.
  • User-visible effect: Linear issue content (title, description, status, due date, assignees, labels as JSON) becomes available to the agent and retrieval layer the same way Gmail / Notion / Slack / ClickUp content already is.

Parity Contract

  • Legacy behavior preserved: existing gmail / notion / slack / clickup providers are completely untouched. Their SyncState KV namespaces (composio-sync-state keyed by (toolkit, connection_id)) are unchanged.
  • Guard/fallback/dispatch parity checks: provider follows the existing ComposioProvider trait contract — daily budget, dedup-by-id, cursor-based pagination, idempotent persist_single_item upserts.
  • The LINEAR_CURATED migration from catalogs_productivity to linear::tools preserves the meta-tool layer's view of the curated catalog: catalog_for_toolkit("linear") returns the same &[CuratedTool] shape, just sourced from the provider's own module instead of the catalog-only file.

Duplicate / Superseded PR Handling

Summary by CodeRabbit

  • New Features

    • Added MCP Server UI support with full German language translations for the developer menu and configuration sections
  • Improvements

    • Linear toolkit integration is now properly registered as a native provider with optimized sync intervals
    • Updated Linear toolkit description to clarify its Memory Tree syncing capabilities

Review Change Stack

Mirrors the existing gmail / notion / slack / clickup ComposioProvider
layout to periodically ingest the connected user's Linear issues into
the Memory Tree. Until now Linear was exposed only as a catalog-only
toolkit (curated for tool-calling but never reaching long-term memory).

Implementation follows the ClickUp provider's incremental-sync model
1:1 (the most recent native provider, structurally simplest reference):

  1. SyncState load + daily request budget check.
  2. Resolve the authenticated viewer's id via LINEAR_GET_VIEWER so we
     can scope the filter by `assignee`.
  3. Re-check budget after the viewer probe — same discipline
     ClickUpProvider got after the CodeRabbit feedback on tinyhumansai#2291
     between its user-id and workspaces probes, so the daily cap is
     honoured strictly even when entering the sync with one slot left.
  4. Page through LINEAR_LIST_LINEAR_ISSUES filtered by `assignee = viewer_id`,
     sorted by `updatedAt` descending. Stop each pass early when a
     task's updatedAt is older than the saved cursor or when Linear's
     Relay pagination signals `pageInfo.hasNextPage == false`.
  5. Per issue, persist as one memory document via the shared
     `persist_single_item` helper. Dedupe by composite
     `issue_id@updatedAt` so edited issues re-ingest.
  6. Advance cursor to newest updatedAt seen across the pass, record
     last_sync_at_ms, save state.

Privacy posture: only issues the user is assigned to are pulled,
never the whole workspace's issue graph. Matches the
"fetch-what-the-user-sees" stance gmail / notion / clickup already
take and avoids accidentally ingesting other teammates' private work.

Files added:
  - composio/providers/linear/mod.rs        — module wiring (24)
  - composio/providers/linear/provider.rs   — LinearProvider impl (~450)
  - composio/providers/linear/sync.rs       — payload helpers (~290)
  - composio/providers/linear/tools.rs      — LINEAR_CURATED, 22 actions (~115)
  - composio/providers/linear/tests.rs      — 18 unit tests (~165)

Files modified (registration touchpoints):
  - composio/providers/mod.rs               — pub mod linear; +
                                              has_native_provider arm +
                                              native_provider_sync_interval arm +
                                              catalog_for_toolkit("linear") repointed +
                                              new regression test
                                              `capability_matrix_includes_linear_as_native_memory_provider`
  - composio/providers/registry.rs          — register_provider in
                                              init_default_providers
  - composio/providers/descriptions.rs      — Linear description updated
                                              to mention Memory Tree sync
  - composio/providers/catalogs.rs          — LINEAR_CURATED re-export
                                              removed (now in linear::)
  - composio/providers/catalogs_productivity.rs — LINEAR_CURATED const
                                              removed (migrated to linear::tools)

Tests: 38 new linear unit tests pass (helpers, trait metadata, capability
registration). All 303 existing `composio::providers` tests continue to
pass — no regression on gmail / notion / slack / clickup or any of the
catalog-only toolkits.

Verified locally:
  - `cargo check --lib` clean (pre-existing warnings only)
  - `cargo test --lib composio::providers` 303/303 pass
  - `cargo test --lib composio::providers::linear` 38/38 pass
  - `cargo test --lib capability_matrix_includes_linear` 1/1 pass
  - `cargo fmt --check` clean
  - `cargo clippy --lib --no-deps` no new warnings in
    `src/openhuman/composio/providers/linear/`

Closes tinyhumansai#2400
@justinhsu1477 justinhsu1477 requested a review from a team May 21, 2026 02:19
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a9822cca-c4f3-426d-80fc-ceed834e3edf

📥 Commits

Reviewing files that changed from the base of the PR and between be662ad and 7b6ce71.

📒 Files selected for processing (1)
  • app/src/lib/i18n/chunks/de-5.ts

📝 Walkthrough

Walkthrough

This PR consolidates the Linear provider's curated-tools catalog from duplicate declarations in catalogs_productivity into the provider module, registers linear as a native Composio provider with proper sync intervals and catalog routing, and adds German UI translations for MCP Server configuration.

Changes

Linear Provider Catalog Integration

Layer / File(s) Summary
Catalog deduplication
src/openhuman/composio/providers/catalogs_productivity.rs, src/openhuman/composio/providers/catalogs.rs
Remove duplicate LINEAR_CURATED constant and re-export, consolidating the curated catalog to a single source in the linear provider module.
Linear native provider registration
src/openhuman/composio/providers/mod.rs, src/openhuman/composio/providers/descriptions.rs
Export linear module, update linear toolkit description, extend native-provider behavior to include linear with 30-minute sync intervals, route catalog_for_toolkit("linear") to linear::LINEAR_CURATED, and add capability matrix test verifying linear is native with memory ingest enabled.

MCP Server UI Translations

Layer / File(s) Summary
German MCP Server UI strings
app/src/lib/i18n/chunks/de-5.ts
Add German translations for MCP Server developer menu, configuration sections (tools/config), copy and config file actions, MCP client names (Claude Desktop, Cursor, Codex, Zed), and UI labels.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • tinyhumansai/openhuman#2400: This PR implements the Linear provider catalog consolidation and native provider wiring that issue #2400 describes.

Possibly related PRs

  • tinyhumansai/openhuman#2452: Both PRs modify the same Linear catalog plumbing—removing LINEAR_CURATED from catalogs_productivity/catalogs and routing it to the Linear provider module with matching description updates.

Suggested labels

feature, rust-core

Poem

A Linear path through catalogs made clear, 🐰
Deduplication buries the duplicate tier,
Native sync now ticks at thirty-minute cheer,
German words for config UI appear!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately summarizes the main feature: adding a Linear provider for Memory Tree ingest, which is the primary purpose of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 21, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/openhuman/composio/providers/linear/provider.rs (1)

230-233: ⚡ Quick win

Add connection_id to branch/error logs for correlation.

Several logs in this method omit connection_id even though it is available in scope, which makes multi-connection debugging harder.

As per coding guidelines, “Use log / tracing at debug or trace level on RPC entry and exit, error paths, state transitions, and any branch that is hard to infer from tests alone… and include correlation fields such as request IDs, method names, and entity IDs when available.”

Also applies to: 276-279, 292-292, 355-359, 365-368, 377-377

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/composio/providers/linear/provider.rs` around lines 230 - 233,
The tracing calls in this method (e.g., the tracing::info call that logs "budget
exhausted mid-sync, stopping pagination" and the other branch/error logs around
the ranges noted) are missing the connection_id field; update each tracing
invocation in this function to include connection_id = connection_id (or
connection_id = %connection_id if you prefer display formatting) so all branch,
error, and important transition logs (including the calls around the other
ranges you flagged) contain the correlation id; locate these in the current
function by the existing tracing::info/tracing::warn/tracing::error calls and
add the connection_id field to their structured fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/composio/providers/linear/provider.rs`:
- Around line 252-257: The transport call to ctx.execute(ACTION_LIST_ISSUES,
Some(args)) can early-return on error before persisting SyncState; modify the
map_err (or surrounding await) to persist the current state by calling
state.save(&memory) (or the appropriate save method) before returning the
formatted error (include page_num and the formatted error string as currently
done); ensure this change references ctx.execute, ACTION_LIST_ISSUES,
state.save, memory and page_num so the sync counters/markers are written to
storage on transport failures prior to propagating the error.

In `@src/openhuman/composio/providers/linear/sync.rs`:
- Around line 99-109: The viewer-id extractor extract_viewer_id currently falls
back to generic "id" and "data.id" keys which can return non-viewer ids; update
the pick_str key list in extract_viewer_id to only include explicit viewer/user
paths ("viewer.id", "data.viewer.id", "user.id", "data.user.id") and remove "id"
and "data.id" so the assignee filter is driven strictly by viewer/user fields.

---

Nitpick comments:
In `@src/openhuman/composio/providers/linear/provider.rs`:
- Around line 230-233: The tracing calls in this method (e.g., the tracing::info
call that logs "budget exhausted mid-sync, stopping pagination" and the other
branch/error logs around the ranges noted) are missing the connection_id field;
update each tracing invocation in this function to include connection_id =
connection_id (or connection_id = %connection_id if you prefer display
formatting) so all branch, error, and important transition logs (including the
calls around the other ranges you flagged) contain the correlation id; locate
these in the current function by the existing
tracing::info/tracing::warn/tracing::error calls and add the connection_id field
to their structured fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d2e13a1d-0fff-4bbf-9b4b-e7606f2d3317

📥 Commits

Reviewing files that changed from the base of the PR and between 369a392 and ec32960.

📒 Files selected for processing (10)
  • src/openhuman/composio/providers/catalogs.rs
  • src/openhuman/composio/providers/catalogs_productivity.rs
  • src/openhuman/composio/providers/descriptions.rs
  • src/openhuman/composio/providers/linear/mod.rs
  • src/openhuman/composio/providers/linear/provider.rs
  • src/openhuman/composio/providers/linear/sync.rs
  • src/openhuman/composio/providers/linear/tests.rs
  • src/openhuman/composio/providers/linear/tools.rs
  • src/openhuman/composio/providers/mod.rs
  • src/openhuman/composio/providers/registry.rs

Comment thread src/openhuman/composio/providers/linear/provider.rs
Comment thread src/openhuman/composio/providers/linear/sync.rs Outdated
Three items from the CodeRabbit review:

1. [major] `ctx.execute(ACTION_LIST_ISSUES, ...)` in the pagination
   loop early-returns on transport error via `?` before
   `state.save(&memory)`. Request counters / synced markers
   accumulated earlier in the same sync pass would be dropped on a
   mid-loop flap, so the next sync would burn through the daily cap
   re-fetching pages we already drained. Replaced the `?` with an
   explicit match that persists state on the error path before
   propagating, mirroring the discipline the successful-response
   branch already follows.

2. [major] `extract_viewer_id` accepted generic `id` / `data.id`
   fallback paths. Since this value drives the assignee filter for
   the whole sync, picking up a non-viewer identifier (e.g. the
   first item id in a list response that Composio collapsed)
   would silently scope the sync to the wrong user and leak issues
   from another teammate. Removed the two permissive fallbacks;
   only explicit viewer/user paths are probed now. Docstring
   updated to call out the safety rationale.

3. [minor] Several `tracing::info!` / `tracing::debug!` /
   `tracing::warn!` calls inside `sync()` omitted `connection_id`
   even though it was in scope, which makes multi-connection
   debugging harder. Added `connection_id = %connection_id` to the
   six branch / error / transition logs CodeRabbit flagged
   (budget-exhausted-mid-sync, empty-page, missing-id, persist
   failure, cursor-boundary-stop, no-next-cursor).

Plus a clippy doc-list overindent in `mod.rs` collapsed to single
line.

All 38 linear unit tests still pass; 303 composio::providers tests
still pass — no regression.
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Review — Linear Memory Provider

Solid, well-structured addition. This mirrors the ClickUp provider pattern faithfully and all five registration touchpoints are wired correctly. The sync model (viewer-id resolve → assignee-scoped pagination → cursor-based dedup → persist) is clean, and the privacy posture (assigned issues only) is appropriate.

Gates: CI pass ✓ | Conflicts pass ✓ | Coverage gate pass ✓

CodeRabbit overlap: Both findings (persist-before-return on transport failure, narrow viewer-id extraction) were addressed in 91942a9 — nothing to repeat.

Issue #2400 alignment: All acceptance criteria are met — provider registered, incremental sync with cursor, assignee filter, budget check, catalog migration, unit tests.

Cross-cutting check: LINEAR_CURATED re-export removed from catalogs.rs cleanly — catalog_for_toolkit("linear") now routes through the provider module. No other call sites reference the old re-export path (CI confirms).

One minor note:

[minor] sync.rs inline tests and tests.rs have ~15 overlapping test cases (identical assertions on the same helpers). The tests.rs module tests are the right home since they're the public integration-level tests for the module — the inline sync.rs tests could be trimmed to avoid doubling the maintenance surface. Not blocking.

Clean PR — no critical or major findings. Nice work following the established provider pattern end to end. 👍

Addresses graycyrus's tinyhumansai#2402 review minor note:
"sync.rs inline tests and tests.rs have ~15 overlapping test cases
(identical assertions on the same helpers). The tests.rs module tests
are the right home since they're the public integration-level tests
for the module — the inline sync.rs tests could be trimmed to avoid
doubling the maintenance surface."

Strategy:
  - Make tests.rs the canonical home for all helper tests.
  - Delete the entire `#[cfg(test)] mod tests {...}` block from
    sync.rs (was ~165 lines, 20 inline tests).
  - One inline test had unique coverage not duplicated in tests.rs:
    `extract_pagination_end_cursor_skips_empty_cursor_string`
    (validates that hasNextPage:true + whitespace endCursor returns
    None, preventing an infinite loop on the caller side).
    Moved that test into tests.rs verbatim (with an inline comment
    explaining the migration).
  - The other inline-only test (`now_ms_returns_nonzero`) tested a
    trivial wrapper around `SystemTime::now()` — removed without
    re-homing since the assertion `> 0` is structurally guaranteed
    by the underlying API.

Result:
  - sync.rs loses 165 lines of test code and its `#[cfg(test)]`
    block entirely — module is now extract helpers only.
  - tests.rs gains 1 test (the cursor-edge case migration).
  - Net: 165 lines deleted, 16 lines added, single source of truth
    for Linear provider unit tests.

Tests: 19 linear unit tests pass (was 38 with full duplication;
-19 net = -20 removed + 1 migrated). All 284 `composio::providers`
tests still pass — no regression.

Verified locally:
  - `cargo check --lib` clean
  - `cargo test --lib composio::providers::linear` 19/19 pass
  - `cargo test --lib composio::providers` 284/284 pass
  - `cargo fmt --check` clean
@justinhsu1477
Copy link
Copy Markdown
Contributor Author

@graycyrus thanks for the careful read.

Minor note (sync.rs inline tests vs tests.rs duplication) — addressed in be662add. Removed the entire #[cfg(test)] mod tests { ... } block from sync.rs (~165 lines, 20 inline tests), making tests.rs the single source of truth for Linear provider unit tests.

One inline test had coverage not duplicated in tests.rsextract_pagination_end_cursor_skips_empty_cursor_string (whitespace endCursor + hasNextPage:true → must return None to avoid an infinite paginate loop). Migrated that one verbatim into tests.rs with an inline comment about the move. The only other inline-only test (now_ms_returns_nonzero) was a trivial wrapper around SystemTime::now()> 0 is structurally guaranteed by the API, so dropped without re-homing.

Net diff: -166 / +16 lines, no behaviour change. 19 linear unit tests pass (was 38 with duplication); all 284 composio::providers tests still pass.

Ready for re-review.

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 22, 2026
# Conflicts:
#	src/openhuman/composio/providers/catalogs_productivity.rs
#	src/openhuman/composio/providers/descriptions.rs
#	src/openhuman/composio/providers/linear/mod.rs
#	src/openhuman/composio/providers/linear/provider.rs
#	src/openhuman/composio/providers/linear/sync.rs
#	src/openhuman/composio/providers/linear/tests.rs
#	src/openhuman/composio/providers/linear/tools.rs
#	src/openhuman/composio/providers/mod.rs
@senamakel
Copy link
Copy Markdown
Member

Resolved merge with main after #2452 shipped the equivalent Linear provider implementation.

Merge resolution

Main merged #2452 ("feat(composio): add Linear as a native memory provider") first, which added a parallel implementation of the same feature. The linear/{mod,provider,sync,tests,tools}.rs files now use the version from main (already reviewed and merged via #2452).

The remaining diff of this PR vs main is small and additive:

  • providers/catalogs.rs / catalogs_productivity.rs: pointer-stub comments at the old LINEAR_CURATED site so future readers can find the new home alongside the LinearProvider.
  • providers/descriptions.rs: line-wrapped braces form for the linear description (matches the local style used for clickup).
  • providers/mod.rs::catalog_for_toolkit: moves the linear arm into the "Native providers" section above // Catalog-only toolkits — Linear is no longer a catalog-only toolkit, so this is the correct grouping.
  • providers/mod.rs test comment: notes the five-touchpoint contract (CAPABILITY_TOOLKITS, has_native_provider, native_provider_sync_interval, catalog_for_toolkit, toolkit_description) — the version on main mentions four and predates the toolkit_description update.

Outdated review threads

The two prior CodeRabbit inline comments on linear/provider.rs and linear/sync.rs no longer apply — this PR no longer modifies those files; main's reviewed-and-merged version is authoritative.

Validation

  • cargo check --lib — clean (pre-existing warnings only)
  • cargo check --manifest-path app/src-tauri/Cargo.toml — clean
  • cargo fmt --check — clean
  • cargo test --lib composio::providers::linear — 36/36 pass
  • cargo test --lib composio::providers — 339/339 pass

Push note

Pushed with --no-verify — the pre-push hook fails on app/ ESLint errors that came in via the merge from main (18 errors in files this PR does not touch); these are pre-existing on main and not introduced by the conflict resolution.

@justinhsu1477
Copy link
Copy Markdown
Contributor Author

@senamakel — really appreciate the careful conflict resolution and preserving the four polish bits. The pointer-stubs in particular will save the next contributor some hunting. Thanks for taking the time.

senamakel added 3 commits May 22, 2026 19:41
…merge

Commit e9c9374 (tinyhumansai#2361) accidentally removed all settings.developerMenu.mcpServer.*
and settings.mcpServer.* keys from de-5.ts, leaving German as the only locale
without translations for the MCP server settings panel. Other locales
(en, ar, bn, es, fr, hi, id, it, ko, pt, ru, zh-CN) still have them.

Restored the 18 missing keys with the same German translations they
had before tinyhumansai#2361.
@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Linear as a Composio memory provider (joining gmail / notion / slack / clickup)

3 participants