Skip to content

feat(plane): add Plane integration - #8667

Open
mzxchandra wants to merge 10 commits into
stagingfrom
feat/plane-integration
Open

mzxchandra wants to merge 10 commits into
stagingfrom
feat/plane-integration

Conversation

@mzxchandra

Copy link
Copy Markdown
Contributor

Summary

Adds a Plane (plane.so) integration: a block with 32 operations over Plane's open-source v1 API, so it works with Plane Cloud and self-hosted instances.

Plane block and tools

  • Work items: create, get, get by identifier (ENG-42), list (cursor pagination, sorting), search, update, delete.
  • Comments: create, list, update, delete.
  • Links: add, list, delete.
  • Attachments: upload, download, list, delete.
  • Activity: list a work item's change history.
  • Projects: list, get, create.
  • Lookups: list states, list labels, create label, list workspace members, list project members, get current user.
  • Planning: list cycles (all, current, upcoming, completed, draft, incomplete), add work items to a cycle, list modules, add work items to a module.
  • Auth is a personal access token (X-API-Key), with an optional self-hosted base URL in advanced mode.
  • Response shapes were verified against Plane's server serializers and a live self-hosted instance, not just the docs examples (which omit or misname several fields).

File handling

  • Upload runs as a registered in-process operation (lib/internal/plane), following the same pattern as Ashby, ClickUp and ServiceNow.
  • It authorizes the stored file with assertToolFileAccess, reads it with a size cap, requests a signed storage upload from Plane, posts the bytes, and confirms the upload.
  • If the file exceeds the instance's attachment limit, the pending attachment is discarded and a clear 413 is returned.
  • The storage URL uses the configuredEndpoint egress profile only when it is on the configured Plane origin (bundled MinIO); any other host uses contentFetch.
  • Download is an external responseType: 'binary' tool.
  • Plane answers with a 302 to signed storage, and the executor drops all request headers on that cross-origin hop, so the API key never reaches the storage host.

Shared changes

  • tools/error-extractors.ts: adds a plane-errors extractor for Plane's { error }, DRF { detail }, and field-validation error bodies.
  • It is opt-in (inFallbackChain: false), so tools without an explicit extractor resolve errors exactly as before.
  • lib/workflows/subblocks/display.ts: a single uploaded file on a block card showed its object keys ("name, path +4"); it now shows the filename.
  • This affects every single-file upload field (ClickUp, ServiceNow, and others), not just Plane.

Review fixes in this PR

  • IDs and slugs go through validatePathSegment, so a .. ID cannot collapse a request onto its parent resource.
  • The block's canvas-to-param remaps no longer overwrite values an Agent passes under the tool's own param names.

Webhook triggers are not included: Plane's open-source API has no endpoint to create webhooks.

Type of Change

  • New feature
  • Bug fix (single-file display label on block cards)

Testing

  • bunx vitest run on the changed areas: 90 tests across the Plane tools, upload operation, block params, error extractors, subblock display, blocks.test.ts, and the internal-operation registry.
  • bun run check:audits, bun run type-check, and check-block-registry.ts origin/staging pass.
  • All 31 HTTP tools were run against a live self-hosted Plane (v1.4.2) and their mapped outputs checked field by field.
  • Browser E2E on a local Sim against that instance:
    • list work items with pagination;
    • create with comma-separated assignees/labels and a priority;
    • get by identifier (lowercase input);
    • a 404 surfacing Plane's error message;
    • upload a file, then download it back, with byte-for-byte equality.

Reviewers may want to focus on lib/internal/plane/operations.ts (egress profile choice and the size-limit discard path) and tools/plane/utils.ts (response mappers).

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced

🤖 Generated with Claude Code

A file-upload subblock holding one file rendered its object keys
("name, path +4") on the canvas card and sentence chip. Multi-file values
already resolved to names; the single-file record now does too.
Adds a Plane (plane.so) block with 32 tools covering work items (create,
get, get by identifier, list, search, update, delete), comments, links,
attachments (upload, download, list, delete), activity history, projects,
states, labels, members, the current user, cycles, and modules. Works
with Plane Cloud and self-hosted instances via an optional base URL.

Attachment upload runs as an in-process operation that authorizes the
stored file, follows Plane's signed-storage upload flow, and confirms the
upload; download uses a raw binary request whose redirect to signed
storage drops the API key on cross-origin hops. A dedicated, opt-in
plane-errors extractor surfaces Plane and Django REST Framework error
bodies without changing the fallback chain for other tools.
encodeURIComponent leaves . and .. intact, so an ID of .. collapsed the
URL onto the parent resource (a work item delete could target its
project). Every slug and ID segment now goes through validatePathSegment.
The block's params transform assigned undefined for canvas-only field ids,
overwriting url, title, identifier, and parentId that an Agent passes
under the tool's own param names. Remaps now apply only when the canvas
field is set, and work items and labels share one parent ID field.
@vercel

vercel Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Oct 6, 2026 6:18am UTC

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

6 issues found across 62 files

Confidence score: 3/5

  • add_work_items_to_cycle.ts only reports assignments for the submitted issues, so the result can miss other work items already in the cycle. Fetch and include the cycle’s full work-item list.
  • operations.ts leaves the pending attachment row and uploaded bytes behind when the PATCH is rejected. Discard the pending attachment on that failure path.
  • work_item_shared.ts omits a supplied blank description from the PATCH, so callers can’t clear an existing description. Preserve the difference between an omitted description and a blank one.
  • list_comments.ts and list_projects.ts send no page size when perPage is omitted, so Plane returns 20 items instead of the advertised default of 100. Apply the default in both tools or update the advertised defaults.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/tools/plane/work_item_shared.ts">

<violation number="1" location="apps/sim/tools/plane/work_item_shared.ts:80">
P2: An explicitly blank description is omitted from the PATCH, so callers cannot clear an existing work-item description through this tool. Preserve the distinction between an omitted field and a supplied blank value, sending `null` for the latter.</violation>
</file>

<file name="apps/sim/tools/plane/list_projects.ts">

<violation number="1" location="apps/sim/tools/plane/list_projects.ts:38">
P3: The tool advertises a default page size of 100, but an omitted `perPage` is sent without `per_page`, so Plane returns its default of 20. Default `perPage` to 100 here or correct the advertised default.</violation>
</file>

<file name="apps/sim/tools/plane/add_work_items_to_cycle.ts">

<violation number="1" location="apps/sim/tools/plane/add_work_items_to_cycle.ts:61">
P2: This mapper only sees the assignments returned for the submitted `issues`, so it omits unrelated work items already in the cycle despite promising all current members. Fetch the cycle work-item list, including its pages, before returning the full list, or narrow the output contract.</violation>
</file>

<file name="apps/sim/lib/internal/plane/operations.ts">

<violation number="1" location="apps/sim/lib/internal/plane/operations.ts:264">
P2: The initial POST persists an attachment with `is_uploaded: false`; this rejected PATCH returns without calling `discardPendingAttachment`, leaving the pending row and uploaded bytes behind. Delete the asset before returning the confirmation error to avoid orphaned attachments.</violation>
</file>

<file name="apps/sim/tools/error-extractors.ts">

<violation number="1" location="apps/sim/tools/error-extractors.ts:135">
P2: Nested DRF validation errors are dropped because this filter accepts only direct strings, so invalid nested/list fields produce `Request failed with status 400` instead of the validation reason. Recursively flatten nested arrays and objects while preserving field paths.</violation>
</file>

<file name="apps/sim/tools/plane/list_comments.ts">

<violation number="1" location="apps/sim/tools/plane/list_comments.ts:34">
P2: When `perPage` is omitted, this helper leaves `per_page` out and Plane returns its 20-item default, despite the tool advertising a default of 100. Default `perPage` to 100 here so the first page matches the parameter contract.</violation>
</file>

Re-trigger cubic

Comment thread apps/sim/tools/plane/work_item_shared.ts
Comment thread apps/sim/tools/plane/add_work_items_to_cycle.ts
Comment thread apps/sim/lib/internal/plane/operations.ts
Comment thread apps/sim/tools/error-extractors.ts Outdated
Comment thread apps/sim/tools/plane/list_comments.ts
Comment thread apps/sim/tools/plane/list_projects.ts
@greptile-apps

greptile-apps Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium risk] Adds a new integration block for Plane project management.

The PR appears safe to merge based on this review; no outstanding findings remain.

Summary

Adds a Plane integration with work-item, project, comment, attachment, lookup, and planning operations, plus an in-process attachment upload flow.

  • Adds Plane-specific error extraction and improves single-file names on block cards.
  • Separates the create-project identifier field from the work-item lookup field and maps it to the create-project tool parameter.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  B[Plane block] --> T[Plane HTTP tools]
  B --> U[Attachment upload operation]
  T --> A[Plane API]
  U --> A
  U --> S[Signed storage upload]
  S --> A
Loading

Reviews (5) · Last reviewed commit: "fix(plane): keep the project identifier ..."

Comment thread apps/sim/lib/internal/plane/operations.ts
Comment thread apps/sim/tools/plane/work_item_shared.ts
- Discard the pending attachment when Plane rejects the upload confirmation.
- Always send per_page so Cloud and self-hosted list defaults agree.
- Keep nested Django REST Framework validation errors with field paths.
- Document that <p></p> clears a work item description (Plane rejects an
  empty string as invalid HTML).
- Regenerate the docs manifest.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 63 files

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/tools/plane/work_item_shared.ts
Adds a clearFields param (a multi-select in the block) that empties the
description, assignees, labels, parent, start and target dates, estimate
point, or work item type. Clearing is explicit rather than inferred from an
empty input, so a blank canvas field never wipes stored values.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 63 files

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/blocks/blocks/plane.ts Outdated
The identifier, url, and title fields were canvas-only ids remapped in the
params function, which kept the platform from applying its own precedence
(user-configured values over agent values) and from hiding filled params
from the agent schema. They now use the tool's param ids with
per-operation conditions, and the remaps are gone.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 63 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

Comment thread apps/sim/blocks/blocks/plane.ts Outdated
Sharing the identifier subblock between Get Work Item by Identifier and
Create Project carried a value typed for one operation into the other.
Create Project now has its own projectIdentifier field, applied only when
it is non-empty so an agent-supplied identifier is never cleared.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 63 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Re-trigger cubic

This branch was previously deployed

1 inactive deployment
Preview — 5ca4225b Deployed Oct 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant