A bracket engine you can call

Five formats for any field size, with byes, seeding and the grand final reset handled properly. Run it as a library, hit it over HTTP with no account, or hand it to an LLM.

Try it

This calls the public endpoint below — nothing is stored.

Format
Result
 

From a terminal

No account, no network once installed.

shell
npx @bracketintel/cli new "Ann,Bo,Cy,Di"
npx @bracketintel/cli new -n 32 --format de
npx @bracketintel/cli new --from teams.txt --format de --randomize --seed friday --svg

From an LLM

The same binary is an MCP server. Four tools, no authorization needed — a bracket is computed from its inputs, so nothing here touches your data.

json
{
  "mcpServers": {
    "bracketintel": {
      "command": "npx",
      "args": ["-y", "@bracketintel/cli", "mcp"]
    }
  }
}
  • explain_formathow many rounds, matches and byes a field will produce
  • create_bracketbuild a bracket from a list of names
  • report_resultrecord a winner and see the updated bracket
  • next_matcheswhich matches are playable right now

Over HTTP

Stateless and cacheable. Identical input always returns identical output, so responses are safe to cache indefinitely.

shell
curl -X POST https://www.bracketintel.com/api/v1/engine/generate \
  -H 'Content-Type: application/json' \
  -d '{"format":"DOUBLE_ELIM","participants":["Alice","Bob","Carol","Dave"]}'

Also /api/v1/engine/apply to report a result and /api/v1/engine/render for text, JSON or SVG. Full schema at /api/v1/openapi.json.

As a library

Pure and dependency-free, so an agent can skip tool calls and just write code against it.

javascript
import { generate, apply, renderText } from "@bracketintel/engine";

const bracket = generate({
  format: "DOUBLE_ELIM",
  participants: [{ id: "a", name: "Ann" }, { id: "b", name: "Bo" }],
});

console.log(renderText(bracket));

How it models a bracket

A match declares where each of its two occupants comes from, rather than pointing forward at the match it feeds:

json
{ "id": "L2.1",
  "slotA": { "kind": "winner", "matchId": "L1.1" },
  "slotB": { "kind": "loser",  "matchId": "W2.1" } }

One shape covers an elimination tree, a losers bracket, group standings and a Swiss round that has not been paired yet. It is also what makes double elimination expressible at all: a loser edge has nowhere to live in a model built on “next match” pointers.