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:
| Change | What it does |
|---|---|
| Manifest editor | Edit, validate, save, clone and delete any resource’s manifest on its page in the web console. |
| Errors that make sense | apply and prompt return the right status code and a message that names the problem, instead of a 500. |
| Separate infrastructure worker | Slow deployments run on their own Celery worker, so chat history, charges and scheduled jobs are never stuck behind them. |
| A live dashboard | Real service health checks, recent activity, budget alerts, a getting-started checklist and quick links. |
| A better built-in assistant | The smarter LLMClient answers from the docs and code on GitHub, and from a web search, instead of a 2023 sales script. |
| Prompt passthrough | The 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.dependenciesin 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.
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
defaultTemperaturais caught when you apply it, not a week later. - An empty or unparseable body, an unknown kind, or a missing
metadataorspecis 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-infrastructureworker. 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,undeployanddeletecommands, with failures highlighted. It needs the journal to be on (theenable_journalswitch). - 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-chatandsmarter-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_smarteris 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_tokenstomax_completion_tokens. Other providers still getmax_tokens, which some of them require. - Some OpenAI reasoning models accept function tools only when
reasoning_effortisnone. When OpenAI refuses a request for exactly that reason, Smarter retries it once withreasoning_effort: noneand logs a warning that says so. - The Function Call template uses
toolsinstead of the legacyfunctionsfield, 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-pluswas retired). Fireworks and Together AI default togpt-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
dnsVerificationStatusin 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, notbool.booleanis what JSON Schema, OpenAI and Smarter’s own plugin manifests use, but the validator refused it and acceptedbool. Now it’s the other way around. spec.config.subdomainandcustomDomainon an LLMClient are set when it’s deployed. Setting them in a manifest is a 400, andapplyno 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.
describeworks 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,POSTorPATCHreturned 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_llmclientsstopped 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_manifestswrites all 12 examples again. - Management commands:
verify_api_v1_cli_endpointscould not run at all,send_welcome_emailsent two emails, and rerunningcreate_smarter_admincreated a new API key each time. All fixed.
Upgrading
- Run the new infrastructure worker. Docker Compose has a new
smarter-worker-infrastructureservice, and the Helm chart has a newworkerInfrastructuredeployment. Without it, LLMClient deployments, LLMHost launches and Vectorstore maintenance sit in their queue. The queue name is set byINFRASTRUCTURE_TASKS_CELERY_TASK_QUEUE(defaultinfrastructure_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
boolparameter, and plugins that name a removed OpenAI model such asgpt-4-turbono longer validate. OpenAI shuts downgpt-4-turboon 23 October 2026 anyway. - Optional: set
TAVILY_API_KEY(orSMARTER_TAVILY_API_KEY) to deploy the built-insmarterLLMClient. Without it, that one LLMClient isn’t deployed; the other built-in LLMClients aren’t affected. - Run the migrations. This release adds journal migration
0006and provider migration0003. manage.py initialize_platformloads the seven new GitHub MCPClients and the web search plugin, and no longer loadsabout_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.
