Skip to main content

AnnealBridge

CI PyPI Python 3.11+ License: MIT

English | 繁體中文

Combinatorial optimization middleware for AI agents. An agent describes what to optimize as structured JSON; AnnealBridge decides how to encode and solve it, checks every answer against the original problem, and returns ranked, verified solutions over MCP, a CLI, or plain Python.

flowchart LR
    U[Natural language] --> A[AI agent]
    A -->|OptimizationProblem JSON<br/>variables · objective · constraints| B
    subgraph B[AnnealBridge]
        direction LR
        V[validate] --> C[compile<br/>BQM / CQM] --> S[solve<br/>local or remote] --> R[re-validate against<br/>the original problem] --> K[rank]
    end
    B -->|SolveResult<br/>ranked, verified solutions| A
    A --> N[Natural-language answer]

Quick start

pip install annealbridge

A 0/1 knapsack: four items, capacity 10, maximize value. No file needed.

from annealbridge.models import OptimizationProblem
from annealbridge.orchestration import OptimizationService

problem = OptimizationProblem.model_validate({
    "version": "1.0",
    "name": "knapsack",
    "variables": [{"name": n, "type": "binary"} for n in ["a", "b", "c", "d"]],
    "objective": {"direction": "maximize", "linear_terms": [
        {"variable": "a", "coefficient": 10}, {"variable": "b", "coefficient": 8},
        {"variable": "c", "coefficient": 7}, {"variable": "d", "coefficient": 6}]},
    "constraints": [{"id": "capacity", "type": "hard", "operator": "<=", "rhs": 10, "terms": [
        {"variable": "a", "coefficient": 6}, {"variable": "b", "coefficient": 5},
        {"variable": "c", "coefficient": 4}, {"variable": "d", "coefficient": 3}]}],
})

result = OptimizationService().solve(problem)
print(result.status)                        # success
print(result.solutions[0].variables)        # {'a': 1, 'b': 0, 'c': 1, 'd': 0}
print(result.solutions[0].objective_value)  # 17.0

Domain failures come back as results, never as exceptions: result.status is one of success, infeasible, invalid_problem, resource_limit_exceeded, backend_unavailable, configuration_error or solver_error. See docs/output-format.md.

Optional extras:

pip install "annealbridge[mcp]"       # + MCP server (annealbridge-mcp)
pip install "annealbridge[dwave]"     # + D-Wave cloud backends
pip install "annealbridge[all]"       # everything

Use it from an AI agent (MCP)

With uv installed, add the server to claude_desktop_config.json (or your host's equivalent) and restart the host; uvx fetches the package into its own cached environment the first time.

{
  "mcpServers": {
    "annealbridge": {
      "command": "uvx",
      "args": ["--from", "annealbridge[mcp]", "annealbridge-mcp"]
    }
  }
}

Claude Code registers it in one line:

claude mcp add annealbridge -- uvx --from "annealbridge[mcp]" annealbridge-mcp

Optimizing is then an ordinary chat:

You: I can carry 10 kg. Item A is worth 10 and weighs 6, B is worth 8 and weighs 5, C is worth 7 and weighs 4, D is worth 6 and weighs 3. Which ones should I take?

Behind the reply, the agent calls three tools in order:

  1. get_optimization_capabilities — allowed variable types and operators, usable backends and their limits.
  2. validate_optimization_problem — its draft JSON comes back with every error at once, or clean. Nothing is solved yet and nothing is spent.
  3. solve_optimization — ranked solutions, each re-validated against the original constraints, with optimality_proven: true on the exhaustive exact backend.

Agent: Take A and C: value 17 at exactly 10 kg. The runners-up are A and D (16, at 9 kg) and B and C (15, at 9 kg). This is the proven optimum.

The wording is the agent's; the numbers are the tool result. A fourth tool, recommend_backend, ranks the backends for a problem and is advisory only. Any stdio-capable MCP host works the same way, a streamable-http transport exists, and pipx or a pip-installed server behind an absolute path work in place of uvx. uvx reuses the environment it resolved on its first run, so a new release reaches an existing install only after uv cache clean annealbridge and a host restart; see docs/mcp.md.

Use it from the command line

Save the problem JSON below as knapsack.json, then:

annealbridge solve knapsack.json
Problem:   knapsack
Backend:   exact
Status:    success
Attempts:  1
Elapsed:   2.7 ms

Best solution (rank 1)
  objective (maximize):  17
  soft violation score:  0
  item_a = 1
  item_b = 0
  item_c = 1
  item_d = 0

Hard constraints: 1 / 1 satisfied
Soft constraints: 0 violations
Optimality proven: yes

Elapsed is the service's own wall clock and varies from run to run. Add --json for the full SolveResult, --backend simulated_annealing to override the backend, or try validate, recommend, capabilities and export-schema. See docs/cli.md.

The problem JSON

The document behind the MCP and CLI examples above, the reduced form of examples/knapsack.json:

{
  "version": "1.0",
  "name": "knapsack",
  "variables": [
    {"name": "item_a", "type": "binary"},
    {"name": "item_b", "type": "binary"},
    {"name": "item_c", "type": "binary"},
    {"name": "item_d", "type": "binary"}
  ],
  "objective": {
    "direction": "maximize",
    "linear_terms": [
      {"variable": "item_a", "coefficient": 10},
      {"variable": "item_b", "coefficient": 8},
      {"variable": "item_c", "coefficient": 7},
      {"variable": "item_d", "coefficient": 6}
    ]
  },
  "constraints": [
    {
      "id": "capacity",
      "type": "hard",
      "terms": [
        {"variable": "item_a", "coefficient": 6},
        {"variable": "item_b", "coefficient": 5},
        {"variable": "item_c", "coefficient": 4},
        {"variable": "item_d", "coefficient": 3}
      ],
      "operator": "<=",
      "rhs": 10
    }
  ],
  "solver": {"backend": "exact"}
}

Integer variables ("type": "integer" with bounds, "version": "1.1"), quadratic objective terms, soft constraints with weights and per-backend solver preferences are described in docs/problem-format.md. annealbridge export-schema prints the JSON Schema an agent can use for structured output.

Four ready-to-run examples live in the repository — knapsack, assignment, TSP and integer knapsack. The installed wheel does not ship them; take them from a checkout or from GitHub.

How it works

The agent produces an OptimizationProblem: binary or bounded-integer variables, a linear or quadratic objective, and hard or soft linear constraints. Nothing else. AnnealBridge then, deterministically:

  1. validates the problem and collects every error in one pass;
  2. compiles it into a BQM or a CQM, computing penalties, slack and integer encodings itself;
  3. solves it on a local or remote backend;
  4. re-validates every candidate against the original JSON, never trusting solver energy;
  5. ranks the feasible solutions and returns the top K with per-constraint evaluations.

The agent never writes a QUBO matrix, a penalty weight, a slack variable or an integer encoding, and every step is testable without an AI, a network or a vendor account.

Backends

Six backends sit behind one protocol.

Backend Kind Path Notes
exact local BQM Enumerates every assignment; 24 compiled variables by default
simulated_annealing local BQM Heuristic; honours num_reads, num_sweeps, seed
dwave_qpu remote BQM D-Wave quantum annealer via EmbeddingComposite
leap_hybrid_bqm remote BQM D-Wave Leap hybrid BQM solver
leap_hybrid_cqm remote CQM D-Wave Leap hybrid CQM solver; native constraints
fujitsu_da remote BQM Fujitsu Digital Annealer, QUBO API V4 over HTTPS, no SDK

Remote backends need their vendor credential and ANNEALBRIDGE_ALLOW_REMOTE=true; without both they report backend_unavailable. annealbridge recommend ranks the backends for a problem without solving it and never changes the one you asked for. Setup and per-backend behaviour: docs/backends.md.

Design guarantees

  • Business-level contract in both directions. Variables, objective and constraints in; ranked solutions with per-constraint evaluations out. No solver internals leak either way.
  • Two compiler paths. BQM (automatic penalties, binary slack, encoded integers) for annealers; CQM (native constraints and integers) for the Leap hybrid CQM solver. The backend chooses by declaring what it supports.
  • Bounded integers without exposure. "version": "1.1" adds integer variables with the encoding hidden; 1.0 behaviour is pinned by a golden test.
  • Structured failures, never exceptions. Every outcome is a SolveResult with a status; every failure carries a stable error code with a recommended_action. infeasible is an answer, not a failure.
  • No silent decisions. An unavailable backend is reported, never swapped. An over-limit parameter is rejected, never clamped. An undeclared field is rejected, never ignored. Validator warnings travel with every solve result.
  • Safe by default. Remote execution and remote retries are off until enabled; every limit is an environment variable enforced as an error; vendor credentials are redacted from results, logs and error messages. The streamable-http transport has no authentication; keep it on a private network. See docs/security.md and SECURITY.md.
  • Enforced architecture. Import boundaries, "no backend names in the orchestration, validation or interface layers", and "a new backend plugs in without touching the pipeline" are tests, not conventions.

Documentation

The pages below live under docs/.

Page What it covers
docs/problem-format.md The input JSON: variables, objective, constraints, solver preferences
docs/output-format.md SolveResult and every field it carries
docs/errors.md Error catalog, warning codes, reason codes, exit codes
docs/cli.md The annealbridge command line
docs/mcp.md The MCP server, tools, host configuration, Inspector
docs/backends.md The six backends, D-Wave and Fujitsu setup, adding a backend
docs/configuration.md Every ANNEALBRIDGE_* variable and the vendor credentials
docs/architecture.md Layers, package layout, design principles
docs/security.md Defaults, limits, credential redaction, what reaches a vendor
docs/testing.md Test layout, golden tests, live tests, CI
docs/limitations.md Known limits and what is out of scope

Development

git clone https://github.com/TheTsungYing/AnnealBridge.git
cd AnnealBridge
pip install -e ".[all,dev]"
pytest

pytest runs the full suite with no skip and no xfail and never touches the network; the live vendor tests are opt-in (pytest -m remote). To install the development version without a checkout: pip install "annealbridge[all] @ git+https://github.com/TheTsungYing/AnnealBridge.git". Architecture rules, design principles and the pull-request checklist are in CONTRIBUTING.md.

Version 0.2.0: the problem contract (1.0 / 1.1), the six backends, the CLI and the MCP tools are complete and covered by tests. What is not supported, by design for now, is listed in docs/limitations.md; changes are in CHANGELOG.md.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

annealbridge-0.2.0.tar.gz (166.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

annealbridge-0.2.0-py3-none-any.whl (195.1 kB view details)

Uploaded Python 3

File details

Details for the file annealbridge-0.2.0.tar.gz.

File metadata

  • Download URL: annealbridge-0.2.0.tar.gz
  • Upload date:
  • Size: 166.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for annealbridge-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f41e13656cc55556fec61a9ac2de426d6b566292798eb27ab3e80892c564b5ea
MD5 1812611c121dae43d6819828f4286837
BLAKE2b-256 b27a1e399b4b5f8a67dc81bad403711aec985300d12634e91b33e9aa32ec624d

See more details on using hashes here.

Provenance

The following attestation bundles were made for annealbridge-0.2.0.tar.gz:

Publisher: release.yml on TheTsungYing/AnnealBridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file annealbridge-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: annealbridge-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 195.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for annealbridge-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 98db6544b83713da3bceceaf522bf6e63bc5e979db6a092d0219bf6c6266dd1a
MD5 7be4df3730b1b503c6081b015b1718b2
BLAKE2b-256 c7a7b3b3039e4d6c886543394ebfb855a082bd2e8a9efc06a5380ebc797275cc

See more details on using hashes here.

Provenance

The following attestation bundles were made for annealbridge-0.2.0-py3-none-any.whl:

Publisher: release.yml on TheTsungYing/AnnealBridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.1

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page