npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mullion/eslint-plugin

v0.2.3

Published

ESLint rules for type-safe LLM context management

Readme


Installation

npm install @mullion/eslint-plugin --save-dev

Overview

This ESLint plugin provides static analysis rules to catch context leaks and enforce confidence checking in Mullion applications. It helps prevent security vulnerabilities by detecting when LLM-generated values cross scope boundaries without proper bridging.

Why Use This?

LLM applications deal with data that crosses trust boundaries. Without static analysis, it's easy to accidentally:

  • Leak privileged data into public scopes (admin → customer)
  • Mix tenant data in multi-tenant systems
  • Use low-confidence outputs for critical decisions without validation
  • Lose audit trails when data flows between contexts

This plugin catches these issues at compile-time with zero runtime overhead.

What It Prevents

| Risk | Without Plugin | With Plugin | | -------------------- | --------------------------------- | --------------------- | | Context leaks | Discovered in production | Caught in IDE/CI | | Low confidence usage | Runtime errors or silent failures | Compile-time warnings | | Audit trail gaps | Manual code review needed | Automatic enforcement | | Security review time | Hours per PR | Seconds (automated) |

Real-World Impact

// ❌ Without plugin: This compiles but leaks admin data
let adminData;
await client.scope('admin', async (ctx) => {
  adminData = await ctx.infer(SecretSchema, sensitiveDoc);
});

await client.scope('public', async (ctx) => {
  return adminData.value; // BUG: No warning!
});

// ✅ With plugin: ESLint error prevents compilation
// "Context leak detected: 'adminData' crosses scope boundary"

Quick Setup

Flat Config (ESLint 9+)

// eslint.config.js
import mullion from '@mullion/eslint-plugin';

export default [
  {
    plugins: {
      '@mullion': mullion,
    },
    rules: {
      '@mullion/no-context-leak': 'error',
      '@mullion/require-confidence-check': 'warn',
    },
  },
];

Legacy Config (.eslintrc)

{
  "plugins": ["@mullion"],
  "rules": {
    "@mullion/no-context-leak": "error",
    "@mullion/require-confidence-check": "warn"
  }
}

Using Preset Configs

// Use recommended configuration
import mullion from '@mullion/eslint-plugin';

export default [
  ...mullion.configs.recommended
];

// Or use strict configuration
export default [
  ...mullion.configs.strict
];

Rules

no-context-leak (🚨 Error)

Prevents accidental context leaks when LLM-generated values cross scope boundaries without proper bridging.

❌ Incorrect

let leaked;

await client.scope('admin', async (ctx) => {
  leaked = await ctx.infer(Schema, 'secret data'); // 🚨 ESLint error
});

await client.scope('public', async (ctx) => {
  return leaked.value; // 🚨 ESLint error
});
await client.scope('scope-a', async (ctxA) => {
  const dataA = await ctxA.infer(Schema, input);

  await client.scope('scope-b', async (ctxB) => {
    return dataA.value; // 🚨 ESLint error - cross-scope usage
  });
});

✅ Correct

await client.scope('admin', async (adminCtx) => {
  const adminData = await adminCtx.infer(Schema, 'secret data');

  await client.scope('public', async (publicCtx) => {
    const bridged = publicCtx.bridge(adminData); // ✅ Explicit bridge
    return bridged.value;
  });
});
await client.scope('scope-a', async (ctxA) => {
  const dataA = await ctxA.infer(Schema, input);
  return ctxA.use(dataA); // ✅ Safe - same scope
});

require-confidence-check (⚠️ Warning)

Warns when LLM-generated values are used without checking their confidence scores.

❌ Triggers Warning

await client.scope('processing', async (ctx) => {
  const result = await ctx.infer(Schema, input);

  // ⚠️ ESLint warning - using value without confidence check
  if (result.value.category === 'important') {
    processImportantData(result.value);
  }

  return result.value; // ⚠️ ESLint warning
});

✅ Correct

await client.scope('processing', async (ctx) => {
  const result = await ctx.infer(Schema, input);

  // ✅ Check confidence before use
  if (result.confidence >= 0.8 && result.value.category === 'important') {
    processImportantData(result.value);
  }

  // ✅ Or use a handler function
  return handleResult(result); // Function receives full Owned object
});

Configuration

Rule Options

no-context-leak

{
  "@mullion/no-context-leak": ["error", {
    "allowBridge": true,    // Allow ctx.bridge() calls (default: true)
    "strictMode": false     // Stricter checking (default: false)
  }]
}

require-confidence-check

{
  "@mullion/require-confidence-check": ["warn", {
    "minConfidence": 0.8,      // Minimum confidence threshold
    "requireExplicit": false,  // Require explicit .confidence checks
    "allowHandlers": true      // Allow functions that handle Owned values
  }]
}

Preset Configurations

recommended

{
  rules: {
    '@mullion/no-context-leak': 'error',
    '@mullion/require-confidence-check': 'warn'
  }
}

strict

{
  rules: {
    '@mullion/no-context-leak': 'error',
    '@mullion/require-confidence-check': 'error' // More strict
  }
}

Examples

Real-World Violations

Customer Support Pipeline

// ❌ BAD: Customer data leaks to admin scope
let customerQuery;

await client.scope('customer', async (ctx) => {
  customerQuery = await ctx.infer(QuerySchema, userInput); // 🚨 Leak
});

await client.scope('admin', async (ctx) => {
  // This could expose customer PII to admin systems
  return analyzeWithAdminTools(customerQuery.value); // 🚨 Leak
});

// ✅ GOOD: Explicit bridging
await client.scope('customer', async (customerCtx) => {
  const query = await customerCtx.infer(QuerySchema, userInput);

  return await client.scope('admin', async (adminCtx) => {
    const bridged = adminCtx.bridge(query); // ✅ Tracked transfer
    return analyzeWithAdminTools(bridged.value);
  });
});

Multi-Tenant Data Processing

// ❌ BAD: Tenant data cross-contamination
const results = [];

for (const tenant of tenants) {
  await client.scope(`tenant-${tenant.id}`, async (ctx) => {
    const data = await ctx.infer(Schema, tenant.input);
    results.push(data); // 🚨 Mixing tenant scopes!
  });
}

// ✅ GOOD: Keep tenant data isolated
const results = [];

for (const tenant of tenants) {
  const result = await client.scope(`tenant-${tenant.id}`, async (ctx) => {
    const data = await ctx.infer(Schema, tenant.input);
    return ctx.use(data); // ✅ Extract safely within scope
  });
  results.push({tenantId: tenant.id, data: result});
}

Confidence Checking Patterns

❌ Common Anti-Patterns

// Direct value access without confidence check
const result = await ctx.infer(Schema, input);
const decision = result.value.decision; // ⚠️ Warning

// Implicit confidence in conditional
if (result.value.important) {
  // ⚠️ Warning
  processImportant();
}

✅ Good Patterns

// Explicit confidence checking
const result = await ctx.infer(Schema, input);

if (result.confidence >= 0.9) {
  const decision = result.value.decision; // ✅ Safe
}

// Handler function approach
function handleClassification(owned: Owned<Classification, string>) {
  if (owned.confidence < 0.8) {
    return escalateToHuman(owned);
  }
  return processAutomatically(owned.value);
}

const result = await ctx.infer(Schema, input);
handleClassification(result); // ✅ Handler receives full context

TypeScript Integration

The plugin leverages TypeScript's type system for accurate detection:

// The plugin understands scope types
type AdminData = Owned<Secret, 'admin'>;
type UserData = Owned<Public, 'user'>;

// It detects type mismatches
function processUserData(data: UserData) {
  /* ... */
}

const adminData: AdminData = await adminCtx.infer(SecretSchema, input);
processUserData(adminData); // 🚨 Type and scope mismatch detected

Troubleshooting

Common Issues

False Positives

If you get false positives, you might need to:

  1. Update TypeScript configuration:

    {
      "parserOptions": {
        "project": "./tsconfig.json"
      }
    }
  2. Ensure proper imports:

    import type {Owned, Context} from '@mullion/core';

Missing Violations

If leaks aren't being caught:

  1. Check TypeScript types are available
  2. Verify the plugin can access type information
  3. Ensure you're using the correct scope patterns

Debugging

Enable debug mode to see what the plugin is detecting:

DEBUG=@mullion/eslint-plugin eslint your-file.ts

Examples in Action

See the basic example which demonstrates both correct usage and intentional violations that ESLint catches.

Run the example:

cd examples/basic
npm install
npm run lint  # See violations caught
npm run demo  # See proper usage

Contributing

Found a bug or want to add a rule? See CONTRIBUTING.md for guidelines.

License

MIT - see LICENSE for details.