# paperclip-adapter-minimax

> A community adapter that lets [Paperclip](https://github.com/paperclipai/paperclip) agents
> talk to [MiniMax](https://MiniMax.ai)'s M2/M3 model family through MiniMax's
> OpenAI-compatible API.

This package implements Paperclip's **adapter contract** so you can register
`minimax` as an adapter in a Paperclip deployment and point your agents at the
MiniMax catalog (`MiniMax-M2`, `MiniMax-M2.5`, `MiniMax-M2.7`, `MiniMax-M3`).

It is **not affiliated with MiniMax or Paperclip**. The Paperclip project is at
<https://github.com/paperclipai/paperclip>; the MiniMax project is at
<https://MiniMax.ai>. This adapter is built against the publicly documented
Paperclip adapter contract (modeled after the community
`paperclip-adapter-openrouter` package).

---

## What you get

- Pure-HTTP TypeScript adapter — no CLI subprocess to spawn.
- `supportsLocalAgentJwt: true` — the heartbeat dispatcher mints a per-run
  JWT and the adapter uses it to call Paperclip's REST API.
- 8 built-in Paperclip tools: `get_issue`, `list_issues`,
  `update_issue_status`, `add_comment`, `list_comments`, `create_sub_issue`,
  `hire_agent`, `request_approval`.
- Side-effect tools (`hire_agent`, `request_approval`) route through Paperclip's
  `/api/companies/:id/approvals` flow — no autonomous sidestepping.
- Repeat-call loop break: aborts the run if the same tool is called 3x in a row
  with the same arguments (prevents infinite ping-pong).
- Cost tracking: input/output tokens × configurable price-per-1M, aggregated
  per heartbeat.
- Skill loading from `<workspace>/skills`, `<workspace>/.paperclip/skills`, the
  configured `MINIMAX_SKILLS_DIR`, or the package's bundled defaults.
- Streaming support via MiniMax's `stream_options.include_usage`.
- JSONL session persistence (for the live Working panel and replay).
- `doctor` CLI for verifying your env + API key.

---

## Install

### Option A: monorepo (you have a Paperclip checkout)

```bash
# 1. Drop this folder next to your Paperclip source code
ls
# -> paperclip  paperclip-adapter-minimax  ...

cd paperclip-adapter-minimax
npm install
npm run build

# 2. Patch server/src/adapters/registry.ts — see REGISTRY_PATCHES.md

# 3. Restart Paperclip and select the "minimax" adapter in the UI
```

### Option B: npm (scoped)

```bash
# Once published (or you can `npm pack` from this folder):
npm install @uthotyan/paperclip-adapter-minimax
```

Then patch the registry (see [`REGISTRY_PATCHES.md`](./REGISTRY_PATCHES.md)) — the import path is `@uthotyan/paperclip-adapter-minimax`.

---

## Configuration

All configuration is via environment variables. Defaults are sensible for
local dev with the free model.

| Env var | Required | Default | Notes |
| --- | --- | --- | --- |
| `MINIMAX_API_KEY` | ✅ | — | Your MiniMax API key. |
| `MINIMAX_BASE_URL` | | `https://api.minimax.chat/v1` | MiniMax's OpenAI-compatible base URL. |
| `MINIMAX_MODEL` | | `MiniMax-M3` | The model ID. See list below. |
| `MINIMAX_PRICE_INPUT_PER_1M` | | `1` | USD per 1M input tokens. Override if MiniMax changes pricing. |
| `MINIMAX_PRICE_OUTPUT_PER_1M` | | `3` | USD per 1M output tokens. |
| `MINIMAX_MAX_TURNS` | | `8` | Hard cap on tool-loop iterations per heartbeat. |
| `MINIMAX_MAX_TOOL_CALLS_PER_TURN` | | `8` | Cap on parallel tool calls in one assistant turn. |
| `MINIMAX_SKILLS_DIR` | | — | Custom skills dir (overrides default discovery). |
| `MINIMAX_STREAM` | | `1` | `0` to disable streaming. |
| `PAPERCLIP_API_KEY` | ✅ | — | Static key OR pre-minted JWT. |
| `PAPERCLIP_API_URL` | | `http://localhost:3100` | Your Paperclip server URL. |

A copy-paste starter is in [`.env.example`](./.env.example).

### MiniMax model catalog

| Model ID | Notes |
| --- | --- |
| `MiniMax-M3` | Latest; default in this adapter. |
| `MiniMax-M2.7` | Previous stable. |
| `MiniMax-M2.5` | Older stable. |
| `MiniMax-M2` | Earliest supported. |
| `MiniMax-M3:free` | Free tier (rate-limited). |

If you have an OpenCode subscription that exposes MiniMax, you can also pass
its `opencode/minimax-m3-free`-style ID as `MINIMAX_MODEL` — MiniMax's
endpoint accepts any ID it serves, the adapter doesn't validate.

---

## Doctor

After configuring `.env`, verify connectivity:

```bash
npx paperclip-adapter-minimax doctor
```

It checks: API key, base URL, Paperclip API key, MiniMax connection, lists
a few model IDs from `GET /v1/models`.

You can also list models:

```bash
npx paperclip-adapter-minimax list
```

---

## How a heartbeat runs

```
┌─────────────────────┐
│ Paperclip heartbeat │
│  dispatcher         │
└──────────┬──────────┘
           │ call adapter.run({ agent, run, issue })
           ▼
┌──────────────────────────────────┐
│  paperclip-adapter-minimax        │
│  (this package)                  │
│                                  │
│  1. Build system prompt          │
│  2. Resume session (if any)      │
│  3. Loop:                        │
│     a. chat.completions(...)     │
│     b. If tool_calls: execute    │
│        each, append results      │
│     c. If 3x same call: BREAK    │
│  4. Post final comment + status  │
│  5. Return { transcript,         │
│        cost, sessionState }      │
└──────────┬───────────────────────┘
           │ AdapterResult
           ▼
┌─────────────────────┐
│ Paperclip board UI  │
│  (transcript, cost) │
└─────────────────────┘
```

---

## Registering in Paperclip

See [`REGISTRY_PATCHES.md`](./REGISTRY_PATCHES.md) for the exact diff to apply
to `server/src/adapters/registry.ts`. The shape is:

```ts
import { minimaxAdapter } from "paperclip-adapter-minimax";

adapterRegistry.minimax = {
  ...minimaxAdapter.metadata,
  run: minimaxAdapter.run.bind(minimaxAdapter),
};
```

---

## Security notes

- This adapter makes outbound HTTPS to MiniMax (`api.minimax.chat`) and
  outbound HTTP(S) to your Paperclip server.
- It does NOT execute arbitrary code, spawn a subprocess, or read arbitrary
  files. The only filesystem access is:
  - reads `**/SKILL.md` under the configured `skillsDir`
  - reads `**/SKILL.md` under `<workspacePath>/skills` and `<workspacePath>/.paperclip/skills`
  - writes JSONL transcripts to `os.tmpdir()/paperclip-adapter-minimax/`
- The MiniMax API key never leaves the process; it's only used as a Bearer
  token on outbound calls to MiniMax.
- Approval-gated tools go through Paperclip's `/api/companies/:id/approvals`
  endpoint. A human must approve in the board UI before the new agent
  materializes or spend happens.
- If you don't want side effects at all, set
  `MINIMAX_APPROVAL_GATED=0` in the agent's environment — the adapter will
  still POST to /approvals but the row will be auto-acknowledged in your
  Paperclip workflow policy (depends on your setup).

---

## Troubleshooting

| Symptom | Likely cause |
| --- | --- |
| `doctor` says `minimax connection: ❌` | `MINIMAX_API_KEY` missing, or MiniMax endpoint unreachable from this network. |
| Tools never fire | `MINIMAX_MAX_TURNS` too low, or the model is returning plain text. Check the transcript in the Working panel. |
| `errorMessage: "repeat_call_loop_break"` | Your prompt is sending the model in circles. Tighten the task or raise `MINIMAX_MAX_TURNS` carefully. |
| Comments appear in the wrong place | The agent's `PAPERCLIP_API_URL` is pointing at a different company than the agent record. |
| `costUsd: 0` | Pricing vars not set; defaults are $1/$3. Override if your model is different. |
| MiniMax rejects `tools` | Some old model versions don't support function-calling. Use `MiniMax-M2.7` or later. |

---

## Development

```bash
npm install
npm run typecheck    # tsc --noEmit
npm test             # vitest
npm run build        # tsc → dist/
```

Run the CLI locally:

```bash
MINIMAX_API_KEY=... npm run dev -- doctor
```

---

## License

MIT. See [`LICENSE`](./LICENSE).

## Disclaimer

This is an independent community project. Not affiliated with, endorsed by,
or sponsored by MiniMax, Paperclip, or any of their parent companies.
Use at your own risk; review the code before pointing production agents at
it.
