> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/thedotmack/claude-mem/llms.txt
> Use this file to discover all available pages before exploring further.

# Development

> Build Claude Mem from source, run tests, manage the worker service, and contribute to the project.

## Prerequisites

<CardGroup cols={3}>
  <Card title="Node.js ≥ 18" icon="node-js">
    Required to build and run the project. Check with `node --version`.
  </Card>

  <Card title="Bun ≥ 1.0" icon="bolt">
    Manages the worker service and runs tests. Auto-installed if missing.
  </Card>

  <Card title="Git" icon="code-branch">
    Required to clone and contribute to the repository.
  </Card>
</CardGroup>

***

## Building from source

<Steps>
  <Step title="Clone the repository">
    ```bash theme={null}
    git clone https://github.com/thedotmack/claude-mem.git
    cd claude-mem
    ```
  </Step>

  <Step title="Install dependencies">
    ```bash theme={null}
    npm install
    ```
  </Step>

  <Step title="Build all components">
    ```bash theme={null}
    npm run build
    ```
  </Step>
</Steps>

### What the build produces

The build uses esbuild to compile TypeScript into several output formats:

| Output                                         | Format              | Location                            |
| ---------------------------------------------- | ------------------- | ----------------------------------- |
| Hook scripts (`*-hook.js`, `smart-install.js`) | ESM                 | `plugin/scripts/`                   |
| Worker service                                 | CJS                 | `plugin/scripts/worker-service.cjs` |
| MCP search server                              | CJS                 | `plugin/scripts/mcp-server.cjs`     |
| Web viewer UI                                  | Self-contained HTML | `plugin/ui/viewer.html`             |

### Build commands

<CodeGroup>
  ```bash Build everything theme={null}
  npm run build
  ```

  ```bash Build and sync to installed plugin theme={null}
  npm run build-and-sync
  ```

  ```bash Build only hooks theme={null}
  npm run build:hooks
  ```
</CodeGroup>

`build-and-sync` is the standard development command — it builds, syncs to the marketplace install location, and restarts the worker in one step.

***

## Source layout

```
src/
├── hooks/           # Hook entry points and logic
├── services/        # Worker service, database, and sync
│   └── sqlite/      # SQLite schema, migrations, search
├── servers/         # MCP search server
├── sdk/             # Claude Agent SDK integration
├── shared/          # Shared utilities
├── ui/
│   └── viewer/      # React web viewer components
└── utils/           # General utilities
```

***

## Development workflow

<Steps>
  <Step title="Make changes">
    Edit TypeScript source files in `src/`.
  </Step>

  <Step title="Build and sync">
    ```bash theme={null}
    npm run build-and-sync
    ```

    This builds, copies to the installed plugin, and restarts the worker.
  </Step>

  <Step title="Test manually">
    Start a Claude Code session to test the feature end-to-end, or run hooks directly (see [Manual hook testing](#manual-hook-testing) below).
  </Step>

  <Step title="Check logs">
    ```bash theme={null}
    npm run worker:logs
    ```
  </Step>

  <Step title="Iterate">
    Repeat until the feature works as expected.
  </Step>
</Steps>

***

## Running tests

Claude Mem uses Bun's built-in test runner. Tests are organized by component.

### Test commands

<CodeGroup>
  ```bash Run all tests theme={null}
  npm test
  ```

  ```bash SQLite and database tests theme={null}
  npm run test:sqlite
  ```

  ```bash Agent processing tests theme={null}
  npm run test:agents
  ```

  ```bash Search tests theme={null}
  npm run test:search
  ```

  ```bash Context injection tests theme={null}
  npm run test:context
  ```

  ```bash Infrastructure tests theme={null}
  npm run test:infra
  ```

  ```bash Server tests theme={null}
  npm run test:server
  ```
</CodeGroup>

### Testing philosophy

Claude Mem prioritizes manual and integration testing over traditional unit tests, because:

* Hook behavior depends on Claude Code's runtime environment
* SDK interactions require real API calls
* Integration issues that unit tests miss are common at system boundaries

The preferred testing approach is:

1. Build and sync changes
2. Test in a real Claude Code session
3. Inspect the database to verify data correctness
4. Monitor worker logs

### Manual hook testing

Run hooks directly with test input to verify behavior without starting a full Claude Code session:

```bash theme={null}
# Test context hook (SessionStart)
node plugin/scripts/bun-runner.js plugin/scripts/worker-service.cjs hook claude-code context

# Test session-init hook (UserPromptSubmit)
node plugin/scripts/bun-runner.js plugin/scripts/worker-service.cjs hook claude-code session-init

# Test observation hook (PostToolUse)
node plugin/scripts/bun-runner.js plugin/scripts/worker-service.cjs hook claude-code observation
```

### Health checks

```bash theme={null}
# Worker status
npm run worker:status

# Queue inspection
curl http://localhost:37777/api/pending-queue

# Database integrity
sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"
```

### Data verification

```bash theme={null}
# Check recent observations
sqlite3 ~/.claude-mem/claude-mem.db "
  SELECT id, tool_name, created_at
  FROM observations
  ORDER BY created_at_epoch DESC
  LIMIT 10;
"

# Check summaries
sqlite3 ~/.claude-mem/claude-mem.db "
  SELECT id, request, completed
  FROM session_summaries
  ORDER BY created_at_epoch DESC
  LIMIT 5;
"
```

***

## Worker management commands

The worker service runs as a background Bun process on port `37777`.

<CodeGroup>
  ```bash Start theme={null}
  npm run worker:start
  ```

  ```bash Stop theme={null}
  npm run worker:stop
  ```

  ```bash Restart theme={null}
  npm run worker:restart
  ```

  ```bash Check status theme={null}
  npm run worker:status
  ```

  ```bash View logs theme={null}
  npm run worker:logs
  ```
</CodeGroup>

### Queue management

```bash theme={null}
# Check pending queue status
npm run queue

# Process pending queue automatically
npm run queue:process

# Clear failed queue entries
npm run queue:clear
```

***

## Viewer UI development

The web viewer is a React application built into a self-contained `viewer.html` bundle.

**Source location**: `src/ui/viewer/`

```
src/ui/viewer/
├── index.tsx              # Entry point
├── App.tsx                # Root component
├── components/
│   ├── Header.tsx
│   ├── Sidebar.tsx
│   ├── Feed.tsx
│   └── cards/
│       ├── ObservationCard.tsx
│       ├── PromptCard.tsx
│       ├── SummaryCard.tsx
│       └── SkeletonCard.tsx
├── hooks/
│   ├── useSSE.ts          # Server-Sent Events
│   ├── usePagination.ts   # Infinite scroll
│   ├── useSettings.ts     # Settings persistence
│   └── useStats.ts        # Database statistics
└── utils/
    ├── constants.ts
    ├── formatters.ts
    └── merge.ts
```

<Warning>
  Hot reload is not supported. Every change requires a full rebuild and worker restart before you can see updates in the browser.
</Warning>

**Viewer update workflow:**

```bash theme={null}
npm run build
npm run sync-marketplace
npm run worker:restart
# Refresh browser at http://localhost:37777
```

### Adding a new card type

<Steps>
  <Step title="Create the component">
    ```tsx theme={null}
    // src/ui/viewer/components/cards/YourCard.tsx
    import React from 'react';

    export interface YourCardProps {
      // define your data structure
    }

    export const YourCard: React.FC<YourCardProps> = (props) => {
      return (
        <div className="card">
          {/* your UI */}
        </div>
      );
    };
    ```
  </Step>

  <Step title="Register in Feed.tsx">
    ```tsx theme={null}
    import { YourCard } from './cards/YourCard';

    // In render logic:
    {item.type === 'your_type' && <YourCard {...item} />}
    ```
  </Step>

  <Step title="Update types if needed">
    Add your data shape to `src/ui/viewer/types.ts`.
  </Step>

  <Step title="Rebuild and test">
    ```bash theme={null}
    npm run build-and-sync
    ```
  </Step>
</Steps>

***

## Adding new features

### Adding a new hook

<Steps>
  <Step title="Create the hook implementation">
    ```typescript theme={null}
    // src/hooks/your-hook.ts
    import { readStdin } from '../shared/stdin';

    async function main() {
      const input = await readStdin();

      // Hook implementation
      const result = {
        hookSpecificOutput: 'optional output'
      };

      console.log(JSON.stringify(result));
    }

    main().catch(console.error);
    ```

    <Note>
      As of v4.3.1, hooks are self-contained files. The shebang line is added automatically by esbuild during the build.
    </Note>
  </Step>

  <Step title="Register in hooks.json">
    ```json theme={null}
    {
      "YourHook": [{
        "hooks": [{
          "type": "command",
          "command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/your-hook.js",
          "timeout": 120
        }]
      }]
    }
    ```
  </Step>

  <Step title="Rebuild">
    ```bash theme={null}
    npm run build
    ```
  </Step>
</Steps>

### Modifying the database schema

<Steps>
  <Step title="Add a migration">
    ```typescript theme={null}
    // src/services/sqlite/migrations.ts
    export const migration011: Migration = {
      version: 11,
      up: (db: Database) => {
        db.run(`
          ALTER TABLE observations ADD COLUMN new_field TEXT;
        `);
      }
    };
    ```
  </Step>

  <Step title="Update types">
    ```typescript theme={null}
    // src/services/sqlite/types.ts
    export interface Observation {
      // ... existing fields
      new_field?: string;
    }
    ```
  </Step>

  <Step title="Update database methods">
    ```typescript theme={null}
    // src/services/sqlite/SessionStore.ts
    createObservation(obs: Observation) {
      // include new_field in INSERT
    }
    ```
  </Step>

  <Step title="Test with a database backup">
    ```bash theme={null}
    cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup
    npm test
    ```
  </Step>
</Steps>

***

## Debugging

### Enable debug logging

```bash theme={null}
export DEBUG=claude-mem:*
npm run worker:restart
npm run worker:logs
```

### Inspect the database

```bash theme={null}
sqlite3 ~/.claude-mem/claude-mem.db

# View schema
.schema observations

# Recent activity
SELECT created_at, tool_name FROM observations ORDER BY created_at DESC LIMIT 10;

# Table counts
SELECT 'sessions', COUNT(*) FROM sdk_sessions
UNION ALL SELECT 'observations', COUNT(*) FROM observations
UNION ALL SELECT 'summaries', COUNT(*) FROM session_summaries;
```

### Trace observations by session

```bash theme={null}
sqlite3 ~/.claude-mem/claude-mem.db "
  SELECT correlation_id, tool_name, created_at
  FROM observations
  WHERE session_id = 'YOUR_SESSION_ID'
  ORDER BY created_at;
"
```

***

## Code style

<AccordionGroup>
  <Accordion title="TypeScript guidelines">
    * Use strict mode
    * Define interfaces for all data structures
    * Use `async`/`await` for asynchronous code
    * Handle errors explicitly with try/catch
    * Add JSDoc comments for public APIs
  </Accordion>

  <Accordion title="Formatting">
    * 2-space indentation
    * Single quotes for strings
    * Trailing commas in objects and arrays
    * Follow the existing code style in the file you're editing
  </Accordion>

  <Accordion title="Example: well-typed function">
    ```typescript theme={null}
    /**
     * Create a new observation in the database
     */
    export async function createObservation(
      obs: Observation
    ): Promise<number> {
      try {
        const result = await db.insert('observations', {
          session_id: obs.session_id,
          tool_name: obs.tool_name,
        });
        return result.id;
      } catch (error) {
        logger.error('Failed to create observation', error);
        throw error;
      }
    }
    ```
  </Accordion>
</AccordionGroup>

***

## Bug reports

Generate a bug report with system diagnostics:

```bash theme={null}
npm run bug-report
```

This collects worker status, recent logs, database statistics, and environment information to include when filing a GitHub issue.

***

## Contributing

### Workflow

<Steps>
  <Step title="Fork and branch">
    ```bash theme={null}
    git checkout -b feature/your-feature-name
    ```
  </Step>

  <Step title="Make changes">
    Edit source files in `src/`. Follow the code style guidelines above.
  </Step>

  <Step title="Test">
    Run `npm test` and verify your feature manually in a Claude Code session.
  </Step>

  <Step title="Update documentation">
    Update relevant MDX files in `docs/public/` if your change affects user-facing behavior.
  </Step>

  <Step title="Commit and push">
    ```bash theme={null}
    git commit -m 'feat: add your feature'
    git push origin feature/your-feature-name
    ```
  </Step>

  <Step title="Open a pull request">
    Open a PR against `main`. Include a clear description of what changed and why.
  </Step>
</Steps>

### Pull request checklist

* Clear title describing what the PR does
* Description explaining why the change is needed
* Tests for new functionality
* Documentation updated where applicable
* Entry added to `CHANGELOG.md`
* TypeScript compiles without errors (`npx tsc --noEmit`)

***

## Releasing

<Steps>
  <Step title="Bump the version">
    Update the version in:

    * `package.json`
    * `plugin/.claude-plugin/plugin.json`
    * `CLAUDE.md` header
    * `README.md` version badge
  </Step>

  <Step title="Build and sync">
    ```bash theme={null}
    npm run build && npm run sync-marketplace
    ```
  </Step>

  <Step title="Commit and tag">
    ```bash theme={null}
    git add .
    git commit -m "chore: release v4.3.2"
    git tag v4.3.2
    git push origin main --tags
    ```
  </Step>

  <Step title="Publish to npm">
    ```bash theme={null}
    npm run release
    ```

    The `release` script runs tests, builds all components, and publishes to the npm registry.
  </Step>
</Steps>

<Note>
  The changelog is generated automatically — do not edit `CHANGELOG.md` manually.
</Note>
