mcpField
M
minimax

minimax

github.com/terrylicaDevelopment140 installsUpdated 1d ago
Repository

About minimax

A production-oriented guide to MiniMax M2.7, covering API behavior, suitable workloads, and defensive practices, with an emphasis on finance and quant workflows. It separates model-based judgment and tool orchestration from deterministic computation and code validation.

Key features

  1. 01Choose models for short or long outputs
  2. 02Document OpenAI-compatible API parameter differences
  3. 03Handle reasoning text, errors, and rate limits
  4. 04Advise on JSON output and caching
  5. 05Route math to Python and validate generated code

Use cases

  1. 01Choose a model or Python for quant tasks
  2. 02Produce parseable trade-signal JSON
  3. 03Build agent workflows with tool calls
  4. 04Troubleshoot MiniMax API limits and responses

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/terrylica/cc-skills --skill minimax

After installing, type/minimaxin Claude Code to confirm it loaded.

Details

From the project README

MiniMax M-series Production Wiring

OpenAI-compatible chat-completion endpoint at https://api.minimax.io/v1 with the M2.7-highspeed reasoning model (premium tier as of 2026-04-29). LOOKS LIKE OPENAI but silently drops 6 OpenAI parameters and exposes <think> reasoning traces inside content. Beyond chat-completion, the API is MiniMax-native (different URLs, different body shapes, different error envelopes — HTTP 200 + base_resp.status_code instead of HTTP 4xx).

The model itself is a competent qualitative judge + theory explainer + tool orchestrator for finance/quant work, but cannot do raw math on realistic data sizes (saturates reasoning budget) and hallucinates plausible details under input uncertainty (6 documented instances). For production: pair it with Python for math, sandbox validators for code, and deterministic detectors for pattern recognition.

Self-Evolving Skill: This skill improves through use. If instructions are wrong, parameters drifted, or a workaround was needed — fix this file immediately, don't defer. Only update for real, reproducible issues. Source-of-truth campaign archive: ~/own/amonic/minimax/ (read-only reference; do not modify from this skill).

🆕 MiniMax-M3 is live (2026-06-01). This file covers M2.7. For M3 — native vision, reasoning_split clean output, response_format acceptance, ~1M input ceiling (reliable retrieval ≤ ~256K) / 524K output cap, n=1, and the docs-vs-reality discrepancies — use the sibling skill ../m3/SKILL.md and the evidence doc ../../references/M3-EMPIRICAL.md. The defensive snippets below (<think> strip, base_resp retry, cached-token reader) apply to M3 unchanged.


When to use M2.7 vs not — the decision table

WorkloadVerdictWhy
Tagging / classification (5-15 token outputs)✅ Use plain MiniMax-M2.7Plain is 2.5× faster than -highspeed for short outputs (cross-over at ~150 tokens).
Summarization / long-form generation✅ Use -highspeed-highspeed wins at >150 tokens. ~50 TPS asymptote (NOT the 100 TPS plan claim).
Trade signal JSON output✅ Production-ready6/6 verified across L1+L2+L3 layers with strict system prompt. Confidence well-calibrated.
Financial theory explanation✅ Graduate-levelBlack-Scholes derivations, FTAP, KKT, vol skew microstructure all correct.
Long-context retrieval (≤ 30K tokens)✅ 4/4 needle retrievalNO "lost in the middle" effect. Perfect retrieval at 10/50/85/98% positions.
Tool orchestration (agent loop)✅ 4/4 correct selectionParallel + chained tool calls work. Refuses irrelevant queries gracefully.
Math / Black-Scholes / Sharpe on N≥50 returns❌ DO NOT USESaturates 8-16K reasoning tokens; route to Python (numpy/scipy/cvxpy).
QP / constrained optimization (Markowitz)❌ DO NOT USESame saturation pattern. Use scipy.optimize / cvxpy.
Risk metrics on realistic data (N=252 returns)❌ DO NOT USEEven SINGLE metric saturates. Pre-summarize aggregates before passing.
Chart pattern recognition❌ DO NOT USEHallucinates patterns in pure noise. Use TA-Lib / CV / classical algos.
Code generation (final, deployable)⚠️ Scaffold-onlyCompiles 100%, runs 0% on first try (hallucinates library imports). Sandbox-validate.
Vision / image input❌ NOT SUPPORTEDM2.7 is text-only. image_url silently dropped at INPUT level.
TTS / video⚠️ Plan-gatedEndpoints exist (/v1/t2a_v2, /v1/video_generation) but error 2061 on Plus-High-Speed.
Embeddings (bulk RAG)⚠️ RPM-tight/v1/embeddings accessible but rate-limited beyond ~5 calls. Use local embeddings.

Top 10 production rules

  1. Always set a system prompt — it's at-most break-even, often net-positive. Long instructions in messages[0] get ~70% billing rate AND replace MiniMax's hidden ~30-token default. Detailed instructions belong in system role, NEVER user content.

  2. Strip <think>...</think> from content before displaying. M-series exposes its reasoning trace inside the content string. Production: re.sub(r"<think>[\s\S]*?</think>\s*", "", content). Server-side stripping for billing on assistant replay (multi-turn doesn't double-bill).

  3. max_tokens ≥ 1024 for non-trivial tasks. 512 is a silent-empty footgun. Reasoning consumes budget BEFORE visible content. Branch on finish_reason == "length" defensively.

  4. Trust capability params, suspect control params. Honored: tools, messages, max_tokens, temperature, stream. Silently dropped: stop, tool_choice, response_format, streaming usage, image_url, messages[].name.

  5. For JSON output, prompt-engineer it — response_format is silently dropped. Strict system prompt + temperature=0.2 + max_tokens=4096 + try/except json.loads = 100% reliability (6/6 verified).

  6. Plain MiniMax-M2.7 for short-output workloads (<150 visible tokens); -highspeed for long-form. "Highspeed" is COUNTERINTUITIVELY slower for short outputs (Karakeep tagging at 5-15 tokens: plain is 2.5× faster).

  7. Caching is COST-only on MiniMax, not LATENCY. Add cache_control: {type: "ephemeral"} to system messages for ~95% input-token cost reduction; don't expect interactive-UX latency benefits. Activates at ~600+ prompt_tokens. Prefix-match works (varied user + stable system gets ~70% hit rate).

  8. Route financial math to Python — M2.7 saturates on QP / numerical integration / Sharpe on N≥50 returns. Pre-summarize aggregates (mean / stdev / n) and pass them; M2.7 handles the final-step formula. Define financial primitives as TOOLS for agent-loop orchestration.

  9. NEVER trust M2.7-generated code without sandbox validation. compile() is INSUFFICIENT. M2.7 invents library imports (SMA, RSI, BollingerBands from backtesting.lib — none exist). Run in subprocess + capture exit code + iterative repair on failure.

  10. NO HTTP 429 — rate-limited responses are HTTP 200 + base_resp.status_code=1002. Standard retry middleware that watches HTTP status WILL NOT catch this. Use code-prefix-based handler: 1xxx family = retry with backoff; 2xxx family = fix request, don't retry.


Canonical Tier F agentic stack (quant-LLM workflow)

F4: long-context retrieval         → M2.7 finds facts from filings/research
        ↓
F2: structured judgment as JSON    → M2.7 emits trade signal
        ↓
F6: tool orchestration             → M2.7 selects + calls tools (parallel + chained)
        ↓
F1+F8+F9: Python math layer        → numpy/scipy/cvxpy compute deterministically
        ↓
F3: textbook explanation           → M2.7 narrates the result with theory
        ↓
F5: sandbox-validated code         → M2.7 scaffolds; subprocess validates

The pattern: M2.7 for judgment / theory / orchestration; Python for math / validation / pattern detection. Never mix "explain + compute" in one prompt for complex problems — saturation is the failure mode.

PrimitiveM2.7's rolePython's roleVerdict
F1 Math❌ saturates✅ scipy/numpy computePython only
F2 JSON✅ 6/6 trade signals across scenariosparse + executeM2.7 + Py
F3 Theory✅ graduate-level Black-Scholes / FTAP / KKTrender markdownM2.7 only
F4 Long-ctx✅ 4/4 needle retrieval at 27K tokens❌ pre-tag Items client-side (anti-fabrication)M2.7 + Py guard
F5 Codegenscaffold only — invents library imports✅ subprocess validation MANDATORYM2.7 + Py validator
F6 Tools✅ 4/4 orchestration + parallel callsexecute the tool bodiesM2.7 + Py
F7 Patterns❌ hallucinates in random walks✅ TA-Lib / CV / classical algosPython only
F8 Optim❌ saturates on QP✅ scipy.optimize / cvxpyPython only
F9 Risk❌ saturates on N=252 returns✅ numpy returns/drawdownsPython only
F10 Mandarin✅ matches/exceeds English on quant contenttranslate + pass throughM2.7 (with caveats)

Defensive code snippets (copy-paste ready)

Strip <think> tags + handle finish_reason
import re

def parse_minimax_response(response: dict) -> tuple[str, str | None]:
    """Returns (visible_content, error_class).
    error_class is None for normal responses; set when finish_reason indicates issues."""
    choice = response["choices"][0]
    raw_content = choice.get("message", {}).get("content", "")
    finish = choice.get("finish_reason")

    # Strip reasoning trace
    visible = re.sub(r"<think>[\s\S]*?</think>\s*", "", raw_content).strip()

    # Defensive: detect saturation (per iter-36/37 — empty visible + length finish)
    if finish == "length" and len(visible) < 50:
        usage = response.get("usage", {})
        reasoning_tokens = (usage.get("completion_tokens_details") or {}).get("reasoning_tokens", 0)
        max_tokens = usage.get("completion_tokens", 0)
        if reasoning_tokens >= max_tokens * 0.95:
            return visible, "saturated"
    if finish == "length":
        return visible, "truncated"
    return visible, None
Production-ready JSON output (no response_format reliance)
SYSTEM_PROMPT = """You are a trading signal generator. Output ONLY a JSON object with these exact 5 fields:
{
  "action": "long" | "short" | "flat",
  "confidence": <0.0 to 1.0>,
  "reasoning": "<one sentence explaining the setup>",
  "stop_loss_pct": <number, 0 if action=flat>,
  "take_profit_pct": <number, 0 if action=flat>
}
No markdown, no prose before or after, no code fences. Just the JSON object."""

# call with temperature=0.2, max_tokens=4096, model="MiniMax-M2.7-highspeed"
# then: signal = json.loads(parse_minimax_response(resp)[0])
Cache-friendly system prompt with prefix-match
def build_messages(user_input: str, stable_system: str) -> list[dict]:
    """stable_system varies per service but is constant per call. Cached after first call,
    re-used across varying user_input (~70% hit rate on prefix match)."""
    return [
        {
            "role": "system",
            "content": stable_system,
            "cache_control": {"type": "ephemeral"},  # Anthropic-style; honored by MiniMax
        },
        {"role": "user", "content": user_input},
    ]

# For short system prompts (<300 tokens), pad to ≥600 to ACTIVATE caching.
# Counterintuitive: more bytes = lower billable tokens once cached.
Rate-limit-aware retry (no HTTP 429 — parse base_resp)
import time

def call_with_retry(client_fn, body: dict, max_attempts: int = 5) -> dict:
    """MiniMax returns HTTP 200 + base_resp.status_code=1002 on rate limit.
    Standard HTTP-status-based middleware will NOT catch this."""
    for attempt in range(max_attempts):
        resp = client_fn(body)
        base_resp = resp.get("base_resp", {})
        code = base_resp.get("status_code", 0)
        if code == 0:
            return resp
        if code == 1002:  # rate limit
            time.sleep(2 ** attempt)
            continue
        if code in (1004, 2013, 2061):  # auth / params / plan-gated — don't retry
            raise RuntimeError(f"MiniMax error {code}: {base_resp.get('status_msg')}")
        raise RuntimeError(f"Unknown MiniMax error {code}: {base_resp.get('status_msg')}")
    raise RuntimeError("MiniMax rate limit persisted across max attempts")
Cached-token reader (handles both API shapes)
def get_cached_tokens(usage: dict) -> int:
    """MiniMax uses BOTH OpenAI-style (auto-cache) and Anthropic-style (explicit cache_control).
    Production parsers must handle BOTH variants."""
    pt_details = usage.get("prompt_tokens_details") or {}
    return (
        pt_details.get("cached_tokens", 0)               # OpenAI shape
        or usage.get("cache_read_input_tokens", 0)       # Anthropic shape
        or 0
    )

11 documented failure modes — defenses

Hallucination (6 instances) — fabricates plausible details under input uncertainty
DomainWhat was fabricatedDefense
JSON enforcementReturned JSON-shaped natural language without response_formatPrompt-engineer; try/except json.loads
Vision inputDeliberated about missing image instead of refusingDon't use M2.7 for vision; pre-OCR
10-K source citationsInvented "Source: ITEM 3" attributionsPre-tag inputs client-side; validate post-hoc
Library importsSMA, RSI from backtesting.lib (do not exist)Sandbox-execute; iterative repair
Chart patterns"Descending Triangle bullish breakout" in PURE GBM noiseUse TA-Lib / CV; don't ask M2.7
Confidence handling(Counter-example — calibration WAS correct; pattern is broader)Cross-validate with deterministic alts

Detection heuristic: reasoning_tokens > 2.5× baseline correlates with hallucination (per iter-35). Flag for review.

Saturation (4 instances) — exhausts reasoning budget on impossible math
TaskBudgetSymptomDefense
Sharpe (N=10)4KEmpty visible; succeeded at 16K budgetPre-summarize; route to Python
Black-Scholes16KN(d1)/N(d2) computation never convergedDon't use M2.7; use scipy.stats.norm.cdf
Markowitz QP8KKKT solve attempted; budget exhaustedUse scipy.optimize / cvxpy
Sortino (N=252)8KPer-value tracking burned tokensPre-summarize aggregates

Detection heuristic: is_saturated = (finish_reason=='length' AND len(visible)<50 AND reasoning_tokens >= 0.95*max_tokens). Don't retry with higher budget — route to Python instead.

Cross-language asymmetry (1 instance)
QueryEnglish responseMandarin response
Tiananmen 1989Full historical narrative incl. "massacre"Graceful deflection ("我不太清楚...换个话题")

Defense: detect non-substantive responses (short + uncertainty language) for amonic services with multilingual users. Financial use cases unlikely to bite. International api.minimax.io applies Chinese-language-specific filtering on politically-sensitive content; English equivalents unfiltered.


API surface map (Plus-High-Speed plan)

EndpointURLBody shapePlan-gated?Notes
Chat completion/v1/chat/completionsOpenAI-compat (6 silent-dropped params)NoPrimary interface
Models catalog/v1/modelsOpenAI-compatNo7 models on this tier
Embeddings/v1/embeddingsMiniMax (texts/type/vectors)RPM-gatedMulti-min cooldown; impractical for bulk RAG
Files (CRUD)/v1/files/{list,upload,delete}Sub-resource verbsNoFull CRUD; int64 file_id (JS precision risk)
TTS/v1/t2a_v2MiniMax-nativeYesAll 6 speech models gated (2061)
Video/v1/video_generationMiniMax-native, asyncYestask_id polling pattern (untested)
Vision (image_url)(drops at input)OpenAI-compatN/ANOT supported on M2.7 — text-only model
Web search MCPtools: [{type: "web_search"}]OpenAI-compatYesFirst HTTP 400 in campaign (2013 "not support")

Operational facts

TopicFact
Concurrency sweet spotp=10 for chat-completion (true parallelism, ~5x throughput vs serial). p=20 only buys 25% more.
TPS asymptote~50 tokens/sec on highspeed (NOT the 100 TPS plan claim). Use 40 TPS for production capacity baseline.
Min latency floor~1.5s per call (network + tokenization + reasoning preamble) — can't go below regardless of prompt size
Context ceiling200K tokens (between 142K and 262K). Safe operating: 100K. Token-byte ratio: 3.6 chars/token English
Cache activationAuto-cache at ~600+ prompt_tokens; explicit cache_control works; ~70% hit rate on prefix match
Cache TTL≥ 3 minutes (zero decay across 185s tested); upper bound likely 5min
Stream chunk shapeCoarse-grained (~125 chars/chunk, ~2/sec). Not per-token. <think> splits across chunks.
Mandarin token cost1.4-1.5× English for equivalent semantic content (BPE behavior on CJK)

OPS tooling — model-upgrade detection

The campaign produced an active tripwire: when MiniMax ships a new model, scheduled polling detects it and exits non-zero to force re-verification. See scripts/minimax-check-upgrade (ported in iter-16) and references/model-upgrade-detection.md.

# After install + lock-snapshot setup:
~/path/to/minimax-check-upgrade
# Exit 0 = no change (live matches locked snapshot)
# Exit 1 = upgrade detected (review diff before bumping lock)
# Exit 2 = fetch error

Recommended: schedule daily via launchd/cron. Add to CI as a pre-merge gate to refuse changes when the catalog has drifted without explicit lock review.


Deep references (drill into these for specifics)

  • references/RETROSPECTIVE.md — the 41-iteration retrospective (TL;DR, top 10 rules, agentic stack, full failure-mode catalog, API surface, operational facts, open questions)
  • references/quirks.md — use-case-organized critical findings (5 production-must-knows up front)
  • references/api-patterns/INDEX.md — navigable TOC of 40 per-endpoint pattern docs
  • references/api-patterns/<endpoint>.md — minimum-viable request/response shape, idiomatic snippets, known failure modes, reproducer commands, full provenance per probe
  • references/fixtures/ — selected raw API responses for diffing against future API changes
  • scripts/minimax-check-upgrade — model-upgrade detection executable
  • templates/launchd-check-upgrade.plist — daily polling plist template

Quick-start for new amonic services

# 1. Set environment
export OPENAI_BASE_URL=https://api.minimax.io/v1
export OPENAI_API_KEY=<from 1Password>
export MINIMAX_MODEL=MiniMax-M2.7              # for tagging-style services
# OR: export MINIMAX_MODEL=MiniMax-M2.7-highspeed   # for long-form services

# 2. Verify wiring
curl -sS -X POST "$OPENAI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"model": "MiniMax-M2.7", "messages": [{"role": "user", "content": "Reply OK"}], "max_tokens": 200}' \
  | python3 -m json.tool | head -20

# 3. Add cache_control to your stable system prompt for ~95% input cost reduction (see snippet above)
# 4. Add the strip-<think> + finish_reason check to your response parser
# 5. Add base_resp.status_code rate-limit handler (no HTTP 429)
# 6. If using mise: schedule check-upgrade as a pre-merge CI gate

Provenance

Distilled from the 41-iteration minimax-m27-explore autonomous-loop campaign at ~/own/amonic/minimax/:

  • 40 verified hands-on pattern docs (api-patterns/*.md)
  • 1 quirks consolidation (quirks/CLAUDE.md — iter-11)
  • 1 retrospective (RETROSPECTIVE.md — iter-42)
  • 1 OPS tool with launchd plist (bin/minimax-check-upgrade + config/plists/)
  • ~50 API response fixtures
  • ~155 Non-Obvious Learnings, 35 critical findings, 11 documented failure modes, 4 error code families, 6 compat envelope categories

Campaign verified against MiniMax-M2.7-highspeed between 2026-04-28 and 2026-04-29. Re-verify against new model versions via mise run minimax:check-upgrade.

Post-Execution Reflection

  1. Locate yourself. — Confirm this SKILL.md is the canonical file before any edit.
  2. What failed? — A wiring snippet stopped working, a parameter that was reported "silently dropped" now succeeds, or a base_resp.status_code mapping changed. Update the affected pattern doc + the table here so the next reader doesn't repeat the failure.
  3. What drifted? — mise run minimax:check-upgrade flagged a new model version, the OpenAI-compat envelope changed shape, or rate-limit / cache_control semantics shifted. Update the locked-snapshot pointer and the impacted sections.
  4. Log it. — Append a dated line under "Provenance" (or a new "Evolution log" section) with trigger + fix + evidence so future iters can audit drift.

Comments

Markdown supported