# Contributing

> Dev setup with openclaw plugins install --link, test scripts (vitest), build targets, commit conventions, and PR expectations.

- Repository: TencentCloud/TencentDB-Agent-Memory
- GitHub: https://github.com/TencentCloud/TencentDB-Agent-Memory
- Human docs: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-14fefdd76c97
- Complete Markdown: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-14fefdd76c97/llms-full.txt

## Source Files

- `CONTRIBUTING.md`
- `package.json`
- `vitest.config.ts`
- `vitest.e2e.config.ts`
- `.github/workflows/pr-ci.yml`
- `CHANGELOG.md`

---

---
title: "Contributing"
description: "Dev setup with openclaw plugins install --link, test scripts (vitest), build targets, commit conventions, and PR expectations."
---

Local development for `@tencentdb-agent-memory/memory-tencentdb` is a **link-from-source** OpenClaw plugin workflow: install dependencies, register the repo with `openclaw plugins install --link .`, edit TypeScript under `index.ts` / `src/`, and restart the Gateway. Runtime loads `.ts` directly (Node ≥ 22.16.0 type stripping); packaging and package bins use separate `npm run build*` targets. Pull requests target `main`, require DCO `Signed-off-by`, and are gated by `.github/workflows/pr-ci.yml` (install, pack, manifest, size).

## Prerequisites

| Requirement | Constraint |
|-------------|------------|
| Node.js | `>=22.16.0` (`package.json` `engines`) |
| Package manager | `npm` or `pnpm` |
| OpenClaw (for plugin host loop) | `>=2026.3.13` (CONTRIBUTING; plugin `openclaw.compat.pluginApi` / `minGatewayVersion`) |
| Peer (optional) | `openclaw` `>=2026.3.7`, `node-llama-cpp` `^3.16.2` |

CI runners use Node **22** and `npm install --ignore-scripts`.

## Develop from source

OpenClaw loads plugin TypeScript from the linked directory. No plugin rebuild is required between edits.

<Steps>
  <Step title="Clone and install">
```bash
git clone https://github.com/Tencent/TencentDB-Agent-Memory.git
cd TencentDB-Agent-Memory
npm install
```
  </Step>
  <Step title="Link the plugin into OpenClaw">
```bash
openclaw plugins install --link .
```
`install --link` registers the **current directory** as a local plugin. Source changes apply after a Gateway restart.
  </Step>
  <Step title="Iterate">
1. Edit `index.ts`, `src/**`, `openclaw.plugin.json`, or `hermes-plugin/` as needed.
2. Restart the OpenClaw Gateway.
3. Confirm load via Gateway / plugin logs tagged `[memory-tdai]` and your usual smoke path (`tdai_memory_search` / capture).
  </Step>
</Steps>

<Note>
`postinstall` runs `scripts/openclaw-after-tool-call-messages.patch.sh` (errors swallowed). Local `npm install` may attempt that host patch; CI deliberately uses `--ignore-scripts`.
</Note>

### Repository layout (contribution hotspots)

```text
├── index.ts                 # OpenClaw plugin shell (tools, hooks, TdaiCore wiring)
├── openclaw.plugin.json     # Plugin id, contracts, configSchema
├── package.json             # Scripts, engines, openclaw metadata, bins
├── tsdown.config.ts         # Plugin ESM bundle → dist/
├── vitest.config.ts         # Unit tests
├── vitest.e2e.config.ts     # E2E include pattern
├── src/
│   ├── config.ts
│   ├── core/                # Host-neutral memory (conversation, record, scene, persona, store, …)
│   ├── adapters/            # openclaw / standalone host adapters
│   ├── gateway/             # Standalone HTTP gateway
│   ├── offload/             # Context-engine offload
│   ├── cli/                 # openclaw memory-tdai CLI registration
│   └── utils/
├── hermes-plugin/           # Hermes MemoryProvider adapter
├── scripts/                 # ctl, migrate, export, patch, hermes install
├── bin/                     # Published CLI wrappers (need build:scripts)
├── CONTRIBUTING.md
└── .github/                 # PR/issue templates, pr-ci.yml
```

CONTRIBUTING’s older flat `src/conversation` tree maps to `src/core/*` in the current tree; prefer paths above when placing PRs.

## npm scripts

| Script | Command surface | Purpose |
|--------|-----------------|---------|
| `test` | `vitest run` | Unit suite (default config) |
| `test:watch` | `vitest` | Watch mode |
| `test:coverage` | `vitest run --coverage` | v8 coverage (`text` / `html` / `lcov`) |
| `build` | `build:plugin` + `build:scripts` | Full package + CLI compile |
| `build:plugin` | `tsdown` | Bundle `index.ts` → `dist/index.mjs` |
| `build:scripts` | three `tsc` projects | migrate / export / read-local-memory |
| `build:migrate-sqlite-to-vdb` | `tsc -p scripts/migrate-sqlite-to-tcvdb/tsconfig.json` | Migration CLI |
| `build:export-tencent-vdb` | `tsc --project scripts/export-tencent-vdb/tsconfig.json` | Export CLI |
| `build:read-local-memory` | `tsc --project scripts/read-local-memory/tsconfig.json` | Local memory reader |
| `migrate-sqlite-to-tcvdb` | `node ./bin/migrate-sqlite-to-tcvdb.mjs` | Run migration bin |
| `export-tencent-vdb` | `node ./bin/export-tencent-vdb.mjs` | Run export bin |
| `read-local-memory` | `node ./bin/read-local-memory.mjs` | Run reader bin |
| `prepack` | `npm run build` | Ensures build before pack |
| `postinstall` | patch script `\|\| true` | Optional OpenClaw after-tool-call patch |

Published bins:

- `migrate-sqlite-to-tcvdb`
- `export-tencent-vdb`
- `read-local-memory`

Each `bin/*.mjs` wrapper imports precompiled output under `scripts/*/dist/`. Build the matching script target before invoking a bin against a dirty tree.

### Build target: plugin (`tsdown`)

`tsdown.config.ts`:

| Option | Value |
|--------|--------|
| Entry | `./index.ts` |
| Out dir | `./dist` |
| Format | ESM |
| Platform | node |
| DTS / sourcemap | off |
| Externals | `openclaw` (+ subpaths), `node:*`, all `dependencies` / `peerDependencies` / `optionalDependencies` |

`package.json` `main` / `exports` point at `./dist/index.mjs`. Link-dev OpenClaw uses `openclaw.extensions: ["./index.ts"]`, not the packed `dist/` path.

### When you need `npm run build`

| Workflow | Build needed? |
|----------|----------------|
| OpenClaw `--link` edit/reload | No (source `.ts`) |
| `npm pack` / publish | Yes (`prepack` → `build`) |
| CLI bins / migrate-export tools | Yes (`build:scripts` or full `build`) |
| PR CI pack job | Yes (pack triggers `prepack` → build when scripts run) |

## Tests (Vitest)

### Unit tests (`vitest.config.ts`)

| Setting | Value |
|---------|--------|
| Environment | `node` |
| Pool | `forks` |
| Include | `src/**/*.test.ts`, `__tests__/**/*.test.ts` |
| Exclude | `dist/**`, `node_modules/**`, `**/*.e2e.test.ts` |
| Timeouts | `testTimeout` / `hookTimeout` **120_000** ms |
| Mocks | `clearMocks`, `restoreMocks`, `unstubEnvs`, `unstubGlobals` |
| Coverage | provider `v8`; include `src/**/*.ts`, `index.ts`; exclude tests/dist/node_modules |

```bash
npm test
npm run test:watch
npm run test:coverage
```

Existing co-located unit examples include `src/utils/time.test.ts`, `src/utils/sanitize.test.ts`, `src/utils/no-think-fetch.test.ts`, `src/offload/auth-profile-key.test.ts`. Prefer the same `*.test.ts` placement next to the module under test.

### E2E config (`vitest.e2e.config.ts`)

| Setting | Value |
|---------|--------|
| Include | `**/*.e2e.test.ts` |
| Exclude | `dist/**`, `node_modules/**` |
| `testTimeout` | 120_000 ms |
| `hookTimeout` | 60_000 ms |

There is **no** `package.json` script that selects this config. Run explicitly when adding e2e files:

```bash
npx vitest run --config vitest.e2e.config.ts
```

`.npmignore` / `package.json` `files` exclude tests from the published tarball (`!src/**/*.test.ts`, `!src/**/__tests__/`, etc.).

## Pull request CI

Workflow: `.github/workflows/pr-ci.yml`  
Triggers: `pull_request` → branch **`main`**  
Concurrency: `ci-${{ github.ref }}` with `cancel-in-progress: true`

| Job | Depends on | What it checks |
|-----|------------|----------------|
| **Install** | — | Checkout, Node 22, cache `node_modules` by `hashFiles('package.json')`, `npm install --ignore-scripts` on cache miss |
| **Pack** | install | Restore cache → `npm pack --dry-run` → `npm pack` → upload `*.tgz` (7-day retention) |
| **Manifest** | — (parallel) | `openclaw.plugin.json` exists + valid JSON; required `id`; optional `configSchema` object; `package.json` `openclaw.extensions`, `openclaw.compat.pluginApi`, `openclaw.build.openclawVersion` |
| **Size Guard** | pack | Tarball size ≤ **2048 KB** |

<Warning>
CI does **not** currently run `vitest`. Local `npm test` (and targeted builds) remain the contributor self-test bar from the PR template.
</Warning>

## Commit conventions

Format from `CONTRIBUTING.md`:

```text
<type>(<scope>): <short summary>

<detailed description (optional)>

Closes #123
Signed-off-by: Your Name <your-email@example.com>
```

### Types (aligned with PR template change types)

| Type | Meaning | PR Change Type checkbox |
|------|---------|-------------------------|
| `fix` | Bug fix | Bug fix |
| `feat` | New feature | New feature |
| `docs` | Documentation | Documentation update |
| `perf` | Performance | Code optimization |
| `refactor` | No behavior change | Code optimization |
| `test` | Tests | — |
| `chore` | Build / tooling / deps | — |

### Scope examples

`store`, `hooks`, `persona`, `scene`, `record`, `conversation`, `gateway`, `hermes`

### Code style expectations

- Match existing TypeScript style.
- Prefer English identifiers.
- Comment **why** at non-obvious logic.
- Import order: Node built-ins → third-party → internal modules.

## DCO (required)

Every commit must include a `Signed-off-by` line (Developer Certificate of Origin). Commits without it are not merged.

```bash
git commit -s -m "feat(store): add batch insert support"
```

## Pull request expectations

1. Fork and branch from **`main`** (default PR target).
2. Keep commits focused/atomic; use the type/scope convention above.
3. Self-test: `npm test` (and `npm run build` / relevant script builds if you touch packaging or bins).
4. Update user-facing docs (`README.md`, `CHANGELOG.md`, `openclaw.plugin.json` descriptions) when behavior or config changes.
5. Open a PR using `.github/PULL_REQUEST_TEMPLATE.md`.

### PR template fields

| Section | Expectation |
|---------|-------------|
| Description | What the PR does |
| Related Issue | e.g. `Fix #123` |
| Change Type | Bug fix / New feature / Documentation update / Code optimization |
| Self-test checklist | Verified locally; no existing features affected |
| Additional notes | Optional |

### Issue templates

| Template | Title prefix | Typical fields |
|----------|--------------|----------------|
| Bug report | `[Bug]` | OpenClaw version, plugin version, OS, repro, expected, logs |
| Feature request | `[Feature]` | Problem, desired solution, alternatives |
| Question | (consultation) | Question body per template |

## Security and license

| Topic | Rule |
|-------|------|
| Security vulnerabilities | Email **agentmemory@tencent.com** (do not open a public issue for sensitive reports) |
| Contribution license | MIT (`LICENSE`); submitting a PR accepts MIT licensing of the contribution |
| Changelog style | Keep a Changelog + SemVer (`CHANGELOG.md`) |

## Verification checklist before open PR

```bash
# Unit tests
npm test

# Optional coverage
npm run test:coverage

# If changing pack surface / bins
npm run build
npm pack --dry-run

# If changing plugin manifest or package openclaw metadata
# (mirrors CI Manifest job)
node -e "JSON.parse(require('fs').readFileSync('openclaw.plugin.json','utf8'))"
```

Confirm Gateway still loads the linked plugin after restart and that new config keys (if any) appear in `openclaw.plugin.json` `configSchema`.

## Related pages

<CardGroup>
  <Card title="Installation" href="/installation">
    Prerequisites, openclaw plugins install/update, link-from-source install, postinstall patch behavior.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Package bins and seed CLI, including build prerequisites for migrate/export/read tools.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Source-backed failure modes useful when a local link install or Gateway reload misbehaves.
  </Card>
  <Card title="Overview" href="/overview">
    Product surface and host entry points (OpenClaw plugin, Hermes, Gateway).
  </Card>
</CardGroup>
