Skip to content

Latest commit

 

History

150 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Mindctl



Mindctl is an LLM router that uses built-in logic and a System 1 decision model like Jev or Laya to intelligently route requests to the appropriate LLM model based on the input prompt.


💻 Visit stormsoftware.com to stay up to date with this developer


Commitizen friendly semantic-release GitHub Workflow Status (with event)

Important

This repository, and the apps, libraries, and tools contained within, is still in it's initial development phase. As a result, bugs and issues are expected with it's usage. When the main development phase completes, a proper release will be performed, the packages will be available through NPM (and other distributions), and this message will be removed. However, in the meantime, please feel free to report any issues you may come across.

Be sure to ⭐ this repository on GitHub so you can keep up to date on any daily progress!

Table of Contents


Install

The following installation methods are available for setting up Mindctl:

npm

Install the native CLI through npm:

npm install --global mindctl
mindctl version

npx mindctl version

The npm package includes the supported Linux, macOS, and Windows native binaries. Gateway mode still requires a runtime configuration file and the required environment variables.

Native binary

Download the archive for your platform from the GitHub Release, verify it against checksums.txt, unpack it, and run:

./mindctl version
./mindctl --config ./config.yaml

On Linux, run sha256sum --ignore-missing --check checksums.txt. On macOS, compare shasum -a 256 <archive> to the matching checksums.txt entry.

Homebrew

brew tap storm-software/mindctl https://github.com/storm-software/mindctl
brew install mindctl

Container

Pull a versioned image and mount a runtime configuration file:

docker pull ghcr.io/storm-software/mindctl
docker run --rm -p 8080:8080 \
  -v "$PWD/config.yaml:/etc/mindctl/config.yaml:ro" \
  --env-file .env \
  ghcr.io/storm-software/mindctl

The image runs as a non-root user and contains no usable configuration, credentials, encryption keys, or database. Mount a writable data volume and configure its SQLite path in config.yaml.

The GHCR package is public after its first release: an organization owner must set the package visibility to Public in GitHub Packages before advertising the image. Confirm an anonymous docker pull succeeds for the release tag.

Go Install

Install Mindctl using the Go toolchain:

go install github.com/storm-software/mindctl/cmd/mindctl@latest

From source

devenv shell -- go run ./cmd/mindctl --config ./config.yaml

Configuration

Mindctl reads one strict YAML document. Unknown fields and multiple YAML documents are rejected. Start from config.example.yaml, set the environment variables it names, and choose a writable SQLite database path.

When no --config argument is supplied, Mindctl resolves the configuration in this order:

  1. ${XDG_CONFIG_HOME}/mindctl/config.yaml, when that file exists. When XDG_CONFIG_HOME is unset, Mindctl uses ~/.config/mindctl/config.yaml.
  2. config.example.yaml, for source-checkout usage when no user config exists.

An explicit --config <path> always takes precedence. The legacy -config <path> spelling is also accepted. Installed binaries do not include config.example.yaml, so create the user configuration before running one without --config:

mindctl_config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/mindctl"
mkdir -p "$mindctl_config_dir"
cp config.example.yaml "$mindctl_config_dir/config.yaml"
chmod 700 "$mindctl_config_dir"
chmod 600 "$mindctl_config_dir/config.yaml"

The example configuration references environment variables rather than storing secret values. Export values for its gateway token, LAYA_CLASSIFIER_TOKEN, and encryption key before startup. Keep the configuration and SQLite database in locations the Mindctl process can read and write, respectively.

Container deployments should continue to mount the configuration explicitly at /etc/mindctl/config.yaml, as shown above; the image command supplies that path through its configuration flag.

Managed Headroom compression

Compression is opt-in:

headroom:
  enabled: true
  mode: cache # cache or token

On first use, an enabled installation may need network access and writable private cache storage to provision the pinned Headroom runtime. Mindctl sends only round-trip-safe assistant and string tool-result text to a loopback, token-authenticated child; provider credentials and inference requests never go to that child. Compression failures are fail-closed and return HTTP 503 with code headroom_unavailable; Mindctl never forwards the uncompressed request. Disable it by setting headroom.enabled: false and restarting.

Do not enable this option when another Headroom proxy already fronts Mindctl, or the request may be compressed twice.

Debug router traces

Set top-level debug: true, export MINDCTL_DEBUG=true, or start the gateway with --debug to write detailed JSONL traces to ${XDG_CACHE_HOME:-$HOME/.cache}/mindctl/logs. An explicit --debug=true|false overrides MINDCTL_DEBUG, which overrides the YAML value. Each gateway process creates a private trace file containing request IDs, derived feature counts, classifier signals, policy candidates and rejections, selected routes, provider attempts, and stream retries. Trace files exclude prompt and response content, credentials, request headers, and raw provider errors.

Model and provider availability

Mindctl can keep the routable model allow-list separate from the gateway catalog. The gateway reads ${XDG_STATE_HOME:-$HOME/.local/state}/mindctl/providers.yaml once during startup and caches the resulting availability in memory. When the file is absent, each model's available value in config.yaml remains authoritative. When the file exists, only the models listed in it are available:

providers:
  openai:
    - gpt-6-astra
    - gpt-6-sol
    - gpt-6-luna
    - gpt-5.6-sol
    - gpt-5.6-terra
    - gpt-5.6-luna
    - gpt-5.3-codex
    - gpt-5.3-codex-spark
  deepseek:
    - deepseek-flash

Use the catalog commands to inspect or update the file. The first update initializes it from the current available values, and changes take effect in the gateway after restart.

mindctl model list
mindctl model list --all
mindctl model enable openai.gpt-6-astra
mindctl model disable openai

mindctl provider list
mindctl provider list --all
mindctl provider enable openai
mindctl provider disable openai

Laya system 1 sidecar

The Laya classifier is optional. To launch the local sidecar, set a shared bearer token and start its opt-in Compose profile:

export LAYA_CLASSIFIER_TOKEN="$(openssl rand -hex 32)"
docker compose -f compose.laya.yaml --profile laya up --build -d

compose.laya.yaml keeps port 8091 inside the named mindctl Docker network; it does not publish a host port. Run the gateway in that network and configure the endpoint shown in config.example.yaml:

classifier:
  endpoint: http://laya:8091
  token_env: LAYA_CLASSIFIER_TOKEN

The sidecar requires Authorization: Bearer <LAYA_CLASSIFIER_TOKEN> on POST /v1/classify. It pins convaiinnovations/laya and the typed-decisions variant, downloads model files only on its first startup, and retains them in the laya-model-cache volume. Normal Go and Python tests do not download model weights.

For an operator-managed sidecar, point the same classifier: configuration at an absolute HTTPS endpoint instead. It must implement the documented mindctl.classifier.v1 bearer-authenticated /v1/classify contract; Mindctl continues to make deterministic routing decisions and falls back safely when the endpoint is unavailable.

Command Line Interface

The Mindctl command line interface provides several commands to manage the application, its configuration, models, and providers. A complete list of available commands can be found in the CLI documentation.

Check whether Codex or Claude Code is configured to use the Mindctl router:

mindctl status
mindctl status codex
mindctl status claude

The first command lists harnesses and their configuration status; the other commands print one status. Codex checks the top-level model_provider in ~/.codex/config.toml; Claude checks the global env.ANTHROPIC_BASE_URL in ~/.claude/settings.json against http://127.0.0.1:8080 (with one optional trailing slash). Neither command checks project-level or shell overrides or tests whether the gateway is running or reachable.

Development

Enter the repository's development environment before running Go commands:

devenv shell -- go test ./...

More information can be found in the Mindctl documentation.


Build

Run devenv shell -- goreleaser release --snapshot --clean to build local release archives in dist/ without publishing them.


Development Server

Run devenv shell -- go run ./cmd/mindctl to start the gateway with the home configuration when present, or pass --config ./config.yaml to use a project- local file explicitly.


ChatGPT subscription routing

Mindctl can route Codex requests through the ChatGPT account already signed in to Codex. Configure Mindctl with chatgpt_oauth_passthrough as shown in config.example.yaml or your active configuration file, then add this custom provider to the Codex config.toml:

model = "mindctl-auto"
model_provider = "mindctl"

[model_providers.mindctl]
name = "Mindctl"
base_url = "http://127.0.0.1:8080/v1"
wire_api = "responses"
requires_openai_auth = true
env_http_headers = { "X-Mindctl-Token" = "MINDCTL_GATEWAY_TOKEN" }

mindctl-auto enables Mindctl's automatic routing. A concrete model name is an explicit selection and must match a model ID in Mindctl's configured catalog. Set explicit_only: true on a catalog model reserved for explicit requests, such as a dedicated approval reviewer. Mindctl keeps it out of automatic routing, classifier choices, and fallback candidates; an explicit request still requires normal model availability, capabilities, tier bounds, and provider credentials. The default is false for existing models. An explicit-only model's failed stream does not escalate to a different model.

With chatgpt_oauth_passthrough, Mindctl adds codex-auto-review to the effective OpenAI catalog as an available, explicit-only model; no YAML model entry is needed. API-key providers do not get this entry. A manually configured codex-auto-review entry is retained only when it belongs to openai and has explicit_only: true; otherwise configuration loading fails. Its catalog capacity and capabilities are local routing settings, not a guarantee of account access or upstream limits. If providers.yaml already exists and omits it, enable the reviewer with mindctl model enable openai.codex-auto-review and restart the gateway.

Sign in to Codex with ChatGPT and export MINDCTL_GATEWAY_TOKEN with the same gateway token supplied to Mindctl. Do not set OPENAI_API_KEY for this provider. Codex owns OAuth login and token refresh; Mindctl forwards the request-scoped credential only to the configured ChatGPT Codex endpoint.

Available models, workspace access, rate limits, and usage limits remain subject to the selected ChatGPT account and subscription. The shipped ChatGPT Pro catalog includes gpt-6-astra, gpt-6-sol, gpt-6-luna, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.3-codex, and the Pro-only research preview gpt-5.3-codex-spark. GPT-6 model access is currently rolling out and may not yet appear for every Pro account.


Claude subscription routing

Mindctl can also route requests through a caller-managed Claude subscription credential. Generate a long-lived token with claude setup-token, export it as CLAUDE_CODE_OAUTH_TOKEN, and configure the Anthropic provider with claude_oauth_passthrough as shown in config.example.yaml.

Add the Claude credential to the Codex provider's environment-backed headers:

[model_providers.mindctl]
name = "Mindctl"
base_url = "http://127.0.0.1:8080/v1"
wire_api = "responses"
requires_openai_auth = true
env_http_headers = { "X-Mindctl-Token" = "MINDCTL_GATEWAY_TOKEN", "X-Mindctl-Claude-Token" = "CLAUDE_CODE_OAUTH_TOKEN" }

Codex sends the Claude token to Mindctl on each request. Mindctl keeps it in request context only, makes subscription-backed Anthropic models eligible for that request, and forwards it to the configured Anthropic endpoint as a bearer credential. Mindctl does not store, refresh, or log the token.

The shipped catalog includes Claude Fable 5.1, Opus 5.5, Sonnet 5, and Haiku 4.5 with comparable Claude API prices for routing decisions. Actual usage is governed by the selected Claude subscription's model access and plan limits, not API token billing.

Claude Code Messages endpoint (opt-in)

To route Claude Code itself, set client_auth.header: X-Mindctl-Token and claude_messages.enabled: true in the gateway configuration. Configure the Anthropic provider with claude_oauth_passthrough and the models you want in the Mindctl catalog. The endpoint is POST /v1/messages; it is absent by default, and /v1/responses keeps its existing authentication behavior.

Set only the non-secret gateway origin in your global Claude settings:

{"env":{"ANTHROPIC_BASE_URL":"http://127.0.0.1:8080"}}

Let Claude Code retain its native subscription login. Do not set ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY, or an apiKeyHelper for this connection. Supply the separate gateway token from your existing secret store in a trusted launcher instead of checking it into Claude settings:

#!/bin/sh
: "${MINDCTL_GATEWAY_TOKEN:?load the gateway token from your secret store}"
export ANTHROPIC_CUSTOM_HEADERS="X-Mindctl-Token: ${MINDCTL_GATEWAY_TOKEN}"
exec claude "$@"

mindctl-auto can choose any eligible configured provider. A subscription credential is sent only to the Anthropic OAuth provider; other providers require their own API credentials and may incur separate billing. A specific model must match a Mindctl catalog ID; configure Claude Code's main and background model overrides deliberately, as built-in aliases are not automatically remapped. Signed thinking restricts a turn to Anthropic.

For an existing Home Manager setup managed by Headroom, choose Mindctl explicitly in that separate configuration before enabling this setting; to roll back, restore Headroom's ANTHROPIC_BASE_URL and remove the launcher header. Mindctl does not change the managed settings automatically. Confirm the actual login and a streamed tool round-trip in a live Claude Code session before relying on the connection.


Roadmap

See the open issues for a list of proposed features (and known issues).


Contributing

First off, thanks for taking the time to contribute! Contributions are what makes the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are greatly appreciated.

Please try to create bug reports that are:

  • Reproducible. Include steps to reproduce the problem.
  • Specific. Include as much detail as possible: which version, what environment, etc.
  • Unique. Do not duplicate existing opened issues.
  • Scoped to a Single Bug. One bug per report.

Please adhere to this project's code of conduct.

You can use markdownlint-cli to check for common markdown style inconsistency.


Support

Reach out to the maintainer at one of the following places:


License

This project is licensed under the Apache License 2.0. Feel free to edit and distribute this template as you like. If you have any specific questions, please reach out to the Storm Software development team.

See LICENSE for more information.


FOSSA Status


Contributors ✨

Thanks goes to these wonderful people (emoji key):

Patrick Sullivan
Patrick Sullivan

🎨 💻 🔧 📖 ⚠️
Tyler Benning
Tyler Benning

🎨
Stormie
Stormie

🚧
Add your contributions

This project follows the all-contributors specification. Contributions of any kind welcome!




Storm Software

Fingerprint: F47F 1853 BCAD DE9B 42C8 6316 9FDE EC95 47FE D106

Storm Software is an open source software development organization and creator of Acidic, StormStack and StormCloud.

Our mission is to make software development more accessible. Our ideal future is one where anyone can create software without years of prior development experience serving as a barrier to entry. We hope to achieve this via LLMs, Generative AI, and intuitive, high-level data modeling/programming languages.

Join us on Discord to chat with the team, receive release notifications, ask questions, and get involved.

If this sounds interesting, and you would like to help us in creating the next generation of development tools, please reach out on our website or join our Slack channel!


Storm Software

Visit us at stormsoftware.com



About

An LLM router that uses built-in logic and system 1 decision models to intelligently route requests to the appropriate LLM based on the input prompt

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages