Skip to content

BugReporter SDK

The BugReporter class is a TypeScript SDK that captures bug reports from your application and sends them to Mentu as memories. It handles evidence collection (screenshots, console errors, page context) and provides methods for tracking fix progress.

BugReporter is included in the main mentu package:

Terminal window
npm install mentu
import { BugReporter } from 'mentu';

Create a BugReporter instance with your workspace credentials:

const reporter = new BugReporter({
apiUrl: 'https://mentu-proxy.affihub.workers.dev/ops',
apiToken: 'your-api-token',
workspaceId: 'your-workspace-id',
projectDomains: ['app.example.com', 'staging.example.com'],
});
OptionTypeRequiredDescription
apiUrlstringYesThe Mentu proxy API endpoint.
apiTokenstringYesYour workspace API token.
workspaceIdstringYesThe UUID of your Mentu workspace.
projectDomainsstring[]NoDomains associated with this project. Used for the Project Match gate in triage.

Capture a bug memory and send it to Mentu.

const memory = await reporter.report(
'The login form rejects valid emails containing a + character',
{
severity: 'high',
page: '/login',
meta: {
screenshot: screenshotBase64,
consoleErrors: ['Uncaught TypeError: email.match is not a function'],
userAgent: navigator.userAgent,
url: window.location.href,
},
}
);
console.log(memory.id); // "mem_a8f3c21d..."
ParameterTypeRequiredDescription
bodystringYesThe bug description. Should include reproduction steps and expected vs. actual behavior.
options.severity'low' | 'medium' | 'high' | 'critical'NoBug severity. Affects triage scoring. Defaults to 'medium'.
options.pagestringNoThe page or route where the bug occurred.
options.tagsstring[]NoTags for categorization (e.g., ['ui', 'auth', 'mobile']).
options.metaobjectNoArbitrary metadata object. See Auto-Capture for common fields.
interface BugMemory {
id: string; // Mentu memory ID (e.g., "mem_a8f3c21d...")
workspaceId: string; // Workspace where the memory was created
createdAt: string; // ISO 8601 timestamp
status: string; // "open"
}

Get the current pipeline status for the workspace.

const status = await reporter.getStatus();
console.log(status.open); // 3
console.log(status.claimed); // 1
console.log(status.closed); // 27
interface PipelineStatus {
open: number; // Memories not yet committed
claimed: number; // Commitments currently being worked on
closed: number; // Commitments completed (pass or fail)
throughput: number; // Fixes per day (7-day rolling average)
}

Poll a commitment until it reaches a terminal state (pass or fail). Useful for integrations that need to block until a fix is shipped.

const result = await reporter.waitForCompletion('cmt_x9y8z7', 300000);
if (result.status === 'pass') {
console.log('Fix shipped:', result.evidence.pr.url);
} else {
console.log('Fix failed:', result.reason);
}
ParameterTypeRequiredDescription
commitmentIdstringYesThe Mentu commitment ID to watch.
timeoutnumberNoMaximum wait time in milliseconds. Defaults to 600000 (10 minutes).
interface CompletionResult {
status: 'pass' | 'fail';
commitmentId: string;
evidence: {
pr?: { url: string; number: number };
build?: { exitCode: number; durationMs: number };
review?: { verdict: string; passes: number };
};
reason?: string; // Present when status is 'fail'
closedAt: string; // ISO 8601 timestamp
totalDurationMs: number;
}

Throws a TimeoutError if the commitment does not close within the timeout period.

import { BugReporter } from 'mentu';
import { useRef, useCallback } from 'react';
const reporter = new BugReporter({
apiUrl: import.meta.env.VITE_MENTU_API_URL,
apiToken: import.meta.env.VITE_MENTU_API_TOKEN,
workspaceId: import.meta.env.VITE_MENTU_WORKSPACE_ID,
});
function BugReportButton() {
const handleReport = useCallback(async () => {
const description = prompt('Describe the bug:');
if (!description) return;
try {
const memory = await reporter.report(description, {
page: window.location.pathname,
meta: {
url: window.location.href,
userAgent: navigator.userAgent,
consoleErrors: getRecentConsoleErrors(),
timestamp: new Date().toISOString(),
},
});
alert(`Bug reported: ${memory.id}`);
} catch (err) {
console.error('Failed to report bug:', err);
}
}, []);
return <button onClick={handleReport}>Report Bug</button>;
}
import { BugReporter } from 'mentu';
const reporter = new BugReporter({
apiUrl: process.env.MENTU_API_URL!,
apiToken: process.env.MENTU_API_TOKEN!,
workspaceId: process.env.MENTU_WORKSPACE_ID!,
});
// Report a bug from a server-side error handler
app.use((err, req, res, next) => {
reporter.report(`Server error: ${err.message}`, {
severity: 'high',
page: req.originalUrl,
meta: {
stack: err.stack,
method: req.method,
statusCode: err.statusCode || 500,
userId: req.user?.id,
},
}).catch(console.error); // fire-and-forget
next(err);
});

The meta field on the options parameter is a freeform object. The following fields are recognized by the triage garbage filter and can improve scoring:

Meta FieldTypeDescription
screenshotstringBase64-encoded screenshot of the page at the time of the bug.
consoleErrorsstring[]Recent console.error messages captured from the browser.
urlstringFull URL where the bug was observed (including query params).
userAgentstringBrowser user-agent string.
viewport{ width: number, height: number }Browser viewport dimensions.
timestampstringISO 8601 timestamp of when the bug was observed.
userIdstringAuthenticated user ID (for correlating with server logs).
stackstringJavaScript stack trace if the bug triggered an exception.
networkErrorsobject[]Failed HTTP requests captured around the time of the bug.

These fields are optional. The BugReporter sends whatever you include — the triage agent uses recognized fields to improve filtering accuracy.