Skip to content

Commit 4287a0b

Browse files
dcramercodex
andauthored
ref(scheduler): Extract scheduler plugin package (#429)
Move scheduler behavior into a dedicated `@sentry/junior-scheduler` trusted plugin package. Apps now opt into scheduled tasks with `schedulerPlugin()`, while core keeps the generic heartbeat, dispatch, and plugin-state primitives. **Plugin Boundary** The scheduler package owns schedule tools, recurrence math, prompt framing, durable scheduler state, and heartbeat dispatch. `@sentry/junior` no longer registers scheduler hooks by default. **Trusted Plugin API** Expose plugin state locking, set-if-not-exists writes, and `AgentPluginToolInputError` so scheduler can preserve its idempotency and model-repairable validation behavior outside core. **Release And Docs** Add the scheduler package to workspace dependencies, release metadata, CI packaging, docs, tests, and eval harness wiring. --------- Co-authored-by: GPT-5 Codex <codex@openai.com>
1 parent ace18f7 commit 4287a0b

43 files changed

Lines changed: 626 additions & 210 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.craft.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ targets:
2626
- name: npm
2727
id: "@sentry/junior-notion"
2828
includeNames: /^sentry-junior-notion-\d.*\.tgz$/
29+
- name: npm
30+
id: "@sentry/junior-scheduler"
31+
includeNames: /^sentry-junior-scheduler-\d.*\.tgz$/
2932
- name: npm
3033
id: "@sentry/junior-sentry"
3134
includeNames: /^sentry-junior-sentry-\d.*\.tgz$/

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ jobs:
5858
pnpm --filter @sentry/junior-hex pack --pack-destination artifacts
5959
pnpm --filter @sentry/junior-linear pack --pack-destination artifacts
6060
pnpm --filter @sentry/junior-notion pack --pack-destination artifacts
61+
pnpm --filter @sentry/junior-scheduler pack --pack-destination artifacts
6162
pnpm --filter @sentry/junior-sentry pack --pack-destination artifacts
6263
ls -la artifacts
6364

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ This repo uses Craft for manual lockstep npm releases of:
6767
- `@sentry/junior-hex`
6868
- `@sentry/junior-linear`
6969
- `@sentry/junior-notion`
70+
- `@sentry/junior-scheduler`
7071
- `@sentry/junior-sentry`
7172

7273
Run `pnpm release:check` before changing release package lists so `.craft.yml`, CI,

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ Start here:
3030
| `@sentry/junior-hex` | Hex plugin package for data warehouse query workflows |
3131
| `@sentry/junior-linear` | Linear plugin package for issue workflows |
3232
| `@sentry/junior-notion` | Notion plugin package for page search workflows |
33+
| `@sentry/junior-scheduler` | Scheduler plugin package for scheduled Junior tasks |
3334
| `@sentry/junior-sentry` | Sentry plugin package for issue workflows |

apps/example/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ Copy `.env.example` and set:
2828
- `AI_VISION_MODEL` (optional, enables image-understanding; unset disables vision features)
2929
- `AI_WEB_SEARCH_MODEL` (optional, overrides the `webSearch` tool model; defaults to a search-tuned model)
3030
- `JUNIOR_SECRET` (required outside `pnpm dev`; the local wrapper supplies a dev-only secret when unset)
31-
- `JUNIOR_SCHEDULER_SECRET` or `CRON_SECRET` (optional for `pnpm dev`; the local wrapper supplies a dev-only secret when both are unset)
31+
- `JUNIOR_SCHEDULER_SECRET` or `CRON_SECRET` (optional for `pnpm dev`; the local wrapper supplies a dev-only heartbeat secret when both are unset)
3232
- `NOTION_TOKEN` (optional, enables the bundled Notion plugin)
3333

3434
## Wiring
3535

3636
- `plugin-packages.ts` is the single source of truth for installed plugin packages in this app
3737
- `nitro.config.ts` passes that list to `juniorNitro()` so plugin content is copied into the build output
3838
- `server.ts` passes the same list to `createApp()` so local dev does not depend on Nitro's virtual config path for plugin discovery
39-
- root `pnpm dev` starts a local heartbeat loop that calls `/api/internal/heartbeat` every minute, matching the production cron pulse used by the built-in scheduler plugin; it also defaults `JUNIOR_BASE_URL` to the local server when unset so signed internal callbacks can recover scheduled dispatches
39+
- root `pnpm dev` starts a local heartbeat loop that calls `/api/internal/heartbeat` every minute, matching the production cron pulse used for trusted plugin heartbeats and stale dispatch recovery; it also defaults `JUNIOR_BASE_URL` to the local server when unset so signed internal callbacks can recover dispatched runs

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"test:watch": "pnpm --filter @sentry/junior test:watch",
2323
"evals": "pnpm --filter @sentry/junior-evals evals",
2424
"evals:record": "pnpm --filter @sentry/junior-evals evals:record",
25-
"typecheck": "pnpm --filter @sentry/junior typecheck && pnpm --filter @sentry/junior-testing typecheck && pnpm --filter @sentry/junior-example typecheck",
25+
"typecheck": "pnpm --filter @sentry/junior-plugin-api typecheck && pnpm --filter @sentry/junior-scheduler typecheck && pnpm --filter @sentry/junior typecheck && pnpm --filter @sentry/junior-testing typecheck && pnpm --filter @sentry/junior-example typecheck",
2626
"skills:check": "pnpm --filter @sentry/junior skills:check"
2727
},
2828
"simple-git-hooks": {

packages/docs/src/content/docs/contribute/releasing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Junior uses lockstep package releases for:
1919
- `@sentry/junior-hex`
2020
- `@sentry/junior-linear`
2121
- `@sentry/junior-notion`
22+
- `@sentry/junior-scheduler`
2223
- `@sentry/junior-sentry`
2324

2425
## Package release

packages/docs/src/content/docs/extend/index.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,9 @@ my-junior-plugin/
5454
For reuse across apps or teams, package plugin manifests and any bundled skills as npm packages and install them next to `@sentry/junior`.
5555

5656
```bash
57-
pnpm add @sentry/junior @sentry/junior-agent-browser @sentry/junior-datadog @sentry/junior-github @sentry/junior-hex @sentry/junior-linear @sentry/junior-notion @sentry/junior-sentry
57+
pnpm add @sentry/junior @sentry/junior-agent-browser @sentry/junior-datadog @sentry/junior-github @sentry/junior-hex @sentry/junior-linear @sentry/junior-notion @sentry/junior-scheduler @sentry/junior-sentry
5858
```
5959

60-
Junior also includes the built-in [Scheduler Plugin](/extend/scheduler-plugin/)
61-
for reminders and recurring Slack tasks. It does not require a separate package.
62-
6360
List the plugin packages in `juniorNitro` so they are bundled at build time and available at runtime:
6461

6562
```ts title="nitro.config.ts"
@@ -78,6 +75,7 @@ export default defineConfig({
7875
"@sentry/junior-hex",
7976
"@sentry/junior-linear",
8077
"@sentry/junior-notion",
78+
"@sentry/junior-scheduler",
8179
"@sentry/junior-sentry",
8280
],
8381
},
@@ -115,18 +113,20 @@ If you publish your own package with bundled skills, include both `plugin.yaml`
115113

116114
Some packaged plugins also export trusted runtime hooks for deterministic
117115
behavior that cannot live in skill prose or `plugin.yaml`. For example, the
118-
GitHub plugin registers runtime code that installs a sandbox Git hook,
119-
configures global Git defaults, and injects commit attribution env before bash
120-
commands run.
116+
scheduler plugin registers schedule-management tools and heartbeat behavior, and
117+
the GitHub plugin installs a sandbox Git hook, configures global Git defaults,
118+
and injects commit attribution env before bash commands run.
121119

122120
Trusted hooks are explicit app code:
123121

124122
```ts title="server.ts"
125123
import { createApp } from "@sentry/junior";
126124
import { githubPlugin } from "@sentry/junior-github";
125+
import { schedulerPlugin } from "@sentry/junior-scheduler";
127126

128127
const app = await createApp({
129128
plugins: [
129+
schedulerPlugin(),
130130
githubPlugin({
131131
botNameEnv: "GITHUB_APP_BOT_NAME",
132132
botEmailEnv: "GITHUB_APP_BOT_EMAIL",
@@ -331,7 +331,7 @@ Then install it in the host app:
331331
pnpm add @acme/junior-example
332332
```
333333

334-
The `juniorNitro({ plugins: { packages: [...] } })` module includes `app/**/*` and the declared plugin package content in the deployed function bundle. The plugin list is automatically available at runtime via `createApp()` for declarative manifest behavior. Plugins that export trusted runtime hooks, such as `@sentry/junior-github`, must also be registered from app code.
334+
The `juniorNitro({ plugins: { packages: [...] } })` module includes `app/**/*` and the declared plugin package content in the deployed function bundle. The plugin list is automatically available at runtime via `createApp()` for declarative manifest behavior. Plugins that export trusted runtime hooks, such as `@sentry/junior-scheduler` and `@sentry/junior-github`, must also be registered from app code.
335335

336336
## Validate extensions
337337

packages/docs/src/content/docs/extend/scheduler-plugin.md

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
22
title: Scheduler Plugin
3-
description: Enable and verify Junior's built-in scheduled task support.
3+
description: Enable and verify Junior's scheduled task support.
44
type: tutorial
5-
summary: Configure the built-in scheduler plugin so Slack users can create reminders and recurring tasks.
5+
summary: Configure the scheduler plugin so Slack users can create reminders and recurring tasks.
66
prerequisites:
77
- /start-here/quickstart/
88
- /start-here/slack-app-setup/
@@ -12,20 +12,39 @@ related:
1212
- /operate/reliability-runbooks/
1313
---
1414

15-
The scheduler plugin is built into `@sentry/junior`. It registers Slack tools for creating, listing, updating, deleting, and running scheduled tasks, then uses Junior's internal heartbeat to dispatch due work back to the configured Slack conversation.
15+
The scheduler plugin lives in `@sentry/junior-scheduler`. It registers Slack tools for creating, listing, updating, deleting, and running scheduled tasks, then uses Junior's internal heartbeat to dispatch due work back to the configured Slack conversation.
1616

1717
## Runtime setup
1818

19-
No plugin package install is required. `createApp()` registers the trusted scheduler plugin automatically:
19+
Install the package next to `@sentry/junior`:
20+
21+
```bash
22+
pnpm add @sentry/junior-scheduler
23+
```
24+
25+
Register the trusted plugin in app code:
2026

2127
```ts title="server.ts"
2228
import { createApp } from "@sentry/junior";
29+
import { schedulerPlugin } from "@sentry/junior-scheduler";
2330

24-
const app = await createApp();
31+
const app = await createApp({
32+
plugins: [schedulerPlugin()],
33+
});
2534

2635
export default app;
2736
```
2837

38+
List the package in `juniorNitro()` as well so Nitro bundles the manifest:
39+
40+
```ts title="nitro.config.ts"
41+
juniorNitro({
42+
plugins: {
43+
packages: ["@sentry/junior-scheduler"],
44+
},
45+
});
46+
```
47+
2948
The scaffolded `vercel.json` includes the internal heartbeat route:
3049

3150
```json title="vercel.json"
@@ -47,14 +66,14 @@ If you manage routes manually, call the heartbeat route on a one-minute cadence:
4766

4867
## Configure environment variables
4968

50-
Set one scheduler route secret:
69+
Set one heartbeat route secret:
5170

52-
| Variable | Required | Purpose |
53-
| ------------------------------------------ | ---------- | --------------------------------------------------------------------------------------------- |
54-
| `CRON_SECRET` or `JUNIOR_SCHEDULER_SECRET` | Production | Bearer token for internal scheduler and heartbeat routes. Use `CRON_SECRET` with Vercel Cron. |
55-
| `JUNIOR_TIMEZONE` | No | Default IANA timezone for schedule authoring. Defaults to `America/Los_Angeles`. |
71+
| Variable | Required | Purpose |
72+
| ------------------------------------------ | ---------- | ---------------------------------------------------------------------------------- |
73+
| `CRON_SECRET` or `JUNIOR_SCHEDULER_SECRET` | Production | Bearer token for the internal heartbeat route. Use `CRON_SECRET` with Vercel Cron. |
74+
| `JUNIOR_TIMEZONE` | No | Default IANA timezone for schedule authoring. Defaults to `America/Los_Angeles`. |
5675

57-
Local development can run without a scheduler route secret when you call the dev server directly. Production deployments should set `CRON_SECRET` or `JUNIOR_SCHEDULER_SECRET`.
76+
Local development can run without a heartbeat route secret when you call the dev server directly. Production deployments should set `CRON_SECRET` or `JUNIOR_SCHEDULER_SECRET`.
5877

5978
## Verify
6079

@@ -80,4 +99,4 @@ For recurring or non-reminder scheduled work, Junior should show the proposed ta
8099

81100
## Next step
82101

83-
Read [Build a Plugin](/extend/build-a-plugin/) for the trusted `tools(ctx)` and `heartbeat(ctx)` APIs that the built-in scheduler uses.
102+
Read [Build a Plugin](/extend/build-a-plugin/) for the trusted `tools(ctx)` and `heartbeat(ctx)` APIs that the scheduler uses.

packages/docs/src/content/docs/reference/api/functions/createApp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ title: "createApp"
77

88
> **createApp**(`options?`): `Promise`\<`Hono`\<`BlankEnv`, `BlankSchema`, `"/"`\>\>
99
10-
Defined in: [app.ts:180](https://github.com/getsentry/junior/blob/main/packages/junior/src/app.ts#L180)
10+
Defined in: [app.ts:179](https://github.com/getsentry/junior/blob/main/packages/junior/src/app.ts#L179)
1111

1212
Create a Hono app with all Junior routes.
1313

0 commit comments

Comments
 (0)