Skip to content

Added initial repo cursor rules and other docs for AI #1783

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 11, 2025
Merged
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
24 changes: 24 additions & 0 deletions .cursor/rules/executing-commands.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
description: how to run commands in the monorepo
globs:
alwaysApply: true
---
Almost all commands in the monorepo should be executed when `pnpm run ...` from the root of the monorepo. For example, running tests for the `@internal/run-engine` internal package:

```
pnpm run dev --filter webapp
```

But often, when running tests, it's better to `cd` into the directory and then run tests:

```
cd apps/webapp
pnpm run test
```

This way you can run for a single file easily:

```
cd internal-packages/run-engine
pnpm run test ./src/engine/tests/ttl.test.ts
```
Comment on lines +1 to +24
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Good command execution guidance with minor inconsistency

This documentation effectively explains how to run commands in the monorepo with helpful examples. However, there's an inconsistency in the first example - it mentions running tests for the @internal/run-engine package but the example shows pnpm run dev --filter webapp.

 ---
 description: how to run commands in the monorepo
 globs: 
 alwaysApply: true
 ---
-Almost all commands in the monorepo should be executed when `pnpm run ...` from the root of the monorepo. For example, running tests for the `@internal/run-engine` internal package:
+Almost all commands in the monorepo should be executed using `pnpm run ...` from the root of the monorepo. For example, running the development server for the webapp:

pnpm run dev --filter webapp


+For running tests for a specific package from the root:
+
+```
+pnpm run test --filter @internal/run-engine
+```
+
But often, when running tests, it's better to `cd` into the directory and then run tests:

cd apps/webapp
pnpm run test


This way you can run for a single file easily:

cd internal-packages/run-engine
pnpm run test ./src/engine/tests/ttl.test.ts

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---
description: how to run commands in the monorepo
globs:
alwaysApply: true
---
Almost all commands in the monorepo should be executed when `pnpm run ...` from the root of the monorepo. For example, running tests for the `@internal/run-engine` internal package:
```
pnpm run dev --filter webapp
```
But often, when running tests, it's better to `cd` into the directory and then run tests:
```
cd apps/webapp
pnpm run test
```
This way you can run for a single file easily:
```
cd internal-packages/run-engine
pnpm run test ./src/engine/tests/ttl.test.ts
```
---
description: how to run commands in the monorepo
globs:
alwaysApply: true
---
Almost all commands in the monorepo should be executed using `pnpm run ...` from the root of the monorepo. For example, running the development server for the webapp:

6 changes: 6 additions & 0 deletions .cursor/rules/repo.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
description: understanding the structure of the monorepo
globs:
alwaysApply: true
---
We've documented the structure of our monorepo here: [repo.md](mdc:ai/references/repo.md)
37 changes: 37 additions & 0 deletions .cursor/rules/webapp.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
description: Making updates to the main trigger.dev remix webapp
globs: apps/webapp/**/*.tsx,apps/webapp/**/*.ts
alwaysApply: false
---

The main trigger.dev webapp, which powers it's API and dashboard and makes up the docker image that is produced as an OSS image, is a Remix 2.1.0 app that uses an express server, written in TypeScript. The following subsystems are either included in the webapp or are used by the webapp in another part of the monorepo:

- `@trigger.dev/database` exports a Prisma 5.4.1 client that is used extensively in the webapp to access a PostgreSQL instance. The schema file is [schema.prisma](mdc:internal-packages/database/prisma/schema.prisma)
- `@trigger.dev/core` is a published package and is used to share code between the `@trigger.dev/sdk` and the webapp. It includes functionality but also a load of Zod schemas for data validation. When importing from `@trigger.dev/core` in the webapp, we never import the root `@trigger.dev/core` path, instead we favor one of the subpath exports that you can find in [package.json](mdc:packages/core/package.json)
- `@internal/run-engine` has all the code needed to trigger a run and take it through it's lifecycle to completion.
- `@internal/redis-worker` is a custom redis based background job/worker system that's used in the webapp and also used inside the run engine.

## Environment variables and testing

In the webapp, all environment variables are accessed through the `env` export of [env.server.ts](mdc:apps/webapp/app/env.server.ts), instead of directly accessing `process.env`.

Ideally, the `env.server.ts` file would never be imported into a test file, either directly or indirectly. Tests should only imported classes and functions from a file matching `app/**/*.ts` of the webapp, and that file should not use environment variables, everything should be passed through as options instead. This "service/configuration" separation is important, and can be seen in a few places in the code for examples:

- [realtimeClient.server.ts](mdc:apps/webapp/app/services/realtimeClient.server.ts) is the testable service, and [realtimeClientGlobal.server.ts](mdc:apps/webapp/app/services/realtimeClientGlobal.server.ts) is the configuration

Also for writing tests in the webapp, checkout our [tests.md](mdc:ai/references/tests.md) guide

## Legacy run engine vs Run Engine 2.0

We originally the Trigger.dev "Run Engine" not as a single system, but just spread out all over the codebase, with no real separate or encapsulation. And we didn't even call it a "Run Engine". With Run Engine 2.0, we've completely rewritten big parts of the way the system works, and moved it over to an internal package called `@internal/run-engine`. So we've retroactively named the previous run engine "Legacy run engine". We're focused almost exclusively now on moving to Run Engine 2.0 and will be deprecating and removing the legacy run engine code eventually.

## Where to look for code

- The trigger API endpoint is [api.v1.tasks.$taskId.trigger.ts](mdc:apps/webapp/app/routes/api.v1.tasks.$taskId.trigger.ts)
- The batch trigger API endpoint is [api.v1.tasks.batch.ts](mdc:apps/webapp/app/routes/api.v1.tasks.batch.ts)
- Setup code for the prisma client is in [db.server.ts](mdc:apps/webapp/app/db.server.ts)
- The run engine is configured in [runEngine.server.ts](mdc:apps/webapp/app/v3/runEngine.server.ts)
- All the "services" that are found in app/v3/services/**/*.server.ts
- The code for the TaskEvent data, which is the otel data sent from tasks to our servers, is in both the [eventRepository.server.ts](mdc:apps/webapp/app/v3/eventRepository.server.ts) and also the [otlpExporter.server.ts](mdc:apps/webapp/app/v3/otlpExporter.server.ts). The otel endpoints which are hit from production and development otel exporters is [otel.v1.logs.ts](mdc:apps/webapp/app/routes/otel.v1.logs.ts) and [otel.v1.traces.ts](mdc:apps/webapp/app/routes/otel.v1.traces.ts)
- We use "presenters" to move more complex loader code into a class, and you can find those are app/v3/presenters/**/*.server.ts

6 changes: 6 additions & 0 deletions .cursor/rules/writing-tests.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
description: How to write tests in the monorepo
globs:
alwaysApply: true
---
Follow our [tests.md](mdc:ai/references/tests.md) guide for how to write tests in the monorepo.
7 changes: 7 additions & 0 deletions .cursorignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apps/docker-provider/
apps/kubernetes-provider/
apps/proxy/
apps/coordinator/
packages/rsc/
.changeset
.zed
37 changes: 37 additions & 0 deletions ai/references/repo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Repo Overview

This is a pnpm 8.15.5 monorepo that uses turborepo @turbo.json. The following workspaces are relevant

## Apps

- <root>/apps/webapp is a remix app that is the main API and dashboard for trigger.dev
- <root>/apps/supervisor is a node.js app that handles the execution of built tasks, interaction with the webapp through internal "engine" APIs, as well as interfacing with things like docker or kubernetes, to execute the code.

## Public Packages

- <root>/packages/trigger-sdk is the `@trigger.dev/sdk` main SDK package.
- <root>/packages/cli-v3 is the `trigger.dev` CLI package. See our [CLI dev command](https://trigger.dev/docs/cli-dev.md) and [Deployment](https://trigger.dev/docs/deployment/overview.md) docs for more information.
- <root>/packages/core is the `@trigger.dev/core` package that is shared across the SDK and other packages
- <root>/packages/build defines the types and prebuilt build extensions for trigger.dev. See our [build extensions docs](https://trigger.dev/docs/config/extensions/overview.md) for more information.
- <root>/packages/react-hooks defines some useful react hooks like our realtime hooks. See our [Realtime hooks](https://trigger.dev/docs/frontend/react-hooks/realtime.md) and our [Trigger hooks](https://trigger.dev/docs/frontend/react-hooks/triggering.md) for more information.

## Internal Packages

- <root>/internal-packages/\* are packages that are used internally only, not published, and usually they have a tsc build step and are used in the webapp
- <root>/internal-packages/database is the `@trigger.dev/database` package that exports a prisma client, has the schema file, and exports a few other helpers.
- <root>/internal-packages/run-engine is the `@internal/run-engine` package that is "Run Engine 2.0" and handles moving a run all the way through it's lifecycle
- <root>/internal-packages/redis-worker is the `@internal/redis-worker` package that implements a custom background job/worker sytem powered by redis for offloading work to the background, used in the webapp and also in the Run Engine 2.0.
- <root>/internal-packages/redis is the `@internal/redis` package that exports Redis types and the `createRedisClient` function to unify how we create redis clients in the repo. It's not used everywhere yet, but it's the preferred way to create redis clients from now on.
- <root>/internal-packages/testcontainers is the `@internal/testcontainers` package that exports a few useful functions for spinning up local testcontainers when writing vitest tests. See our [tests.md](./tests.md) file for more information.
- <root>/internal-packages/zodworker is the `@internal/zodworker` package that implements a wrapper around graphile-worker that allows us to use zod to validate our background jobs. We are moving away from using graphile-worker as our background job system, replacing it with our own redis-worker package.

## References

- <root>/references/\* are test workspaces that we use to write and test the system. Not quite e2e tests or automated, but just a useful place to help develop new features

## Other

- <root>/docs is our trigger.dev/docs mintlify documentation site
- <root>/docker/Dockerfile is the one that creates the main trigger.dev published image
- <root>/docker/docker-compose.yml is the file we run locally to start postgresql, redis, and electric when we are doing local development. You can run it with `pnpm run docker`
- <root>/CONTRIBUTING.md defines the steps it takes for OSS contributors to start contributing.
81 changes: 81 additions & 0 deletions ai/references/tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
## Running Tests

We use vitest exclusively for testing. To execute tests for a particular workspace, run the following command:

```bash
pnpm run test --filter webapp
```

Prefer running tests on a single file (and first cding into the directory):

```bash
cd apps/webapp
pnpm run test ./src/components/Button.test.ts
```

If you are cd'ing into a directory, you may have to build dependencies first:

```bash
pnpm run build --filter webapp
cd apps/webapp
pnpm run test ./src/components/Button.test.ts
```

## Writing Tests

We use vitest for testing. We almost NEVER mock anything. Start with a top-level "describe", and have multiple "it" statements inside of it.

When writing anything that needs redis or postgresql, we have some internal "testcontainers" that are used to spin up a local instance, redis, or both.

redisTest:

```typescript
import { redisTest } from "@internal/testcontainers";
import { createRedisClient } from "@internal/redis";

describe("redisTest", () => {
redisTest("should use redis", async ({ redisOptions }) => {
const redis = createRedisClient(redisOptions);

await redis.set("test", "test");
const result = await redis.get("test");
expect(result).toEqual("test");
});
});
```

postgresTest:

```typescript
import { postgresTest } from "@internal/testcontainers";

describe("postgresTest", () => {
postgresTest("should use postgres", async ({ prisma }) => {
// prisma is an instance of PrismaClient
});
});
```

containerTest:

```typescript
import { containerTest } from "@internal/testcontainers";

describe("containerTest", () => {
containerTest("should use container", async ({ prisma, redisOptions }) => {
// container has both prisma and redis
});
});
```

## Dos and Dont's

- Do not mock anything.
- Do not use mocks in tests.
- Do not use spies in tests.
- Do not use stubs in tests.
- Do not use fakes in tests.
- Do not use sinon in tests.
- Structure each test with a setup, action, and assertion style.
- Feel free to write long test names.
- If there is any randomness in the code under test, use `seedrandom` to make it deterministic by allowing the caller to provide a seed.