Extend the evidence loop

Extend the evidence loop without forking it.

Use the SDK and plugins to add custom auth, clients, assertions, secrets, traces, and domain-specific runtimes while keeping the same evidence model across local, CI, and Cloud.

repo-native TypeScriptruntime guardrailsshared configure() runtimeone evidence model

Use SDK when

Your verification needs are specific, but the result still needs to be readable by agents, CI, and Cloud.

your auth is customyour API client is internalyour assertions are domain-specificyour data setup is complexyour redaction rules are strictyour runtime needs browser, GraphQL, gRPC, or queue behavior

Keep code reviewable

Agents write plain TypeScript your team can review, refactor, debug, and keep in the repo.

Expose your runtime surface

Expose GraphQL, browser steps, auth helpers, or internal clients without teaching agents a second system.

Keep execution consistent

Local runs, CI, browser steps, and Cloud share the same runtime, trace model, and verification structure.

Why the runtime matters

The core SDK gives agents the parts that make tests auditable: requests, assertions, secrets, templating, structured traces, and useful failure diffs. Plugins add scope without removing those evidence surfaces.

products.test.ts
import { test } from "@glubean/sdk";

test("list products", async (ctx) => {
  const base = ctx.vars.require("BASE_URL");

  const data = await ctx.http
    .get(`${base}/products?limit=5`)
    .json();

  ctx.expect(data.products.length).toBe(5);
  ctx.log(`Found ${data.total} products`);
});
Core: Auto-traced HTTP requests with timing and status
Core: Template variables and secrets resolved per environment
Core: Structured assertions with useful diffs on failure
Core: Shared helpers that stay plain TypeScript
Core: Secrets auto-redacted before upload to Cloud

Why plugins matter

Use official packages when they fit, then add your own organization-specific capabilities without leaving the shared runtime. The point is not a pile of adapters. The point is one runtime that keeps evidence consistent as it absorbs more of your stack.

@glubean/graphql

Keep GraphQL queries and mutations inside the same traced evidence loop you already use for HTTP.

@glubean/browser

Extend evidence-backed verification into Puppeteer-powered browser steps without losing structure.

@glubean/grpc

Typed gRPC client with proto-first DX, full trace and metadata capture out of the box.

@glubean/auth

OAuth, API key, and custom auth flows as a shared plugin — configure once, use everywhere.

Your own plugin

Wrap internal services, auth flows, or domain helpers as shared capabilities for the whole team.

GraphQL stays inside the same trace model

users.test.ts
import { test, configure } from "@glubean/sdk";
import { graphql } from "@glubean/graphql";

const { gql } = configure({
  plugins: {
    gql: graphql({
      endpoint: "{{GRAPHQL_URL}}",
      headers: { Authorization: "Bearer {{API_KEY}}" },
    }),
  },
});

export const getUser = test("get-user", async (ctx) => {
  const { data } = await gql.query<{ user: { name: string } }>(`
    query GetUser($id: ID!) {
      user(id: $id) { name email }
    }
  `, { variables: { id: "1" } });

  ctx.expect(data?.user.name).toBe("Alice");
});

Browser steps stay inside the same evidence loop

login.test.ts
import { test, configure } from "@glubean/sdk";
import { browser } from "@glubean/browser";

const { chrome } = configure({
  plugins: { chrome: browser({ launch: true }) },
});

const ui = test.extend({
  page: async (ctx, use) => {
    const pg = await chrome.newPage(ctx);
    try { await use(pg); }
    finally { await pg.close(); }
  },
});

export const login = ui("login-flow", async (ctx) => {
  await ctx.page.goto("/login");
  await ctx.page.type("#email", "user@test.com");
  await ctx.page.type("#password", "secret");
  await ctx.page.clickAndNavigate('button[type="submit"]');
  await ctx.page.expectURL("/dashboard");
  await ctx.page.expectText("h1", "Welcome back");
});

Why custom plugins matter

Wrap an internal service client, auth helper, or domain-specific primitive once, then expose it as a shared capability. This is the difference between a convenient test file and a testing system that compounds.

payments-plugin.ts
import { definePlugin, configure, test } from "@glubean/sdk";

const payments = (opts: { baseUrlKey: string }) =>
  definePlugin((runtime) => {
    const client = runtime.http.extend({
      prefixUrl: runtime.requireVar(opts.baseUrlKey),
      headers: {
        Authorization: `Bearer ${runtime.requireSecret("STRIPE_KEY")}`,
      },
    });
    return {
      charge: (amount: number) =>
        client.post("charges", { json: { amount } }).json(),
      refund: (id: string) =>
        client.post(`charges/${id}/refund`).json(),
    };
  });

const { pay } = configure({
  plugins: { pay: payments({ baseUrlKey: "PAYMENTS_URL" }) },
});

export const chargeAndRefund = test("charge-refund", async (ctx) => {
  const charge = await pay.charge(2500);
  ctx.expect(charge.status).toBe("succeeded");

  const refund = await pay.refund(charge.id);
  ctx.expect(refund.status).toBe("refunded");
});
Plugins receive runtime context, including vars, secrets, and the traced HTTP client
Initialization stays lazy, so setup cost lands only when the plugin is used
Types flow through configure() without casts or wrapper DSLs
Official and custom plugins compose into one runtime for the whole evidence loop

Why one runtime matters

Official packages and custom plugins join in one configure() call. That keeps the evidence surface consistent across local runs, CI, and Cloud.

configure.ts
const { gql, chrome, pay } = configure({
  plugins: {
    gql:    graphql({ endpoint: "{{GQL_URL}}" }),
    chrome: browser({ launch: true }),
    pay:    payments({ baseUrlKey: "PAY_URL" }),
  },
});
Shared auth, clients, and plugin setup live in one place
Test files stay small because heavy setup moves into configure()
The same runtime can power extension authoring, CI runs, and Cloud diagnosis

Runtime note: Node.js, plugin-friendly

Glubean runs on Node.js with native TypeScript support — no build step required. The entire npm ecosystem is available, so any package you already use works out of the box. The practical rule is simple: if you can import it, it is a good plugin candidate. When you need heavier browser coverage, keep Playwright where it fits and use Glubean where shared proof and evidence matter more.