Release v0.17

v0.17 Release: Edit Manifests in the Browser, and Make Everything Else Work

October 2026 · The Smarter Project

v0.16 added four resource kinds: LLMHost, Proxy, Budget and Vectorstore. v0.17 adds almost nothing new. It is about making what already exists work, and tell you why when it doesn’t.

We raised the unit test coverage of Smarter’s Django apps from 85% to almost 90%. The new tests found more than 120 bugs, and this release fixes them. Before v0.17, 71 tests were marked as expected failures, which meant “we know this is broken”. Now there are none. Along the way we added a few features that make the platform easier to use day to day:

ChangeWhat it does
Manifest editorEdit, validate, save, clone and delete any resource’s manifest on its page in the web console.
Errors that make senseapply and prompt return the right status code and a message that names the problem, instead of a 500.
Separate infrastructure workerSlow deployments run on their own Celery worker, so chat history, charges and scheduled jobs are never stuck behind them.
A live dashboardReal service health checks, recent activity, budget alerts, a getting-started checklist and quick links.
A better built-in assistantThe smarter LLMClient answers from the docs and code on GitHub, and from a web search, instead of a 2023 sales script.
Prompt passthroughThe passthrough page works with every provider and every template, including OpenAI’s newest models.

Each change is described below.


Edit manifests in the web console

Every resource in the web console has a detail page that shows its manifest. Until now, that manifest was read-only. To change a resource, you copied the YAML into a file, edited it, and ran smarter apply.

In v0.17, the manifest on each of the 15 detail pages is an editor. It uses Monaco, the editor that VS Code is built on, with YAML highlighting. Its toolbar has:

  • Save, which applies the edited manifest, the same as smarter apply.
  • Clone, which applies a copy under a new metadata.name.
  • Delete, which is disabled while other resources depend on this one (see status.dependencies in the v0.16 release).
  • Undo and redo, copy and paste, revert to the saved version, and download.

Errors while you type

As you edit, the editor checks the YAML syntax, and then validates the manifest against its kind’s schema on the server. Each error is underlined on its line and listed below the editor. Click an error to jump to it. Save stays disabled until the manifest is valid.

The editor uses a new API command, validate, which you can also call yourself. POST /api/v1/cli/validate/ checks a manifest without saving it. An invalid manifest is still a successful validation, so the status is 200 either way. The response’s data says whether the manifest is valid, and lists each problem with its location in the manifest:

{
  "valid": false,
  "errors": [
    {
      "loc": ["spec", "config", "defaultTemperature"],
      "message": "Input should be less than or equal to 1",
      "type": "less_than_equal"
    }
  ]
}

Security

The editor uses the same apply, validate and delete APIs as the CLI, with your web console session and its CSRF token, and those APIs apply the same rules as they do for the CLI. A request with a session but no CSRF token is refused.

The editor also fixes a quiet data problem. The old read-only page removed every apostrophe and backslash from the manifest it showed. A manifest is now passed to the page exactly as stored, so saving it from the editor can’t damage it.

📖 Web console documentation


Errors that tell you what’s wrong

Before v0.17, many mistakes in a manifest came back from smarter apply as HTTP 500, “No broker found for manifest kind”. That message was wrong, and the status said the server was at fault when it wasn’t. A misspelled key was worse: Smarter ignored it without a word, and you found out later that your setting had no effect.

Now:

  • Validation errors are 400s that name the field, the problem and your value, for example config.defaultTemperature: Input should be less than or equal to 1 (got 2.5).
  • Unknown keys are refused. Every kind returns a 400 that lists the keys its schema doesn’t define, so defaultTemperatura is caught when you apply it, not a week later.
  • An empty or unparseable body, an unknown kind, or a missing metadata or spec is a 400. Bad YAML returns the parser’s own error.
  • Only a real server error is a 500, and only a 500 asks you to report a bug.
  • LLMClient values are checked before they’re saved. An unknown or wrongly cased provider, an invalid URL, a value that’s too long, or a system prompt over the documented 2,048 characters is a 400, instead of a saved record or a database error.

Prompts got the same treatment. When the LLM provider returns an error, such as a 400 or 404 from OpenAI, Smarter now returns that status and the provider’s message. It used to return a 200. A connection error is a 502 and a timeout is a 504.


Slow infrastructure work no longer blocks everything else

Deploying an LLMClient creates a DNS record, a Kubernetes ingress and a TLS certificate, and then waits for them. That takes minutes, sometimes hours. Those deployment tasks ran on the same Celery worker as the quick, everyday tasks: saving chat history, recording charges, logging plugin use.

In practice, deploying the built-in LLMClients kept all four worker processes busy for half an hour, while dozens of everyday tasks waited. Because chat history wasn’t saved, the next prompt in a conversation with tool calls failed.

v0.17 fixes this in three ways:

  • A separate worker for infrastructure. Deploying, verifying and deleting LLMClient domains and certificates, launching and destroying LLMHosts, reconciling GPU node groups, and Vectorstore snapshots and maintenance now run in their own queue, on a new smarter-worker-infrastructure worker. Everyday tasks keep their worker to themselves.
  • Tasks don’t sleep. Tasks that waited for a certificate or a DNS record used to sleep inside the worker, often until Celery’s 30-minute time limit killed them. Now each task checks once and schedules its next check, so a worker is never held up waiting.
  • Scheduled jobs run. Every Celery Beat job was sent to a queue that no worker read, so none of them ever ran, in any environment. That includes the hourly Budget evaluation, charge aggregation, LLMHost compute charges and status refreshes, and Vectorstore and node group reconciliation. They all run now.

The decision is recorded in ADR-030: Task queues.


A dashboard that shows what’s happening

The dashboard’s Service Health score was always 100, and every check was always green, because none of them were real. In v0.17 it checks the database, the cache, the Celery broker and the Celery workers, and the score is the share of checks that pass.

The dashboard also has four new widgets:

  • Recent activity: your last 10 apply, deploy, undeploy and delete commands, with failures highlighted. It needs the journal to be on (the enable_journal switch).
  • Getting started: a checklist for new users: create an API key (for staff), a Secret, an LLMClient and a Plugin, and deploy. It hides itself when every step is done.
  • Budget alerts: a banner for each Budget that is locked, or has used 80% or more of a limit.
  • Quick actions: links to the console pages people use most.

Live widgets are now at the top, and the static ones (What’s New, the certificate program, the SDK, CLI and self-hosting cards) are at the bottom.


A built-in assistant that knows the current Smarter

Smarter ships with an LLMClient named smarter that answers questions about The Smarter Project. Its system prompt and its main plugin, about_smarter, were written in 2023 for a SaaS product that no longer exists, with pricing, sales scripts and statistics that had gone stale.

In v0.17 it gets its answers from current sources:

  • Seven new built-in MCPClients, one for each of the project’s GitHub repositories, through GitMCP: smarter-sh/smarter (which contains the docs), smarter-cli, smarter-python, smarter-vscode-yaml, smarter-infrastructure, smarter-chat and smarter-deploy. Each client can read only its own repository.
  • A new web search plugin, smarter_project_websearch, which uses Tavily to search reputable sources for The Smarter Project.
  • A rewritten system prompt that describes Smarter as free, open-source software that organizations run on their own cloud, tells the model to answer only from its tools, and treats web pages as information, not instructions.
  • about_smarter is deleted.

The MCPClients are ordinary manifests, and a good example of how to give an LLMClient read-only access to a repository:

apiVersion: smarter.sh/v1
kind: MCPClient
metadata:
  name: smarter_project_github
  description: Reads and searches the documentation and source code of smarter-sh/smarter.
  version: 1.2.0
spec:
  config:
    transport: http
    endpointUrl: https://gitmcp.io/smarter-sh/smarter
    authType: none
    allowedTools:
      - fetch_smarter_documentation
      - search_smarter_documentation
      - search_smarter_code
    includeInstructions: true
    timeout: 30
    cacheTtl: 3600

allowedTools leaves out GitMCP’s tool that fetches any URL, so the model reads only this repository.

Current OpenAI models

The list of OpenAI chat models that Smarter accepts went from 76 entries to 27. We checked each one against OpenAI’s model list and deprecation page on 4 October 2026, and sent each a real request. Deprecated models (the gpt-3.5 and gpt-4 families, gpt-4-turbo, gpt-5, gpt-5.1, o1, o3, o4-mini and others), models that only the Responses API serves, and models that aren’t chat models were removed. The gpt-5.2, gpt-5.4, gpt-5.5, gpt-5.6 and gpt-6 models were added.

📖 Tavily setup · MCPClient documentation


Prompt passthrough works with every provider

The web console’s prompt passthrough page sends a raw request to a provider, from one of three templates: Hello World, Message Roles and Function Call. It failed with OpenAI’s current models, which reject max_tokens. When we tested every template against every provider, 15 of 24 combinations failed.

  • For OpenAI, Smarter renames max_tokens to max_completion_tokens. Other providers still get max_tokens, which some of them require.
  • Some OpenAI reasoning models accept function tools only when reasoning_effort is none. When OpenAI refuses a request for exactly that reason, Smarter retries it once with reasoning_effort: none and logs a warning that says so.
  • The Function Call template uses tools instead of the legacy functions field, which Google AI rejects. Templates no longer set a temperature, which reasoning models reject.
  • Provider settings are corrected: Cohere uses its OpenAI-compatible endpoint and command-a-03-2025 (command-r-plus was retired). Fireworks and Together AI default to gpt-oss-120b, instead of models from other providers that had been copied in by mistake. Meta AI’s base URL is corrected. Together AI’s model list is stored again; a parsing bug had stopped the whole provider setup.

A new test sends every template to every provider, so a template added later is tested automatically.


Behavior changes you may notice

  • Unknown manifest keys are refused with a 400 (see above). We removed the ones in Smarter’s own manifests, such as dnsVerificationStatus in 21 LLMClients. Check your own manifests before you upgrade.
  • A plugin no longer changes the LLMClient’s model. A selected plugin used to replace the LLMClient’s model, temperature and token limit with the values in its own spec.prompt. Now the LLMClient’s settings are always used, so the model you applied is the model that’s called.
  • The default temperature is 1.0, which the default model, gpt-6-luna, requires.
  • Plugin parameters use boolean, not bool. boolean is what JSON Schema, OpenAI and Smarter’s own plugin manifests use, but the validator refused it and accepted bool. Now it’s the other way around.
  • spec.config.subdomain and customDomain on an LLMClient are set when it’s deployed. Setting them in a manifest is a 400, and apply no longer clears them, which could have unlinked a deployed LLMClient’s DNS record.
  • Anonymous requests to the admin APIs get 401, not 403.
  • Applying a Prompt is refused with 405, because Prompts are read-only. describe works for them now.

Security fixes

The new tests found several places where Smarter checked less than it should have. We know of no exploitation of any of them, but you should upgrade.

  • API keys: an account admin could activate, deactivate or edit another account’s API key with a JSON PATCH. It now returns 403.
  • LLMClient configuration: any signed-in user could read any account’s LLMClient configuration from the prompt configuration page, and the IDs could be guessed. A configuration you can’t read is now a 404.
  • Resource counts: the dashboard’s My Resources widget showed every user the first user’s counts, because of a cache key that didn’t include the user.
  • Database passwords: with debug mode on, a failed SQL connection could put the database password in the logs and in the error returned to the client. The connection string is always masked now.
  • User API: a superuser-only endpoint ignored the results of its own checks, and let a request set any user field, including is_superuser. It wasn’t reachable by anyone but superusers, but the checks now apply, and only the usual profile fields can be set.

Web console improvements

  • Toolbar colors: Edit and Rename icons are blue, Clone is green, Delete is red, and Chat and Copy URL are teal. Disabled buttons are gray and still show the tooltip that explains why.
  • Clone, rename and delete work on the Connections, Providers, Orchestrators, Secrets, Vectorsearches and AuthTokens list pages, where they were refused or failed. Cloning a connection now creates a real copy.
  • Detail pages: the Vectorsearch and Orchestrator pages showed their resource as a Provider, the LLMClient manifest page and the page after creating an API key returned a 500, and the billing address form never saved. All fixed.

Fixes and operations

  • The journal was never written. Every journal entry failed because of a wrong field name, and the error was only logged. Journal entries are saved now, including for anonymous requests.
  • API key authentication in one code path never found the user of a real key. It now checks keys the same way the rest of Smarter does, and an inactive key is anonymous.
  • The Vectorsearch, LLMClient and Orchestrator REST APIs (/api/v1/...) failed on every request, most with a 500. They work now, and their LLMClient plugin, API key and custom domain sub-resources too. Attaching a custom domain that another LLMClient uses returns 409.
  • Updating a plugin through the REST API never worked: every PUT, POST or PATCH returned a 500 or a 400. It works now.
  • Applying a Provider manifest was always a 500, and no provider could be verified. Both work now.
  • Applying an existing Secret failed with a database error instead of updating it.
  • Undeploying an LLMClient now removes its DNS record. It used to stay in public DNS.
  • Deleting an LLMClient whose account was being deleted never removed its DNS record, ingress and certificate. It does now.
  • Deleting a Kubernetes resource that’s already gone is no longer reported as a failure.
  • deploy_builtin_llmclients stopped at the first manifest that failed. It now applies each one in its own transaction and continues with the next.
  • The excessive-404 middleware never blocked anyone, and several middlewares returned an unawaited coroutine in async mode. Both fixed.
  • Shared Google service account: another account’s Secret with the same name could break the platform’s Google AI integration. The lookup is now scoped to the platform admin.
  • Example manifests: the User example published the platform admin’s real email address and account number in the docs. It uses placeholders now. generate_example_manifests writes all 12 examples again.
  • Management commands: verify_api_v1_cli_endpoints could not run at all, send_welcome_email sent two emails, and rerunning create_smarter_admin created a new API key each time. All fixed.

Upgrading

  • Run the new infrastructure worker. Docker Compose has a new smarter-worker-infrastructure service, and the Helm chart has a new workerInfrastructure deployment. Without it, LLMClient deployments, LLMHost launches and Vectorstore maintenance sit in their queue. The queue name is set by INFRASTRUCTURE_TASKS_CELERY_TASK_QUEUE (default infrastructure_celery_task_queue).
  • Upgrade every worker and Celery Beat together with the app. Some task arguments changed, and an old worker refuses tasks queued by the new code.
  • Expect scheduled jobs to start. Because Celery Beat’s jobs never ran before, the first hourly run will evaluate your Budgets and may lock resources that are already over budget.
  • Check your manifests for unknown keys and old models. Manifests with keys their kind doesn’t define, plugins with a bool parameter, and plugins that name a removed OpenAI model such as gpt-4-turbo no longer validate. OpenAI shuts down gpt-4-turbo on 23 October 2026 anyway.
  • Optional: set TAVILY_API_KEY (or SMARTER_TAVILY_API_KEY) to deploy the built-in smarter LLMClient. Without it, that one LLMClient isn’t deployed; the other built-in LLMClients aren’t affected.
  • Run the migrations. This release adds journal migration 0006 and provider migration 0003.
  • manage.py initialize_platform loads the seven new GitHub MCPClients and the web search plugin, and no longer loads about_smarter.

What’s next

With the bug backlog cleared and coverage near 90%, the next step is to raise every app to at least 95%, and to keep the expected-failure list at zero. Then we’ll return to the plan from v0.16: LLMClients that use your self-hosted LLMHost models, and Vectorsearch that uses your Vectorstores, so that a complete RAG application on models you host is a few manifests.

The full list of changes is in the v0.17 changelog. To try the release, start with the documentation, or browse the code on GitHub.