Skip to content

Latest commit

History

History

README.md

favicon

🌪️ Twister, the Plot Twist Creator

The official package for building Plot Twists -
smart automations that connect, organize, and prioritize your work.

📚 Full Documentation →

Quick Start

Choose your path:

  • No Code - Write natural language, deploy in minutes
  • TypeScript - Full control with code

No-Code Quick Start

Describe your twist and Plot will do the rest.

1. Create plot-twist.md:

# My Calendar Twist
I want a twist that:
- Syncs my Google Calendar events into Plot
- Creates tasks for upcoming meetings
- Sends reminders 10 minutes before meetings

2. Deploy:

npx @plotday/twister login
npx @plotday/twister deploy

That's it! Learn more →

Developer Quick Start

Build twists with TypeScript for maximum flexibility.

1. Create a new twist:

npx @plotday/twister create

2. Implement your twist:

import{typeToolBuilder,Twist}from"@plotday/twister";import{Plot,ThreadAccess}from"@plotday/twister/tools/plot";exportdefaultclassMyTwistextendsTwist<MyTwist>{build(build: ToolBuilder){return{plot: build(Plot,{thread: {access: ThreadAccess.Create},}),};}asyncactivate(){awaitthis.tools.plot.createThread({title: "Welcome! Your twist is now active.",notes: [{content: "Your twist is ready to use. Check out the [documentation](https://twist.plot.day) to learn more.",},],});}}

3. Deploy:

npx plot login
npm run deploy

Complete guide →


Core Concepts

Twists

Twists are smart automations that connect, organize, and prioritize your work. They implement opinionated workflows and respond to lifecycle events. A twist is installed at the workspace level and owned by a single user.

// Lifecycle methodsasyncactivate(context?)// When the twist is installedasyncdeactivate()// When the twist is uninstalledasyncupgrade()// When a new version is deployed

Twist Tools

Twist tools provide capabilities to twists. They are usually unopinionated and do nothing on their own.

Built-in Tools:

  • Plot - Manage threads, notes, and focuses
  • Store - Persistent key-value storage
  • AI - Language models with structured output
  • Integrations - OAuth authentication and channel lifecycle
  • Network - HTTP access and webhooks
  • Tasks - Background task execution
  • Callbacks - Persistent function references

View all tools →

External service integrations (Google Calendar, Slack, Linear, etc.) are built as Connectors — see Building Connectors.

Threads and Notes

A Thread represents something done or to be done (a task, event, or conversation). Notes represent updates and details on that thread.

Think of a Thread like a messaging thread and Notes as messages in that thread. Always create threads with an initial note, and add notes for updates rather than creating new threads.

Data sync: When syncing from external systems, connectors save Links (external items attached to threads) via integrations.saveLink(), using Link.sources for deduplication and Note.key for upsertable notes — no manual ID tracking needed. See the Sync Strategies guide for detailed patterns.

import{ActionType}from"@plotday/twister";// Create a thread with an initial noteconstthreadId=awaitthis.tools.plot.createThread({title: "Review pull request",notes: [{key: "description",// Use key for upsertable notescontent: "New PR ready for review",actions: [{type: ActionType.external,title: "View PR",url: "https://github.com/org/repo/pull/123",},],},],});// Add or update a note using key (upserts if key exists)awaitthis.tools.plot.createNote({thread: {id: threadId},key: "approval",// Using key enables upsertscontent: "LGTM! Approved ✅",});

Learn more →


CLI Commands

# Authentication
plot login
# Twist management
plot create # Create new twist project
plot generate # Generate code from plot-twist.md
plot lint # Check for build or lint errors
plot build # Bundle without deploying
plot deploy # Deploy to Plot
plot logs # Stream real-time twist logs# Priority management
plot priority list # List all priorities
plot priority create # Create new priority

Complete CLI reference →


Documentation

📚 Full Documentation at twist.plot.day

Guides

Reference


Examples

Simple Note Twist

exportdefaultclassWelcomeTwistextendsTwist<WelcomeTwist>{build(build: ToolBuilder){return{plot: build(Plot,{thread: {access: ThreadAccess.Create},}),};}asyncactivate(){awaitthis.tools.plot.createThread({title: "Welcome to Plot! 👋",notes: [{content: "This twist will help you get started with Plot.",},],});}}

GitHub Connector

import{Connector,typeToolBuilder}from"@plotday/twister";import{AuthProvider,typeAuthToken,typeAuthorization,typeChannel,Integrations,}from"@plotday/twister/tools/integrations";exportdefaultclassGitHubConnectorextendsConnector<GitHubConnector>{readonlyprovider=AuthProvider.GitHub;readonlyscopes=["repo"];build(build: ToolBuilder){return{integrations: build(Integrations),};}asyncgetChannels(auth: Authorization|null,token: AuthToken|null): Promise<Channel[]>{// Return repositories the user can syncconstrepos=awaitthis.listRepos(token);returnrepos.map((repo)=>({id: repo.id,title: repo.full_name,}));}asynconChannelEnabled(channel: Channel){// Start syncing issues from this repository}asynconChannelDisabled(channel: Channel){// Stop syncing and clean up}}

More examples →


TypeScript Configuration

Extend the Twist Creator's base configuration in your tsconfig.json:

{
"extends": "@plotday/twister/tsconfig.base.json",
"include": ["src/*.ts"]
}

Support


License

MIT © Plot Technologies Inc.