# @mushi-mushi/core

> Types, API client and pre-filter for Mushi SDKs. The bug mediator for AI-built apps: plain-English diagnosis + a ready fix, in your editor.

Latest version **1.28.0** (published 2026-09-13) · MIT license · 0 weekly downloads

## Install

```sh
npm install @mushi-mushi/core
pnpm add @mushi-mushi/core
yarn add @mushi-mushi/core
bun add @mushi-mushi/core
```

## Health

**Score 55/100 (C)** — status: active.

Positive: no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no types; no esm support.

## Facts

| | |
|---|---|
| Version | 1.28.0 |
| Published | 2026-09-13 |
| First published | 2026-04-16 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 3 |
| Author | Kenji Sakuramoto |
| Maintainers | kensaurus |
| Keywords | mushi-mushi, bug-translation, vibe-coding, ai-debugging, ai-triage, auto-fix, mcp, cursor, claude-code, sdk, core, types, api-client, session-replay, screenshot, sentry-companion, ai-agent |

## Links

- npm: https://www.npmjs.com/package/@mushi-mushi/core
- Repository: https://github.com/kensaurus/mushi-mushi
- Homepage: https://kensaur.us/mushi-mushi
- Issues: https://github.com/kensaurus/mushi-mushi/issues
- npm.io page: https://npm.io/package/@mushi-mushi/core

## Alternatives

- [@openai/codex-sdk](https://npm.io/package/@openai/codex-sdk.md) — 731.4K weekly downloads
- [babel-plugin-transform-react-jsx](https://npm.io/package/babel-plugin-transform-react-jsx.md) — 565.0K weekly downloads
- [babel-helper-remove-or-void](https://npm.io/package/babel-helper-remove-or-void.md) — 508.5K weekly downloads
- [@pnpm/store-controller-types](https://npm.io/package/@pnpm/store-controller-types.md) — 186.9K weekly downloads
- [react-native-signature-canvas](https://npm.io/package/react-native-signature-canvas.md) — 155.6K weekly downloads

## Recent versions

- 1.28.0 (latest) — 2026-09-13
- 1.27.2 — 2026-08-16
- 1.27.1 — 2026-08-09
- 1.27.0 — 2026-07-24
- 1.26.0 — 2026-07-16
- 1.25.0 — 2026-07-14
- 1.23.0 — 2026-07-07
- 1.22.5 — 2026-07-02
- 1.22.4 — 2026-07-01
- 1.22.2 — 2026-06-28
- 1.22.1 — 2026-06-25
- 1.22.0 — 2026-06-25
- 1.21.0 — 2026-06-23
- 1.20.2 — 2026-06-22
- 1.20.0 — 2026-06-21
- … 34 more at https://npm.io/package/@mushi-mushi/core/versions

## README

# @mushi-mushi/core

> **Your AI wrote it. Mushi tells you why it broke.**

Core types, API client, and shared utilities for every Mushi SDK package.

> **You almost certainly don't need to install this directly.** Run `npx mushi-mushi` and the wizard will pick the right framework SDK ([`@mushi-mushi/react`](https://npmjs.com/package/@mushi-mushi/react), [`@mushi-mushi/vue`](https://npmjs.com/package/@mushi-mushi/vue), [`@mushi-mushi/svelte`](https://npmjs.com/package/@mushi-mushi/svelte), [`@mushi-mushi/angular`](https://npmjs.com/package/@mushi-mushi/angular), [`@mushi-mushi/react-native`](https://npmjs.com/package/@mushi-mushi/react-native), [`@mushi-mushi/capacitor`](https://npmjs.com/package/@mushi-mushi/capacitor), or [`@mushi-mushi/web`](https://npmjs.com/package/@mushi-mushi/web)) which depends on this package.

## What's Inside

- **Types**: `MushiConfig`, `MushiReport`, `MushiEnvironment`, and all shared interfaces
- **API Client**: Fetch-based HTTP client with retry and exponential backoff. Tags every internal request with `X-Mushi-Internal: <kind>` so framework SDKs can filter their own traffic out of network capture and `apiCascade`. Ships HMAC-signed reporter helpers (`getLatestSdkVersion`, `listReporterReports`, `listReporterComments`, `replyToReporterReport`) for the two-way reply pipeline, plus `postDiscoveryEvent` (v2.1) for the passive inventory channel
- **Pre-Filter**: On-device Stage 0 spam/gibberish filter (runs client-side, zero server cost)
- **Offline Queue**: IndexedDB-backed queue with auto-sync on reconnect
- **Environment Capture**: Browser/device snapshot — viewport, user agent (with **User-Agent Client Hints** when supported), connection info, screen + DPR, accessibility prefs (`prefers-reduced-motion`, `prefers-color-scheme`, `prefers-contrast`), online/displayMode/title, and a one-shot **page load timing** read from `PerformanceNavigationTiming` (TTFB, DOMContentLoaded, FCP, LCP)
- **Reporter Token**: Anonymous persistent identity for report attribution
- **Session ID**: Tab-scoped session correlation
- **Rate Limiter**: Token bucket self-throttle to prevent API flooding
- **Breadcrumb Buffer** (1.0+ — `createBreadcrumbBuffer`): 50-entry ring of `{timestamp, category, level, message, data?}` rows; framework SDKs auto-capture route changes, `console.error/warn`, `[data-testid]` clicks, and SDK lifecycle events. Snapshot is attached to every `MushiReport` (server promotes it to a dedicated `reports.breadcrumbs` jsonb column for GIN-indexed filtering)
- **Exception Normaliser** (1.0+ — `normaliseThrown`): turns any thrown value (`Error`, string, plain object, `null`, `undefined`) into a stable `{ name, message, stack?, cause? }` shape with truncated stacks and cyclic-cause guards. Powers `Mushi.captureException()` in `@mushi-mushi/web`

## Public types added in 0.7 → 0.11

| Type                       | Purpose                                                                                       |
|----------------------------|-----------------------------------------------------------------------------------------------|
| `MushiPreset`              | Posture bundles: `'production-calm' \| 'beta-loud' \| 'internal-debug' \| 'manual-only'` plus the tiers `'minimal' \| 'standard' \| 'full'`. See [Config presets](#config-presets--precedence). |
| `MushiWidgetAnchor`        | Raw-CSS positioning (`top` / `right` / `bottom` / `left`) for the widget launcher.            |
| `MushiPrivacyConfig`       | `maskSelectors`, `blockSelectors`, `allowUserRemoveScreenshot` for screenshot redaction.       |
| `MushiUrlMatcher`          | `string \| RegExp` element used by `capture.ignoreUrls` and `apiCascade.ignoreUrls`.          |
| `MushiApiCascadeConfig`    | Object form of `proactive.apiCascade` so URL filters can be declared per-host-app.            |
| `MushiDiagnosticsResult`   | Return shape of `Mushi.diagnose()` (CSP, runtime-config, capture, widget health).             |
| `MushiSdkVersionInfo`      | Response shape for `getLatestSdkVersion(packageName)`; powers the outdated-banner UI.         |
| `MushiTimelineEntry`       | `{ ts, kind: 'route' \| 'click' \| 'request' \| 'log' \| 'screen', payload }` repro entries. |
| `MushiReporterReport`      | Reporter-facing report row (HMAC-authed) with `unread_count` for the widget badge.            |
| `MushiReporterComment`     | Reporter-facing comment row (HMAC-authed) tagged `author_kind: 'admin' \| 'reporter'`.        |
| `MushiDiscoverInventoryConfig` | Mushi v2.1 — fine-grained controls for `capture.discoverInventory` (`enabled`, `throttleMs`, `routeTemplates`, `userIdSource`, `captureDomSummary`). Pass `true` for defaults. |
| `MushiDiscoveryEventPayload`   | Mushi v2.1 — wire shape for `POST /v1/sdk/discovery`. Mirrored server-side by `_shared/schemas.ts::discoveryEventSchema`; route + page title + testids + network paths + query-param **keys only** + sha256 user id hash. |
| `MushiBreadcrumb`              | 1.0+ — `{ timestamp, category, level: 'debug' \| 'info' \| 'warning' \| 'error' \| 'critical', message, data? }`. Mirrors the Sentry breadcrumb shape so the admin can interleave Mushi + Sentry breadcrumbs on one timeline. |
| `MushiSentryContext`           | 1.0+ — rich Sentry handshake the SDK captures via `@sentry/browser` v7/v8/v9: `eventId`, `replayId`, `traceId`, `spanId`, `transaction`, `release`, `environment`, `user`, `tags`, `breadcrumbs`, `issueUrl`, `mushiReportId` (bidirectional). |
| `MushiCaptureExceptionOptions` | 1.0+ — options for `Mushi.captureException(err, opts)`: `level`, `tags`, `extras`, `category`, `userIntent` overrides for the structured report. |
| `NormalisedException`          | 1.0+ — return type of `normaliseThrown(err)` (`{ name, message, stack?, cause? }`); used internally by `captureException` and exposed for adapters that want to ship their own thin wrappers. |
| `MushiBannerLink`              | 1.8+ — flat action on the rich banner layout: `{ label, href? }` opens an external URL in a new tab, `{ label, featureRequest: true }` opens the widget in feature-request mode. Consumed via `MushiBannerConfig.links`. |
| `screenshotSensitiveHint` (on `MushiWidgetConfig`) | 1.19+ — privacy caption under the screenshot preview: `true` = localized default, `string` = custom copy, `false` = hide caption (preview + Remove remain). Console-configurable via `GET /v1/sdk/config`. See [`docs/SDK_SCREENSHOT_PREVIEW.md`](../../docs/SDK_SCREENSHOT_PREVIEW.md). |

Constants: `MUSHI_INTERNAL_HEADER` (`'X-Mushi-Internal'`),
`MUSHI_INTERNAL_INIT_MARKER`, and the `MushiInternalRequestKind` literal union
are re-exported so framework adapters can build their own self-noise filters.

## Config presets & precedence

Pass `preset` to pick a posture bundle instead of hand-assembling
`widget` / `capture` / `proactive` flags. `expandPreset(config)` expands the
preset into those nested objects; **your explicit config always wins** on every
key (the merge is per-sub-object, so overriding one `capture` flag keeps the
rest of the preset's defaults).

| Field                | `minimal`      | `standard`         | `full`           |
|----------------------|----------------|--------------------|------------------|
| Widget               | on (`auto`)    | on (SDK default)   | on (`auto`)      |
| `capture.console`    | ✅              | default            | ✅                |
| `capture.network`    | ❌              | default            | ✅                |
| `capture.performance`| ❌              | default            | ✅                |
| `capture.screenshot` | `on-report`    | default            | `auto`           |
| `capture.replay`     | `off`          | default            | `lite`           |
| Proactive triggers   | none           | default            | all on           |

- **`minimal`** — widget + console capture only, screenshot on report; no
  network/performance/replay, no proactive nudges. Leanest footprint.
- **`standard`** — today's SDK defaults. Expansion is a **no-op** (the config
  is returned untouched); the preset exists so the intent is explicit and
  documented.
- **`full`** — every capture channel on (including a self-contained `lite`
  session replay) and all proactive triggers. Loudest / most data.

The four legacy postures — `production-calm`, `beta-loud`, `internal-debug`,
`manual-only` — are still supported and expand the same way.

### Precedence

Highest wins. `resolveEnvConfig()` only ever supplies
`projectId` / `apiKey` / `apiEndpoint`, so it never competes with a preset for
the nested option objects.

| Priority | Source                              | Example                                   |
|----------|-------------------------------------|-------------------------------------------|
| 1 (wins) | Explicit config                     | `capture: { network: true }`              |
| 2        | `preset`                            | `preset: 'minimal'` → `network: false`    |
| 3        | Environment variables               | `NEXT_PUBLIC_MUSHI_*` / `VITE_MUSHI_*`    |
| 4        | SDK defaults                        | built-in fallbacks                        |

### Sampling & `beforeSend`

Top-level `MushiConfig` fields (consumed by `@mushi-mushi/web` and framework wrappers):

| Field | Default | Behavior |
|-------|---------|----------|
| `sampleRate` | `1` | Probabilistic gate for **automatic** error reports (`0`–`1`). User-initiated feedback always sends. |
| `replaySampleRate` | `1` | Probabilistic gate for session replay; decided once at session init. Independent of `sampleRate`. |
| `replaysOnErrorSampleRate` | `0` | Start a replay buffer on automatic errors when session sample missed. Keep `0` unless you explicitly want rrweb. |
| `tunnel` | — | Same-origin ingest base (e.g. `/api/mushi-tunnel`). Wins over `apiEndpoint` so browser calls stay first-party. Pagehide uses `fetch` keepalive, then a `{ mushiBeacon, path, headers, body }` envelope because `sendBeacon` cannot set headers. |
| `ignoreErrors` / `denyUrls` / `allowUrls` | — | Drop **automatic** captures only. Never applied to user widget feedback. |
| `beforeSend` | — | `(report) => report \| null \| Promise<…>` after built-in PII scrub. Return `null` to drop. |
| `beforeSendFeedback` | — | Deprecated feedback-only hook; ignored when `beforeSend` is set. |

### Validation

`validateConfig(config)` runs at init and **fails loud but never throws**: it
`console.error`s on unknown top-level keys (usually a typo) and on an invalid
`preset` value, then continues. Set `MUSHI_SILENT=1` to suppress the warnings.

```typescript
import { expandPreset, validateConfig } from '@mushi-mushi/core';

validateConfig(config);              // warns on typos / bad preset (never throws)
const resolved = expandPreset(config); // preset → nested objects, explicit wins
```

## Usage

```typescript
import {
  createApiClient,
  createPreFilter,
  captureEnvironment,
  createRateLimiter,
  MUSHI_INTERNAL_HEADER,
} from '@mushi-mushi/core';
```

This package is used internally by `@mushi-mushi/web` and `@mushi-mushi/react`. Most consumers should use those packages instead.

## Bundle Size

~3.15 KB brotli (limit: 15 KB)

## License

MIT


<!-- mushi-readme-stats-footer -->
---

<sub>Monorepo scale (July 2026): 58 edge functions · 347 SQL migrations · 13 outbound plugins · 11 inbound adapters · 19 pipeline agents. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>

---
_Source: https://npm.io/package/@mushi-mushi/core · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
