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 {
  ActivityType,
  type Priority,
  type ToolBuilder,
  Twist,
} from "@plotday/twister";
import { Plot } from "@plotday/twister/tools/plot";

export default class MyTwist extends Twist<MyTwist> {
  build(build: ToolBuilder) {
    return {
      plot: build(Plot),
    };
  }

  async activate(priority: Pick<Priority, "id">) {
    await this.tools.plot.createActivity({
      type: ActivityType.Note,
      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:

npm run 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.

// Lifecycle methods
async activate(priority)   // When twist is added to a priority
async deactivate()         // When twist is removed
async upgrade()            // When 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 activities and priorities
  • 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.

Activities and Notes

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

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

Data sync: When syncing from external systems, use Activity.source (canonical URL) and Note.key for automatic upserts without manual ID tracking. See the Sync Strategies guide for detailed patterns.

Action scheduling: When creating Actions (tasks), omitting the start field defaults to "Do Now" (current time). For most integrations, explicitly set start: null to create backlog items ("Do Someday"), only using "Do Now" for urgent or in-progress tasks.

// Create an activity with source for automatic deduplication
await this.tools.plot.createActivity({
  source: "https://github.com/org/repo/pull/123", // Enables automatic upserts
  type: ActivityType.Action,
  title: "Review pull request",
  start: null, // "Do Someday" - backlog item (recommended default)
  notes: [
    {
      activity: { source: "https://github.com/org/repo/pull/123" },
      key: "description", // Use key for upsertable notes
      content: "New PR ready for review",
      links: [
        {
          type: ActivityLinkType.external,
          title: "View PR",
          url: "https://github.com/org/repo/pull/123",
        },
      ],
    },
  ],
});

// Add or update a note using key (upserts if key exists)
await this.tools.plot.createNote({
  activity: { source: "https://github.com/org/repo/pull/123" },
  key: "approval", // Using key enables upserts
  content: "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 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

export default class WelcomeTwist extends Twist<WelcomeTwist> {
  build(build: ToolBuilder) {
    return { plot: build(Plot) };
  }

  async activate(priority: Pick<Priority, "id">) {
    await this.tools.plot.createActivity({
      type: ActivityType.Note,
      title: "Welcome to Plot! 👋",
      notes: [
        {
          content: "This twist will help you get started with Plot.",
        },
      ],
    });
  }
}

GitHub Connector

import { Connector, type ConnectorBuilder, type Channel } from "@plotday/twister";
import { Integrations } from "@plotday/twister/tools/integrations";

export default class GitHubConnector extends Connector<GitHubConnector> {
  build(build: ConnectorBuilder) {
    return {
      integrations: build(Integrations),
    };
  }

  async getChannels(): Promise<Channel[]> {
    // Return repositories the user can sync
    return repos.map((repo) => ({
      id: repo.id,
      name: repo.full_name,
    }));
  }

  async onChannelEnabled(channel: Channel) {
    // Start syncing issues from this repository
  }

  async onChannelDisabled(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.