integrations

LangChain

Wrap LangChain tools with brin before they clone repos, fetch pages, or install packages

LangChain tools are regular functions behind a tool interface. That means you can make brin part of the tool path itself: check the artifact first, then run the external action only when the verdict allows it.

##How it works

Put a shared brin helper in front of any DynamicStructuredTool or tool() callback that reaches outside your system. That keeps the enforcement deterministic even if the model ignores natural-language guidance.

##Setup

1. Add a shared helper:

TypeScript
type BrinVerdict = "safe" | "caution" | "suspicious" | "dangerous";
 
async function assertBrinAllowed(
  path: string,
  allowed: BrinVerdict[],
): Promise<void> {
  let response: Response;
 
  try {
    response = await fetch(`https://api.brin.sh/${path}`);
  } catch {
    return;
  }
 
  if (!response.ok) {
    return;
  }
 
  const verdict = response.headers.get("x-brin-verdict") as BrinVerdict | null;
  const score = response.headers.get("x-brin-score");
 
  if (verdict && !allowed.includes(verdict)) {
    throw new Error(
      `brin blocked ${path}: verdict=${verdict} score=${score ?? "unknown"}`,
    );
  }
}

2. Guard external tools before they run:

TypeScript
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
 
async function cloneRepo(owner: string, repo: string) {
  // Replace this with your existing clone or sync path.
  return { owner, repo, queued: true };
}
 
export const cloneRepository = new DynamicStructuredTool({
  name: "clone_repository",
  description: "Clone a repository after brin approves it",
  schema: z.object({
    owner: z.string(),
    repo: z.string(),
  }),
  func: async ({ owner, repo }) => {
    await assertBrinAllowed(`repo/${owner}/${repo}`, ["safe"]);
    return JSON.stringify(await cloneRepo(owner, repo));
  },
});
 
export const readPage = new DynamicStructuredTool({
  name: "read_page",
  description: "Fetch a web page after brin approves it",
  schema: z.object({
    url: z.string().url(),
  }),
  func: async ({ url }) => {
    const target = new URL(url);
    const pagePath = `page/${target.host}${target.pathname}`;
 
    await assertBrinAllowed(pagePath, ["safe", "caution"]);
 
    const response = await fetch(url);
    return await response.text();
  },
});

##Extending the pattern

Apply the same helper to every tool that handles untrusted context:

  • package install tools: npm/<package>, pypi/<package>, crate/<package>
  • repo readers and cloners: repo/<owner>/<repo>
  • browsing or scraping tools: domain/<domain> or page/<domain/path>
  • MCP and skill loaders: mcp/<owner>/<repo> and skill/<owner>/<repo>

If you use LangChain's tool() helper instead of DynamicStructuredTool, keep the same pattern: call brin first inside the tool function, then execute the side effect.