@rudderhq/agent-runtime-opencode-local 0.7.2-canary.0 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -2
  4. package/dist/server/index.d.ts +1 -1
  5. package/dist/server/index.d.ts.map +1 -1
  6. package/dist/server/index.js +1 -1
  7. package/dist/server/index.js.map +1 -1
  8. package/dist/server/models.d.ts.map +1 -1
  9. package/dist/server/models.js +86 -4
  10. package/dist/server/models.js.map +1 -1
  11. package/dist/server/models.test.js +31 -0
  12. package/dist/server/models.test.js.map +1 -1
  13. package/package.json +2 -2
  14. package/skills/app-builder/SKILL.md +39 -9
  15. package/skills/app-builder/assets/scaffold/app/globals.css +109 -16
  16. package/skills/app-builder/assets/scaffold/components/contacts-workspace.tsx +176 -152
  17. package/skills/app-builder/assets/scaffold/components/ui/alert.tsx +12 -0
  18. package/skills/app-builder/assets/scaffold/components/ui/badge.tsx +27 -0
  19. package/skills/app-builder/assets/scaffold/components/ui/button.tsx +9 -7
  20. package/skills/app-builder/assets/scaffold/components/ui/card.tsx +15 -3
  21. package/skills/app-builder/assets/scaffold/components/ui/empty.tsx +18 -0
  22. package/skills/app-builder/assets/scaffold/components/ui/field.tsx +23 -0
  23. package/skills/app-builder/assets/scaffold/components/ui/input.tsx +1 -1
  24. package/skills/app-builder/assets/scaffold/components/ui/label.tsx +1 -1
  25. package/skills/app-builder/assets/scaffold/components/ui/separator.tsx +6 -0
  26. package/skills/app-builder/assets/scaffold/components/ui/skeleton.tsx +6 -0
  27. package/skills/app-builder/assets/scaffold/components/ui/table.tsx +30 -0
  28. package/skills/app-builder/assets/scaffold/components.json +20 -0
  29. package/skills/app-builder/assets/scaffold/next-env.d.ts +1 -1
  30. package/skills/app-builder/assets/scaffold/next.config.ts +19 -0
  31. package/skills/app-builder/assets/scaffold/package.json +2 -1
  32. package/skills/app-builder/assets/scaffold/rudder.app.json +1 -1
  33. package/skills/app-builder/assets/scaffold/rudder.ui.json +13 -0
  34. package/skills/app-builder/assets/scaffold/scripts/validate-rudder-ui.mjs +50 -0
  35. package/skills/app-builder/assets/scaffold/tests/e2e/app.spec.ts +35 -1
  36. package/skills/app-builder/evals/evals.json +2 -1
  37. package/skills/app-builder/references/design-guidelines.md +19 -2
  38. package/skills/app-builder/references/rudder-ui-preset.md +73 -0
  39. package/skills/app-builder/references/scaffold-contract.md +12 -0
  40. package/skills/app-builder/references/verification.md +6 -0
  41. package/skills/app-builder/scripts/report-build-status.mjs +83 -0
  42. package/skills/browser/SKILL.md +11 -4
  43. package/skills/browser/agents/openai.yaml +2 -2
  44. package/skills/browser/evals/trigger-evals.json +22 -0
  45. package/skills/rudder-docs/SKILL.md +2 -2
  46. package/skills/rudder-docs/evals/retrieval-authority-evals.json +40 -0
  47. package/skills/rudder-docs/evals/trigger-evals.json +2 -2
  48. package/skills/rudder-docs/references/api-reference.md +0 -2
  49. package/skills/rudder-docs/references/plugin-authoring.md +38 -114
  50. package/skills/rudder-docs/references/source-map.md +2 -0
@@ -1,8 +1,27 @@
1
1
  import type { NextConfig } from "next";
2
2
 
3
3
  const nextConfig: NextConfig = {
4
+ devIndicators: false,
4
5
  output: "standalone",
5
6
  poweredByHeader: false,
7
+ turbopack: {
8
+ root: process.cwd(),
9
+ },
10
+ webpack(config, { isServer }) {
11
+ if (isServer) {
12
+ config.externals.push((
13
+ { request }: { request?: string },
14
+ callback: (error?: Error | null, result?: string) => void,
15
+ ) => {
16
+ if (request?.startsWith("node:")) {
17
+ callback(null, `commonjs ${request}`);
18
+ return;
19
+ }
20
+ callback();
21
+ });
22
+ }
23
+ return config;
24
+ },
6
25
  };
7
26
 
8
27
  export default nextConfig;
@@ -17,7 +17,8 @@
17
17
  "db:migrate": "tsx scripts/migrate.ts",
18
18
  "db:seed": "tsx scripts/seed.ts",
19
19
  "data:snapshot": "tsx scripts/snapshot.ts",
20
- "verify": "tsc --noEmit && vitest run && next build",
20
+ "ui:check": "node scripts/validate-rudder-ui.mjs",
21
+ "verify": "pnpm ui:check && tsc --noEmit && vitest run && next build",
21
22
  "predev": "tsx scripts/migrate.ts && tsx scripts/seed.ts"
22
23
  },
23
24
  "dependencies": {
@@ -13,7 +13,7 @@
13
13
  "packageManager": "managed-pnpm",
14
14
  "openPath": "/",
15
15
  "readinessPath": "/api/__rudder/health",
16
- "readinessTimeoutMs": 300000
16
+ "readinessTimeoutMs": 600000
17
17
  },
18
18
  "data": {
19
19
  "provider": "sqlite",
@@ -0,0 +1,13 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "preset": "rudder",
4
+ "revision": 1,
5
+ "sourceOwnership": "app",
6
+ "appearance": {
7
+ "designStyle": "luma",
8
+ "baseColor": "neutral",
9
+ "accentTheme": "emerald",
10
+ "colorMode": "system"
11
+ },
12
+ "density": "compact"
13
+ }
@@ -0,0 +1,50 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ const root = process.cwd();
5
+ const requiredFiles = [
6
+ "components.json",
7
+ "app/globals.css",
8
+ "components/ui/button.tsx",
9
+ "components/ui/field.tsx",
10
+ "components/ui/table.tsx",
11
+ "components/ui/empty.tsx",
12
+ ];
13
+
14
+ function fail(message) {
15
+ console.error(`Rudder UI preset invalid: ${message}`);
16
+ process.exit(1);
17
+ }
18
+
19
+ let preset;
20
+ try {
21
+ preset = JSON.parse(await readFile(path.join(root, "rudder.ui.json"), "utf8"));
22
+ } catch {
23
+ fail("rudder.ui.json is missing or invalid JSON");
24
+ }
25
+
26
+ if (preset?.schemaVersion !== 1 || preset?.preset !== "rudder") {
27
+ fail("unsupported preset identity");
28
+ }
29
+ if (!Number.isInteger(preset?.revision) || preset.revision < 1) {
30
+ fail("revision must be a positive integer");
31
+ }
32
+ if (preset?.sourceOwnership !== "app") {
33
+ fail("generated Apps must own their component source");
34
+ }
35
+
36
+ for (const relativePath of requiredFiles) {
37
+ try {
38
+ await access(path.join(root, relativePath));
39
+ } catch {
40
+ fail(`required file is missing: ${relativePath}`);
41
+ }
42
+ }
43
+
44
+ const css = await readFile(path.join(root, "app/globals.css"), "utf8");
45
+ for (const token of ["--background", "--foreground", "--primary", "--destructive", "--border", "--ring", "--radius"]) {
46
+ if (!css.includes(`${token}:`)) fail(`semantic token is missing: ${token}`);
47
+ }
48
+ if (!css.includes("@theme inline")) fail("Tailwind semantic token mapping is missing");
49
+
50
+ console.log(`Rudder UI preset ${preset.revision}: ok`);
@@ -4,7 +4,7 @@ test("creates a contact and keeps it after reload", async ({ page }) => {
4
4
  const suffix = crypto.randomUUID();
5
5
  const name = `Avery ${suffix.slice(0, 8)}`;
6
6
  await page.goto("/");
7
- await expect(page.getByRole("heading", { name: "Customer workspace" })).toBeVisible();
7
+ await expect(page.getByRole("heading", { name: "Contacts", exact: true })).toBeVisible();
8
8
  await page.getByLabel("Name").fill(name);
9
9
  await page.getByLabel("Email").fill(`${suffix}@example.test`);
10
10
  await page.getByLabel("Company").fill("Acme");
@@ -14,6 +14,40 @@ test("creates a contact and keeps it after reload", async ({ page }) => {
14
14
  await expect(page.getByText(name)).toBeVisible();
15
15
  });
16
16
 
17
+ test("ships the Rudder UI preset in system light and dark modes", async ({ browser }) => {
18
+ const lightPage = await browser.newPage({ colorScheme: "light" });
19
+ await lightPage.goto("/");
20
+ await expect(lightPage.getByText("Pipeline Desk")).toBeVisible();
21
+ const lightStyle = await lightPage.evaluate(() => {
22
+ const style = getComputedStyle(document.documentElement);
23
+ return {
24
+ background: getComputedStyle(document.body).backgroundColor,
25
+ radius: style.getPropertyValue("--radius"),
26
+ };
27
+ });
28
+ expect(Number.parseFloat(lightStyle.radius)).toBe(0.375);
29
+
30
+ const darkPage = await browser.newPage({ colorScheme: "dark" });
31
+ await darkPage.goto("/");
32
+ const darkBackground = await darkPage.evaluate(() => (
33
+ getComputedStyle(document.body).backgroundColor
34
+ ));
35
+ expect(darkBackground).not.toBe(lightStyle.background);
36
+ await lightPage.close();
37
+ await darkPage.close();
38
+ });
39
+
40
+ test("keeps the primary workflow usable at 390px", async ({ page }) => {
41
+ await page.setViewportSize({ width: 390, height: 844 });
42
+ await page.goto("/");
43
+ await expect(page.getByRole("heading", { name: "Contacts", exact: true })).toBeVisible();
44
+ await expect(page.getByRole("heading", { name: "Add contact" })).toBeVisible();
45
+ await expect(page.getByLabel("Search contacts")).toBeVisible();
46
+ await expect(page.getByRole("button", { name: "Delete Maya Chen" })).toBeVisible();
47
+ await expect(page.getByText("Northwind").first()).toBeVisible();
48
+ await expect(page.locator("nextjs-portal")).toBeHidden();
49
+ });
50
+
17
51
  test("shows the empty-search state", async ({ page }) => {
18
52
  await page.goto("/");
19
53
  await page.getByLabel("Search contacts").fill("no matching record");
@@ -9,6 +9,7 @@
9
9
  "assertions": [
10
10
  "Does not ask the user to choose a framework, database, package manager, or process topology.",
11
11
  "Uses the maintained App Builder scaffold and SQLite persistence.",
12
+ "Uses the versioned Rudder UI preset and its semantic shadcn primitives instead of inventing a generic dashboard theme.",
12
13
  "Does not ask for or place email credential values in Chat or source.",
13
14
  "Includes the primary contact workflow plus import, persistence, and a production-shaped edge case in verification."
14
15
  ]
@@ -32,7 +33,7 @@
32
33
  "files": [],
33
34
  "assertions": [
34
35
  "Does not inspect or mutate real customer records merely to design the table.",
35
- "Uses the existing scaffold components and avoids decorative dashboard clutter.",
36
+ "Uses the existing Rudder UI preset components and semantic tokens, preserves readable density, and avoids decorative dashboard clutter.",
36
37
  "Verifies the table at desktop width and a 390px viewport.",
37
38
  "Captures rendered screenshot evidence and checks an empty or error state."
38
39
  ]
@@ -2,6 +2,11 @@
2
2
 
3
3
  Design for the user's actual workflow rather than for a technology demo.
4
4
 
5
+ For new maintained Apps, begin with the scaffold's versioned Rudder UI preset.
6
+ Do not replace its semantic tokens with a generic shadcn preset, a one-off
7
+ palette, or copied host application CSS. The generated App owns its component
8
+ source and must remain independently runnable outside Rudder.
9
+
5
10
  - Put the primary action and current work state above decorative summaries.
6
11
  - Use tables for operational lists, with search, meaningful filters, sorting,
7
12
  pagination when needed, empty states, and clear row actions.
@@ -11,10 +16,22 @@ Design for the user's actual workflow rather than for a technology demo.
11
16
  navigation, not both.
12
17
  - Prefer readable density for CRM and marketing data. Avoid oversized KPI cards,
13
18
  excessive gradients, glass panels, and placeholder charts.
14
- - Use the scaffold's component primitives and theme tokens before adding new
15
- one-off styling.
19
+ - Use the scaffold's shadcn primitives and semantic theme tokens before adding
20
+ new components or one-off styling. Compose `Button`, `Input`, `Field`,
21
+ `Table`, `Badge`, `Alert`, `Empty`, `Skeleton`, and `Separator` instead of
22
+ recreating those patterns with styled `div` elements.
23
+ - Keep Rudder's default visual character: calm, dense, operational, quiet, and
24
+ precise. Use compact radii, low-contrast borders, restrained elevation, one
25
+ clear primary action, and color for state or emphasis rather than decoration.
26
+ - Use semantic utilities such as `bg-background`, `text-foreground`,
27
+ `bg-muted`, and `text-destructive`. Do not hardcode product colors in
28
+ workflow components or add component-local dark-mode colors.
29
+ - Treat the preset as a starting system, not a brand lock. When the brief calls
30
+ for a distinct brand, keep the component structure, density, accessibility,
31
+ and state behavior while changing the named token layer deliberately.
16
32
  - Support keyboard use, visible focus, semantic headings, accessible names, and
17
33
  error text that does not rely on color.
18
34
  - Verify at desktop width and at 390px mobile width unless the brief excludes
19
35
  mobile.
20
36
  - Show loading, empty, error, populated, and destructive-operation states.
37
+ - Run `pnpm ui:check` before final verification for new maintained Apps.
@@ -0,0 +1,73 @@
1
+ # Rudder UI Preset
2
+
3
+ The maintained scaffold includes a versioned, source-owned shadcn preset for
4
+ building local operator tools that feel immediately at home in Rudder.
5
+
6
+ ## Source Of Truth
7
+
8
+ - `rudder.ui.json` identifies the preset and revision.
9
+ - `components.json` makes the generated project a conventional shadcn project.
10
+ - `app/globals.css` owns semantic color, radius, typography, and light/dark
11
+ tokens.
12
+ - `components/ui/` owns copied component source. Generated Apps do not import
13
+ components or CSS from the Rudder repository at runtime.
14
+ - `scripts/validate-rudder-ui.mjs` checks that the preset contract remains
15
+ present before handoff.
16
+
17
+ For new Apps, use this preset without asking the user to select a shadcn style,
18
+ base palette, accent, radius, or component library. The default is Rudder's
19
+ spacious-but-compact `luma` character, neutral surfaces, emerald action color,
20
+ and system light/dark mode.
21
+
22
+ ## Composition Rules
23
+
24
+ 1. Start with the shipped primitives. Extend them with variants when the same
25
+ need recurs; do not restyle each call site.
26
+ 2. Use semantic Tailwind utilities rather than raw color utilities. New named
27
+ product colors belong in the token layer.
28
+ 3. Keep normal controls between 32 and 36 pixels high, use compact radii, and
29
+ reserve pills for true circular or exceptional status affordances.
30
+ 4. Bind native `button`, `input`, `select`, and `textarea` text to the inherited
31
+ semantic foreground color so system dark mode cannot reintroduce browser-UA
32
+ contrast regressions.
33
+ 5. Use one primary panel or table region. Cards group independent objects or
34
+ actions; they are not wrappers for every section.
35
+ 6. Operational lists require search or filtering when useful, readable row
36
+ actions, empty/loading/error states, and horizontal containment on narrow
37
+ screens.
38
+ 7. Use Lucide icons for familiar actions. Icon-only controls need accessible
39
+ labels; icons inside buttons inherit their size from `Button`.
40
+ 8. Preserve keyboard focus, semantic headings, persistent labels, inline
41
+ validation, and destructive confirmation.
42
+
43
+ ## Appearance Boundary
44
+
45
+ The preset is copied into the App as a stable creation-time baseline. It does
46
+ not read Rudder's browser-local Appearance preferences or import host CSS at
47
+ runtime. This keeps the App portable and prevents a later Rudder theme change
48
+ from silently changing an independently branded product.
49
+
50
+ An App may add a documented host-theme bridge later, but light/dark following
51
+ must be optional and the standalone URL must still render correctly. Changing
52
+ that boundary is product behavior, not an incidental styling edit.
53
+
54
+ ## Existing Projects
55
+
56
+ Do not install or overwrite the preset in an existing project by default.
57
+ Inspect its framework, component library, tokens, and brand first. If the user
58
+ explicitly asks to align it with Rudder, preserve application behavior and
59
+ choose a bounded migration:
60
+
61
+ - token-only alignment when components are already coherent;
62
+ - primitive-by-primitive alignment when a source-owned component system exists;
63
+ - full preset adoption only when the user accepts the wider visual change.
64
+
65
+ Never run a shadcn overwrite command over locally modified components without
66
+ explicit approval and a reviewed diff.
67
+
68
+ ## Verification
69
+
70
+ Run `pnpm ui:check`, typecheck, tests, build, and the App's Playwright suite.
71
+ In Browser, inspect the primary workflow, loading or empty state, inline error,
72
+ destructive action, desktop layout, 390px layout, and light/dark contrast.
73
+ Capture the useful populated state rather than a decorative empty dashboard.
@@ -25,6 +25,8 @@ definition through **Apps + > Add local web project** before anything runs.
25
25
 
26
26
  - Next.js App Router, React, and TypeScript
27
27
  - Tailwind CSS with shadcn-style component source owned by the project
28
+ - a versioned Rudder UI preset with semantic light/dark tokens and compact
29
+ operator-tool primitives
28
30
  - SQLite with Drizzle ORM
29
31
  - Zod at API, import, and form boundaries
30
32
  - Vitest for unit tests and Playwright for browser tests
@@ -36,6 +38,8 @@ implementation detail and must not become a user decision.
36
38
  ## Required Files And Behaviors
37
39
 
38
40
  - `rudder.app.json` uses schema version 1 and a maintained template revision.
41
+ - `rudder.ui.json` identifies the source-owned Rudder UI preset revision;
42
+ `components.json` keeps the project compatible with the normal shadcn CLI.
39
43
  - `/api/__rudder/health` returns readiness only after the app can open its
40
44
  selected database.
41
45
  - `RUDDER_APP_DATA_MODE=development|production` selects the database without
@@ -64,6 +68,12 @@ manifest.
64
68
  ## Commands
65
69
 
66
70
  - `pnpm dev`: migrate the development database, then run loopback development.
71
+ - On Windows, Rudder's managed preview may select Next.js webpack while keeping
72
+ `node:*` built-ins external to the server bundle. This preserves the short
73
+ managed dependency layout required by native package executables without
74
+ changing the App's website output. The managed runtime supplies the same
75
+ compatibility to existing revision-1 Apps without rewriting their
76
+ `next.config.ts`, `next-env.d.ts`, or other App-owned source files.
67
77
  - `pnpm typecheck`: TypeScript validation.
68
78
  - `pnpm test`: unit and API-contract tests.
69
79
  - `pnpm build`: production build.
@@ -73,5 +83,7 @@ manifest.
73
83
  - `pnpm data:snapshot`: copy the selected SQLite database to `data/snapshots/`
74
84
  using SQLite's backup API.
75
85
  - `pnpm verify`: typecheck, tests, and build.
86
+ - `pnpm ui:check`: validate the maintained Rudder UI preset files and semantic
87
+ token contract.
76
88
 
77
89
  Formal app start must not silently migrate real data. Promotion owns that step.
@@ -18,6 +18,12 @@ substitute a shell HTTP response for UI acceptance.
18
18
  8. Capture current screenshots of the useful final state.
19
19
  9. Materialize screenshots in Chat, Run, or Library evidence.
20
20
 
21
+ Only after all required checks pass may the Agent report
22
+ `verified_source_ready` for the originating App. That report is not a prose
23
+ claim: it is a run-scoped handoff that causes Desktop to repeat its maintained
24
+ checks, start the attested loopback process, and open the App for the user.
25
+ Questions, partial results, and blockers must never emit the handoff.
26
+
21
27
  Close temporary run-owned tabs after verification. Never use the user's
22
28
  persistent app view as an Agent test fixture when that could mutate formal
23
29
  data.
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ const STATUS = process.argv[2];
4
+ const APP_ID = process.argv[3];
5
+ const ALLOWED_STATUSES = new Set(["building", "verified_source_ready", "failed"]);
6
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
7
+
8
+ if (!ALLOWED_STATUSES.has(STATUS) || !UUID_PATTERN.test(APP_ID ?? "")) {
9
+ console.error("Usage: report-build-status.mjs <building|verified_source_ready|failed> <app-id>");
10
+ process.exit(2);
11
+ }
12
+
13
+ const apiUrl = process.env.RUDDER_API_URL?.trim();
14
+ const apiKey = process.env.RUDDER_API_KEY?.trim();
15
+ const orgId = process.env.RUDDER_ORG_ID?.trim();
16
+ const runId = process.env.RUDDER_RUN_ID?.trim();
17
+ if (!apiUrl || !apiKey || !orgId || !runId) {
18
+ console.error("Rudder run context is unavailable; do not report a completed App handoff.");
19
+ process.exit(2);
20
+ }
21
+
22
+ const base = apiUrl.replace(/\/+$/u, "");
23
+ const apiBase = new URL(base).pathname.replace(/\/+$/u, "").endsWith("/api")
24
+ ? base
25
+ : `${base}/api`;
26
+ const endpoint = `${apiBase}/app-builder/${encodeURIComponent(APP_ID)}/build?orgId=${encodeURIComponent(orgId)}`;
27
+ const headers = {
28
+ authorization: `Bearer ${apiKey}`,
29
+ "content-type": "application/json",
30
+ };
31
+ const currentResponse = await fetch(
32
+ `${apiBase}/orgs/${encodeURIComponent(orgId)}/app-builder`,
33
+ { headers },
34
+ );
35
+ if (!currentResponse.ok) {
36
+ console.error(`Rudder could not read the App handoff state (${currentResponse.status}).`);
37
+ process.exit(1);
38
+ }
39
+ const current = (await currentResponse.json()).find((app) => app.id === APP_ID);
40
+ if (!current) {
41
+ console.error("Rudder App handoff identity was not found in this organization.");
42
+ process.exit(1);
43
+ }
44
+ const duplicateRunId = STATUS === "verified_source_ready"
45
+ ? current.latestVerificationRunId
46
+ : current.latestBuildRunId;
47
+ if (current.buildStatus === STATUS && duplicateRunId === runId) {
48
+ console.log(`App Builder status: ${current.buildStatus}`);
49
+ process.exit(0);
50
+ }
51
+ const allowedCurrentStatuses = STATUS === "building"
52
+ ? new Set(["preparing", "ready", "launch_failed", "failed"])
53
+ : STATUS === "verified_source_ready"
54
+ ? new Set(["building"])
55
+ : new Set(["preparing", "building"]);
56
+ if (!allowedCurrentStatuses.has(current.buildStatus)) {
57
+ console.error(
58
+ `Rudder rejected the stale App handoff transition ${current.buildStatus} -> ${STATUS}.`,
59
+ );
60
+ process.exit(1);
61
+ }
62
+ const response = await fetch(
63
+ endpoint,
64
+ {
65
+ method: "PATCH",
66
+ headers,
67
+ body: JSON.stringify({
68
+ status: STATUS,
69
+ expectedStatus: current.buildStatus,
70
+ runId,
71
+ runKind: STATUS === "verified_source_ready" ? "verification" : "build",
72
+ }),
73
+ },
74
+ );
75
+
76
+ if (!response.ok) {
77
+ const detail = await response.text();
78
+ console.error(`Rudder rejected the App handoff (${response.status}): ${detail.slice(0, 500)}`);
79
+ process.exit(1);
80
+ }
81
+
82
+ const app = await response.json();
83
+ console.log(`App Builder status: ${app.buildStatus}`);
@@ -1,13 +1,20 @@
1
1
  ---
2
2
  name: browser
3
- description: "Control Rudder's built-in Browser through the separate run-scoped rudder-browser MCP. Use for opening or showing pages, inspecting visible or interactive state, navigating, clicking, typing, testing localhost web apps, responsive checks, screenshots, dialogs, downloads, uploads, exports, console logs, clipboard, and page assets. Also use to list tabs already open in Rudder's built-in Browser."
3
+ description: "Control Rudder's built-in Browser through the separate run-scoped rudder-browser MCP, but invoke this skill only when the user explicitly mentions or selects Rudder's built-in Browser, Rudder Browser, or $browser. Use it then for opening or showing pages, inspecting visible or interactive state, navigating, clicking, typing, localhost testing, responsive checks, screenshots, dialogs, downloads, uploads, exports, console logs, clipboard, page assets, or listing tabs already open in Rudder's built-in Browser. Do not invoke it for generic web browsing, URL visits, web research, localhost testing, screenshots, or page interaction when the user has not explicitly chosen Rudder's built-in Browser."
4
4
  ---
5
5
 
6
6
  # Browser
7
7
 
8
- Use the Rudder Browser when the task depends on a rendered page or browser
9
- interaction. It may already share signed-in website state from the local Rudder
10
- Browser profile.
8
+ Use Rudder's built-in Browser only when the user explicitly names or selects
9
+ that surface, for example by saying `Rudder Browser`, `Rudder's built-in
10
+ Browser`, or `$browser`, or by referring to a page or tab already open there.
11
+ The request must identify the Rudder Browser as the intended surface; a generic
12
+ request to browse the web, visit a URL, research a site, test localhost, take a
13
+ screenshot, or interact with a page is not enough to invoke this skill.
14
+
15
+ When explicitly selected, the Browser may share signed-in website state from
16
+ the local Rudder Browser profile. If the user does not explicitly select it,
17
+ do not open, inspect, or interact with Rudder's Browser on the skill's behalf.
11
18
 
12
19
  The Browser is a separate optional integration named `rudder-browser`. Do not
13
20
  look for Browser tools inside `rudder-tools`, launch another browser,
@@ -1,7 +1,7 @@
1
1
  interface:
2
2
  display_name: "Browser"
3
3
  short_description: "Control and test pages in Rudder Browser"
4
- default_prompt: "Use $browser to inspect this page and interact through safe high-level refs or explicit coordinate CUA in Rudder's built-in Browser."
4
+ default_prompt: "Use $browser only when the user explicitly requests Rudder's built-in Browser; then inspect this page and interact through safe high-level refs or explicit coordinate CUA."
5
5
 
6
6
  dependencies:
7
7
  tools:
@@ -11,4 +11,4 @@ dependencies:
11
11
  transport: "stdio"
12
12
 
13
13
  policy:
14
- allow_implicit_invocation: true
14
+ allow_implicit_invocation: false
@@ -0,0 +1,22 @@
1
+ [
2
+ {
3
+ "query": "Use Rudder's built-in Browser to open https://example.com and report the page heading.",
4
+ "should_trigger": true
5
+ },
6
+ {
7
+ "query": "Use $browser to inspect the page already open in Rudder and take a screenshot.",
8
+ "should_trigger": true
9
+ },
10
+ {
11
+ "query": "Please browse https://example.com and report the page heading.",
12
+ "should_trigger": false
13
+ },
14
+ {
15
+ "query": "Open the local app at http://localhost:4173 and test its login form.",
16
+ "should_trigger": false
17
+ },
18
+ {
19
+ "query": "Take a screenshot of the current webpage and check whether the layout overlaps.",
20
+ "should_trigger": false
21
+ }
22
+ ]
@@ -134,8 +134,8 @@ Read only the reference needed for the request:
134
134
  installed CLI fallback catalog plus exact command semantics.
135
135
  3. [Agent creation](references/agent-creation.md) — permission-aware Agent
136
136
  configuration, governed hiring, approval, revision, and evidence workflow.
137
- 4. [Plugin authoring](references/plugin-authoring.md) — current scaffold,
138
- manifest, worker, UI, capability, route, and verification workflow.
137
+ 4. [Plugin authoring](references/plugin-authoring.md) — Codex-compatible
138
+ package layout, manifest, Skills, MCPs, Apps, and verification workflow.
139
139
  5. [Work practices](references/operating-practices.md) — exact
140
140
  conditional behavior for ownership, reviews, approvals, budgets,
141
141
  workspaces, Library handoff, authentication, and safe git use.
@@ -258,5 +258,45 @@
258
258
  "expected_public_path": "https://docs.rudderhq.dev/zh/reference/permissions-and-platforms",
259
259
  "expected_anchor": "boundaries",
260
260
  "illustrative_case_sufficient": false
261
+ },
262
+ {
263
+ "query": "How does Rudder build, review, approve, and sign Windows Desktop releases?",
264
+ "locale": "en",
265
+ "query_mode": "current",
266
+ "expected_source_class": "official_public_docs_primary",
267
+ "required_contract_ids": [],
268
+ "expected_public_path": "https://docs.rudderhq.dev/reference/code-signing-policy",
269
+ "expected_anchor": null,
270
+ "illustrative_case_sufficient": false
271
+ },
272
+ {
273
+ "query": "Rudder 如何构建、审查、批准并签名 Windows Desktop 发布产物?",
274
+ "locale": "zh",
275
+ "query_mode": "current",
276
+ "expected_source_class": "official_public_docs_primary",
277
+ "required_contract_ids": [],
278
+ "expected_public_path": "https://docs.rudderhq.dev/zh/reference/code-signing-policy",
279
+ "expected_anchor": null,
280
+ "illustrative_case_sufficient": false
281
+ },
282
+ {
283
+ "query": "Which Rudder data stays local and which optional services process data?",
284
+ "locale": "en",
285
+ "query_mode": "current",
286
+ "expected_source_class": "official_public_docs_primary",
287
+ "required_contract_ids": ["ANALYTICS.TELEMETRY.001"],
288
+ "expected_public_path": "https://docs.rudderhq.dev/reference/privacy",
289
+ "expected_anchor": null,
290
+ "illustrative_case_sufficient": false
291
+ },
292
+ {
293
+ "query": "哪些 Rudder 数据保留在本地,哪些可选服务会处理数据?",
294
+ "locale": "zh",
295
+ "query_mode": "current",
296
+ "expected_source_class": "official_public_docs_primary",
297
+ "required_contract_ids": ["ANALYTICS.TELEMETRY.001"],
298
+ "expected_public_path": "https://docs.rudderhq.dev/zh/reference/privacy",
299
+ "expected_anchor": null,
300
+ "illustrative_case_sufficient": false
261
301
  }
262
302
  ]
@@ -20,11 +20,11 @@
20
20
  "should_trigger": true
21
21
  },
22
22
  {
23
- "query": "Scaffold a new Rudder Plugin named @acme/quality-gate in a temporary external package directory. Verify the current create-rudder-plugin and SDK workflow first, then run its typecheck, tests, and build.",
23
+ "query": "Create a Codex-compatible Rudder Plugin named quality-gate in a temporary directory with one Skill. Verify plugin.json and the current import boundary, then test the package.",
24
24
  "should_trigger": true
25
25
  },
26
26
  {
27
- "query": "Rudder Plugin 的 worker capabilitysame-origin UIroutePath 和 ctx.assets 现在到底有哪些边界?请查当前 authoring guide、SDK 和源码后回答。",
27
+ "query": "Rudder Plugin 的 Codex packageSkillsMCP、App、导入检查和运行权限现在有哪些边界?请查当前 authoring guide 和源码后回答。",
28
28
  "should_trigger": true
29
29
  },
30
30
  {
@@ -246,8 +246,6 @@ or editing that URL by hand.
246
246
 
247
247
  - `GET /api/approvals/:approvalId`
248
248
  - `GET /api/approvals/:approvalId/issues`
249
- - `GET /api/approvals/:approvalId/comments`
250
- - `POST /api/approvals/:approvalId/comments`
251
249
  - `POST /api/approvals/:approvalId/request-revision`
252
250
  - `POST /api/approvals/:approvalId/resubmit`
253
251
  - `POST /api/approvals/:approvalId/approve`