Changelog
Every release of Manifest, straight from GitHub.
July 2026
-
View release on GitHub →
🐛 Patch Changes
- 46a09a8: Fix waitlist sync reading email from session instead of empty tenant field, rename table to waitlist_claims
-
View release on GitHub →
🐛 Patch Changes
-
b2b95f0: Preserve route metadata on streamed provider errors so message logs keep model and provider fields.
-
3dd41a1: fix: Gemini adapter — strip unsupported schema keywords, merge parallel tool responses, and inject missing thought signatures
The Gemini adapter now strips additional JSON Schema keywords that Google’s
function_declarationsparameter schema rejects (propertyNames,uniqueItems,multipleOf,contains/minContains/maxContains,prefixItems,additionalItems,readOnly,writeOnly,deprecated, and$comment/$anchor/$dynamicRef/$dynamicAnchor/$vocabulary).It merges consecutive parallel tool responses into a single Gemini user turn, matching Google’s requirement that N functionCall parts be answered by exactly N functionResponse parts in one turn.
When a functionCall part has no
thought_signaturefrom the client or cache (e.g. after a fallback from another model), the adapter now injects the documented dummy signature so Gemini 3.x does not reject the request with “Function call is missing a thought_signature”. -
3b2bbd9: Self-hosted waitlist claims now sync to the cloud instance
-
-
View release on GitHub →
🐛 Patch Changes
- 4e3fdde: Report Claude Opus 4.8 with a 1M context window for Anthropic subscription routing.
- a0f5549: Preserve Responses reasoning summaries when Copilot responses-only models are used through Chat Completions.
- aafa8d4: Record DeepSeek prompt cache hits from
prompt_cache_hit_tokens. - 6ce3a9d: Send Fireworks prompt cache keys from Manifest sessions.
- 4c9335e: Mark MiniMax Coding Plan subscriptions as prompt-cache capable.
- ff48cfb: Send Moonshot prompt cache keys and record Kimi cached tokens.
- 884170d: Preserve author-prefixed Ollama model IDs when proxying requests.
- a4fd8aa: Stop forwarding Anthropic-style thinking params to Ollama endpoints.
- d329f57: Send Qwen cache-control markers and mark Qwen subscriptions cacheable.
- 09d904a: Remove the proxy message-count limit so long agent sessions are bounded by request body limits instead.
- f1a5243: Mark Xiaomi MiMo Token Plan subscriptions as prompt-cache capable.
- 0cc5520: Mark Z.ai Coding Plan subscriptions as prompt-cache capable.
-
View release on GitHub →
🐛 Patch Changes
- 7ca120b: Enable prompt caching support metadata for Anthropic subscriptions and send first-party subscription requests with Anthropic automatic cache control.
- a46c3dc: Mark Gemini subscriptions as supporting prompt caching in shared provider metadata.
- dc3c4a9: Send stable prompt cache keys to Mistral when callers do not provide one.
- abec177: Mark OpenAI subscriptions as supporting prompt caching in shared provider metadata.
- fb63274: Add OpenRouter prompt cache breakpoints for Gemini and Qwen model families.
- 22a15a4: Send prompt cache keys to xAI Responses requests from Manifest session affinity.
-
View release on GitHub →
🐛 Patch Changes
- fef144a: Show explicit SDK model overrides as Direct in Messages.
- 5572692: Update the shipped modal for OpenAI-compatible model discovery and direct model calls.
- f8a5a5d: Lead README, Docker docs, and app meta tags with connecting agents to any provider instead of cost savings.
June 2026
-
View release on GitHub →
✨ Minor Changes
- 8956f43: Stop storing full message request/response bodies. The Messages page keeps the per-message metadata view (status, model, provider, tokens, cost, routing, request headers, model parameters) but the recorded-body drawer is removed. A migration drops the
message_recordingstable and the unusedllm_calls/tool_executions/agent_logstables, significantly reducing database storage.
🐛 Patch Changes
- b27a16e: Stop index migrations from deadlocking deploys against live traffic. The agent_messages index migrations used blocking DDL (plain CREATE/DROP INDEX), which takes an ACCESS EXCLUSIVE lock and deadlocked against live INSERTs while the previous deployment was still serving — failing every deploy and leaving the schema (and the dashboard perf work) unshipped. Those migrations now run CONCURRENTLY (SHARE UPDATE EXCLUSIVE, which does not conflict with writes) outside a transaction, and the migration runner uses per-migration (‘each’) transactions. The covering index also builds without a write stall.
- 88a8590: Add a timestamp-leading partial index for cross-tenant error scans. The Cloud control plane’s hourly error-insights rollup scans agent_messages by time window across all tenants, but the only error index was tenant-leading — so each run scanned every error row ever recorded (cost growing with total accumulated errors), which turned into multi-minute scans that saturated the database. A timestamp-leading partial index over error rows turns those into windowed range scans (measured 110ms/29k buffers down to 2ms/274 buffers on ~2M error rows). The index stays partial so write amplification on ingest is negligible.
- 29ee8be: Speed up the dashboard, message log, and provider/subscription lists for high-volume tenants. Distinct model/provider lookups now use an index skip-scan instead of scanning a tenant’s whole history, and the Overview derives its summary cards from the timeseries it already fetches (one fewer full-range scan). A covering index lets the Overview summary, timeseries, and cost-by-model aggregations run as index-only scans on every install (previously self-hosted had none). Postgres planner defaults (JIT off, larger work_mem, SSD-tuned random_page_cost) plus tighter autovacuum on agent_messages keep those aggregations off the heap, and a redundant index is dropped to lighten ingest.
- 46c88c2: Lazy-load hidden token and cost chart series on agent overview.
- 1591e53: Name the affected agent when provider disconnect is blocked by routing.
- 8fb56c1: Speed up provider disconnect route checks and ignore disabled route rows.
- e266b8e: Support large OpenAI-compatible inline image requests on
/v1/*with route-scoped body parsing, clear body-size errors, and redacted inline image data for routing and message recordings. - 49ef687: Start retiring complexity and task-specific routing. Agents that never configured them now see only Default and Custom routing, so the routing page is simpler for new and unconfigured agents. Agents already using complexity tiers or task-specific categories keep everything working and see a banner explaining the change.
- 0501bb0: Improve the agent routing empty state contrast in dark mode.
- 5eec940: Stop deploys from deadlocking on database migrations. Migrations ran on every replica’s boot over PgBouncer, so multi-replica deploys with pending migrations could deadlock acquiring locks on agent_messages and fail. Migrations now run once in a pre-deploy step over the direct connection (with an advisory lock so overlapping deploys serialize), before any replica starts. App-boot migration is now configurable (RUN_MIGRATIONS_ON_BOOT, default on for dev and single-instance self-hosted). The migration runner also uses the committed migration list instead of a compiled-file glob, so stale build artifacts from deleted migrations can never run.
- 100a3b4: Run database migrations under a Postgres advisory lock so concurrent runners serialize instead of deadlocking. When more than one process ran migrations at once (overlapping deployments, or replicas across regions), they could deadlock acquiring DDL locks on the high-churn agent_messages table and fail the deploy. The deploy migration step now takes a single advisory lock over the direct migration connection: the first runner applies every pending migration, the rest wait and then find nothing pending. Single-instance and self-hosted deploys are unaffected.
- ca62d7b: Clarify Xiaomi MiMo Basic API-key setup by linking directly to the API Keys console and validating the documented
sk-xxxxxpay-as-you-go key shape separately from Token Plantp-credentials.
- 8956f43: Stop storing full message request/response bodies. The Messages page keeps the per-message metadata view (status, model, provider, tokens, cost, routing, request headers, model parameters) but the recorded-body drawer is removed. A migration drops the
-
View release on GitHub →
✨ Minor Changes
- e30e0e9: Add global provider pages (ConnectProvider, ProviderDetail, AgentProviders tab) and lift provider connections from per-agent to user-scoped. Remove agent H1 header block from AgentDetail shell.
- 21f0981: Tenant-canonical scoping: every resource now belongs to a tenant instead of a user. The
user_providerstable is renamed totenant_providers(junction columnuser_provider_id→tenant_provider_id),api_keys,email_provider_configs, andcustom_providersare re-keyed bytenant_id, and the remaininguser_idscope columns are dropped from routing/notification/playground tables (kept only as nullablecreated_by_user_idaudit columns). Self-host operators querying the database directly should note the table/column renames; migrations run automatically on boot and abort with a clear message if orphaned rows are found (setMANIFEST_MIGRATION_FORCE=1to delete them instead).
🐛 Patch Changes
- e30e0e9: “View more” on a harness’s recent messages now opens the global Messages log pre-filtered to that harness.
- e30e0e9: The per-agent Overview now breaks usage down by provider (chart + provider filter), matching the global Overview.
- e30e0e9: Restructure agent detail view into a horizontal-tabbed shell (Overview / Routing / Guardrails / Settings) with back-link navigation. Unify sidebar to a single global nav (Overview / Messages / Agents) rendered identically on every authenticated route; remove the agent-scoped MONITORING/MANAGE/RESOURCES sub-nav.
- 7aa49e5: A newly added provider key no longer shows another key’s usage on its connection page — per-connection analytics now attribute every message to the exact connection that served it, instead of grouping by provider, auth type, and label.
- 19b9b9e: Add AWS Bedrock as an API-key provider using Bedrock Mantle’s OpenAI-compatible endpoints. Bedrock vendor-prefixed model IDs now resolve model parameters, pricing, and capabilities through the underlying provider metadata while keeping the original Bedrock ID for inference.
- 548a836: Fix Claude Code subscription routing for Anthropic Messages requests by capping Manifest-added
cache_controlmarkers at Anthropic’s four-block limit, enabling thecontext_managementbeta header expected by recent Claude Code clients, and downgradingoutput_config.effort: "xhigh"when routing resolves to Sonnet. - e30e0e9: Custom providers now display their name and models consistently across Messages, Overview, graphs and cost tables — the literal “custom:” prefix is gone and names resolve on global pages too (the backend resolves them, so deleted providers degrade gracefully).
- 550d2a4: Restore the “Add custom provider” button on the Usage-based page and use a dedicated modal for creating and editing custom providers
- 30539c2: Deleting a custom provider can no longer leave orphaned key or routing data behind: the link between custom providers and their stored keys is now enforced by the database (with automatic cleanup of any pre-existing orphans), and creating or deleting a custom provider is atomic.
- 8df85b4: Speed up global overview and Messages by collapsing overview usage timeseries queries and letting Messages load rows before exact totals/filter metadata.
- fd5bc63: Connecting a provider right after creating your first agent no longer fails with “Tenant not found” for several minutes — newly created workspaces are now visible to the dashboard immediately. When a database migration fails on startup, the logs now show the real migration error instead of a misleading “Unable to connect to the database” retry loop.
- e30e0e9: Add global dashboard with Overview, Messages, and Agents navigation for tenant-wide usage analytics.
- e30e0e9: Local providers (sidebar tab, page and overview card) are hidden on cloud — they only apply to self-hosted installs.
- 0efdb6b: Add Kiro IAM Identity Center start URL and region options to the subscription login flow.
- e30e0e9: Fix token/cost limits never blocking (or alerting) when the server’s timezone isn’t UTC.
computePeriodBoundaries/computePeriodResetDatebuilt their window in UTC, butagent_messages.timestamprows are stored in the process’s local time — so on a non-UTC host the window’s upper bound sat behind the stored rows by the TZ offset and the consumption SUM read ~0, meaning hard limits silently never tripped and threshold alerts never fired. Boundaries are now computed in local time (matchingcomputeCutoff), via a newtoLocalSqlTimestamphelper. - 2f2c8e1: Harden provider connection attribution and analytics before release. A subscription a user removed is no longer silently brought back by an agent’s background re-registration. Pre-upgrade message history now attributes to the right connection for users who had the same provider on multiple agents. The dashboard overview keeps Playground traffic out of every card and chart consistently, and the provider-key cache is no longer bypassed on the proxy path.
- 28dbedb: Provider connections lifted from per-agent keys now get clearer names (e.g. “from Agent A”) instead of the bare agent name.
- 3bb50ae: Provider migrations can now be rolled back without dropping connected providers.
- ed58472: Removed the leftover savings/baseline cost tracking (database columns and proxy-side computation) now that the dashboard no longer shows savings.
- e30e0e9: Removed the Subscription Savings card, chart, explainer and its API endpoints.
- 97b401a: Rename the agent_provider_access table to agent_enabled_providers so the database, API routes, and dashboard all use the same “enabled providers” naming. The migration is a pure rename — no data is modified — and rolls back cleanly.
- e30e0e9: Fix the post-create “Set up harness” modal showing the full harness picker instead of the harness you just chose. AgentGuard now refetches the agent list when the viewed agent changes, so a newly created agent’s platform reaches the setup modal (previously the stale, source-less list left the platform unset whenever the agent was created from the always-present sidebar while another agent was open).
- 2492e76: Harden the tenant-scoping upgrade for large production databases. The provider-lift migration now skips rows whose agent was already deleted instead of aborting the whole upgrade with a foreign-key error, and the multi-million-row agent-message attribution backfill runs as a throttled, resumable post-deploy job (
npm run backfill:message-providers) instead of inside the boot transaction — so upgrading no longer holds a long lock onagent_messages. - d6748ad: Close a cross-tenant read path in message-detail logs (the llm_calls/agent_logs/tool_executions child queries are now tenant-scoped), and harden dashboard reliability: reject API keys past their own expiry from the auth cache, stop reporting routing-override saves that didn’t persist, keep a demo-seed failure from aborting boot, and add a retryable error state to the connection page.
- 8d7f916: Add a one-time “What we just shipped” dialog for existing users that announces global providers: connect a provider once across all harnesses, scope access per harness, and track subscription vs usage-based spend per provider and harness. Dismissal is remembered locally.
-
View release on GitHub →
✨ Minor Changes
- a29a705: Add a per-auth-type breakdown to the public
provider-tokensendpoint. Each provider now carries anauth_typesarray ({ auth_type, total_tokens, model_count }) alongside the existingmodelslist, so a provider that is used both with an API key and a subscription (e.g. OpenAI API key vs ChatGPT subscription) can be listed once per auth method. Usage with no recorded auth type is counted asapi_key. The existingprovider/total_tokens/modelsfields are unchanged, so the addition is backwards compatible. - 43e06c6: Add Xiaomi MiMo as an API-key provider with MiMo Token Plan subscription routing.
🐛 Patch Changes
- 17d7fd5: Fix the Anthropic subscription model catalog. Drop the
claude-*-fastids it pulled from the pricing cache — those 404 atapi.anthropic.combecause fast mode is ananthropic-betaheader on the base Opus model, not a model id. Also addclaude-fable-5(Claude Fable 5), a new subscription model that didn’t match the existingclaude-*-4prefixes. - 6eb902d: Forward OpenAI-compatible image inputs as Anthropic image content blocks when routing Chat Completions or Responses requests to Claude.
- abbf574: Inject cache_control prompt-caching breakpoints for Anthropic subscription OAuth requests. The skip dated from a misdiagnosed 400 that was actually caused by the missing Claude Code identity block, so subscription users were re-paying their full prompt prefix in quota on every request.
- 6dc6c07: Filter ChatGPT subscription model discovery to models the Codex backend accepts with a ChatGPT account.
- 00870bf: Make Anthropic Claude Code subscription OAuth and routing match the Claude Code flow: exchange tokens through the Claude Code API host, avoid connect-time probes, and use Claude Code-compatible request headers. Also fix Anthropic OAuth pending-flow consumption so the saved provider keeps the correct agent and user IDs.
- 392efe2: Allow adaptive-only Anthropic thinking mode parameters to be reset to unset from the model parameter dialog.
- 04782c1: Restore prompt-cache hits on the ChatGPT subscription backend: send the session affinity headers the Codex CLI sends (
session-id/thread-id,x-codex-turn-statereplay, stableprompt_cache_key), and forward the caller’sprompt_cache_keyon OpenAI /responses conversions - 4ea4872: Allow self-hosted installs to tune streaming warmup timeout with STREAM_WARMUP_MS.
- 3f59cc4: Route Copilot subscription models using their advertised supported endpoints so responses-only models use
/responsesdirectly instead of failing on/chat/completions. - 96eba2d: Resolve subscription provider aliases before checking subscription support so Gemini subscriptions stored or registered as “google” remain usable for routing.
- 09a7379: Strip unsupported
exclusiveMinimumandexclusiveMaximumJSON Schema fields from Google/Gemini tool declarations so function-calling requests do not fail validation. - 8cbc0da: Forward OpenAI-compatible image inputs as Gemini inline or file data parts when routing requests to Google.
- d018cb4: Fix custom (header) routing tiers keeping stale account pins after disconnecting one of several accounts on the same provider. Provider-reference cleanup only updated complexity and specificity tiers, so disconnecting an account, renaming a key, or deactivating all providers left header-tier routes pointing at a removed account (the account chip then rendered blank).
relabelOverrides,cleanupProviderReferences, anddeactivateAllProvidersnow cleanheader_tiersroutes the same way. - cb48cc0: Fix OAuth subscription tokens getting permanently invalidated (#2012). Providers like OpenAI now rotate refresh tokens on every refresh, so the previous “refresh then persist” path could brick an account when parallel proxy requests refreshed the same credential at once, or when the DB write failed after the provider had already rotated. Lazy refreshes are now coordinated per credential: concurrent refreshes coalesce into a single round-trip, the freshest token is re-read from the database before refreshing, and the rotated token is persisted with retries. Applies to all subscription OAuth providers (OpenAI, Gemini, Anthropic, MiniMax, xAI, Kiro).
- 2ee31b3: Route already-resolved OpenAI
o3-deep-researchAPI-key requests through the Responses endpoint, matching the existing deep-research handling foro4-mini-deep-researchwithout adding unavailable models to discovery. Preserve non-streaming mode when forwarding Chat Completions-shaped requests to OpenAI Responses, and surface collected Responses SSE error events as upstream failures instead of empty successful completions. - 6677b95: Fix the Playground sending MiniMax subscription requests to the default region endpoint. The OAuth
resource_url(which encodes the chosen region) was only applied for Gemini and dropped for MiniMax; it is now turned into aminimax-subscriptionbase-URL override the same way the proxy does, so Playground requests hit the correct region. Follow-up to #2110 (cubic-flagged). - 4a7e1fa: Normalize provider reasoning stream aliases such as Copilot’s
reasoning_textto OpenAI-compatiblereasoning_contentfor chat-completions clients while preserving provider-specific replay safeguards. - 642b162: Prevent OpenAI Responses-backed subscription streams from ending as interrupted client streams: forward terminal upstream
error/response.failedevents as OpenAI-compatible SSE error payloads, convertresponse.incomplete(max_output_tokens / content filter) into a properlength/content_filterfinish chunk, surface upstream stream errors to/v1/messagesclients as native Anthropicerrorevents instead of a fabricated emptyend_turnmessage, and stop the provider request timeout from aborting healthy streaming response bodies after headers have arrived. - 34febf8: Fix the Playground using the wrong endpoint for region-based providers (qwen, zai) and forwarding vendor-prefixed model ids for copilot/zai. The proxy’s endpoint + model resolution (region overrides for minimax/qwen/zai, prefix stripping for copilot/minimax/zai, custom-provider endpoints) is now a shared
resolveForwardEndpointhelper used by both the proxy and the Playground, so the two paths can no longer drift. - 6154127: Try configured tier fallback routes before the auto-assigned route when a manual override model is unavailable.
- a29a705: Add a per-auth-type breakdown to the public
-
View release on GitHub →
🐛 Patch Changes
- 2d7541b: Resolve model parameter specs through the providerless modelparams.dev by-model endpoint so gateway routes such as GitHub Copilot can expose the underlying model’s thinking and reasoning controls.
- 5006434: Speed up the dashboard and lower proxy overhead: unbuffered SSE streaming, smaller render-blocking CSS, lazy-loaded modals, cached per-agent model lookups, and new indexes for hot queries.
- aad3033: Fix native
/v1/responsesforwarding so typed non-message input items such asreasoninganditem_referenceare preserved without arole, preventing ChatGPT subscription Codex backend 400 errors on multi-turn Codex requests.
-
View release on GitHub →
🐛 Patch Changes
- e2ec0a6: Add BytePlus ModelArk Coding Plan as a subscription provider.
- 90e7af5: Add Command Code subscription routing with dynamic model discovery and OpenAI/Anthropic Provider API forwarding.
- c78f6fb: Persist refreshed OAuth subscription tokens to the same provider account label that supplied the token.
- 4884967: Add Qwen Token Plan as a subscription option for the Alibaba Cloud provider.
- 6cdd23d: Add a Z.ai GLM Coding Plan endpoint selector for outside-China and China Mainland subscription routing.
-
View release on GitHub →
✨ Minor Changes
- 50e7ecd: Add OpenCode Zen as an API-key provider. OpenCode Zen exposes an OpenAI-compatible
/v1/modelscatalog and/v1/chat/completionsproxy endpoint, plus a native Anthropic/v1/messagesendpoint for Claude models. Manifest now discovers Zen models on connect and routes Claude requests through/v1/messages(withx-api-keyauth) and everything else through/v1/chat/completions(with Bearer auth).
🐛 Patch Changes
- 0eff607: Keep same-name models from different providers available in the routing model picker.
- d950469: Add Fireworks AI as an official API-key routing provider.
- d439884: Add Kimi Coding Plan subscription routing for Moonshot/Kimi with the
kimi-for-codingmodel. - 31383c5: Refresh OAuth subscription credentials once when the upstream rejects a stored access token.
- 50e7ecd: Add OpenCode Zen as an API-key provider. OpenCode Zen exposes an OpenAI-compatible
-
View release on GitHub →
🐛 Patch Changes
- 65bca08: Fix token-cost calculation for providers that report cache-read prompt tokens. Manifest now uses models.dev cache-read/cache-write prices when available, so cached DeepSeek input tokens are billed at the cache-hit rate instead of the full input-token rate.
- 08f9c6f: Fix
/v1/responsesstreaming to emit the full OpenAI Responses API event lifecycle when bridging a Chat Completions upstream. The converter now opens a message item and content part (response.output_item.added/response.content_part.added) before the text deltas and closes them (response.output_text.done/response.content_part.done/response.output_item.done) with a populatedresponse.completed, instead of emitting bareoutput_text.delta+response.completed{output:[]}. Strict Responses API clients (Pi, OpenClaw-style) previously dropped the deltas and rendered empty assistant messages.
May 2026
-
View release on GitHub →
🐛 Patch Changes
- c86ab75: Record cumulative Anthropic streamed input and cache token counts when they are reported on
message_deltaevents. - 191170c: fix(charts): pad bar chart x-scale by half a bin so the last bar is fully visible (#1756)
- 3471514: Speed up the dashboard’s first load. Heavy code now loads on demand instead of up front: the syntax highlighter is a slim 6-language build, charts load per tab, and the markdown renderer loads when the first message renders. Dev-only tooling no longer ships in production bundles.
- 26f3458: Limit the OAuth callback-URL tutorial video on the provider sign-in screen to OpenAI. Other OAuth providers (Gemini, etc.) no longer show the OpenAI-specific video.
- 72a398b: Separate model selector capabilities from input and output modality columns.
- d3b742f: Fix OpenCode Go reasoning-tier routing by sending qwen3.7 models through the provider’s Anthropic-compatible endpoint, keeping Mimo on the OpenAI-compatible endpoint, and hardening streamed reasoning_content caching for tool-call continuations.
- 1a4063d: Replace the Routing page’s empty pricing catalog panel with a concise warning toast that avoids naming implementation-specific upstream pricing sources.
- 259951e: Parse provider SSE streams with a spec-compliant parser so keepalive comments remain comments instead of being forwarded as data payloads.
- 3434f64: Close an SSRF hole where a custom provider URL written as an IPv4-mapped IPv6 literal (for example
https://[::ffff:169.254.169.254]) slipped past the guard and could reach cloud metadata or private hosts. The carrier-grade NAT range (100.64.0.0/10, used by managed Kubernetes and Tailscale) is now blocked too. Separately, MiniMax, Kiro, and Copilot OAuth errors no longer echo refresh tokens or client secrets into logs. - 690de8d: Request exact token usage for every supported OpenAI-compatible streamed provider by moving
stream_options.include_usagebehind endpoint capability metadata, including Kilo and NVIDIA NIM.
- c86ab75: Record cumulative Anthropic streamed input and cache token counts when they are reported on
-
View release on GitHub →
🐛 Patch Changes
- ba08e72: Support adding and managing multiple GitHub Copilot subscription accounts.
- 9109d10: Keep connected subscription add-account flows visible for OAuth and device-code providers.
-
View release on GitHub →
✨ Minor Changes
- 19e2d5b: Kiro subscriptions now connect in Manifest Cloud. Kiro previously used a local-only CLI flow (reading the
kiro-clitoken cache off the backend’s own disk), so it only worked when self-hosting. It now uses the AWS SSO OIDC device authorization flow server-side — register → show a user code + verification link → poll for the token — exactly like the GitHub Copilot and MiniMax subscriptions, working identically on a laptop and in the cloud.
🐛 Patch Changes
- 8061e86: Show capability badges for gateway models in the model picker. A gateway model like
opencode-go/glm-5.1now resolves its capabilities from the underlying provider’s models.dev metadata (zai/glm-5.1) instead of showing “Capabilities unknown”. The resolution is gateway-generic — it keys off the shared gateway-prefix abstraction, so any gateway added later inherits it automatically. - b13ac3d: Add Grok subscription provider support with xAI OAuth login and dynamic xAI model discovery.
- 20c7c40: Add NVIDIA NIM as an official API-key routing provider.
- f71c741: Show OpenCode Go’s per-request cost in the model picker and tier cards. OpenCode Go bills a per-request slice of its dollar quota rather than a flat fee, so models with a published cost now display e.g.
$0.0136/reqinstead of the generic “Included in subscription” label. Theavailable-modelsAPI surfacescost_per_request(from the OpenCode Go catalog) for gateway models; flat-fee subscriptions are unchanged.
- 19e2d5b: Kiro subscriptions now connect in Manifest Cloud. Kiro previously used a local-only CLI flow (reading the
-
View release on GitHub →
🐛 Patch Changes
-
b6920d3: refactor(proxy): forward Anthropic Messages requests to Anthropic upstreams without OpenAI translation
When a
POST /v1/messagesrequest resolves to an Anthropic upstream, the proxy now forwards the original Anthropic body directly with only additive mutations applied (cache_control on the last system block and last tool, subscription identity injection for OAuth, default max_tokens, cached extended-thinking replay). The OpenAI-shapedchatBodyis retained for the routing/scoring layer but no longer feeds the wire request.Closes the lossy-roundtrip class of bugs that previously dropped Anthropic- native fields (server-tool
typediscriminators,top_k, nativestop_sequencesform, future Anthropic-only parameters) through the Anthropic → OpenAI → Anthropic translation. Replaces the targeted_anthropicServerToolsstash workaround. -
07bc952: Set Claude Code setup snippets to use Manifest’s
automodel by default and expose it through/v1/models. -
610c408: Show captured assistant responses as the final turn in recorded OpenAI Chat and Responses API message log conversations.
-
58dd78c: Show configured task-specific and custom tiers in the Messages tier filter and route those selections to the matching message-log filters.
-
ebb1e2b: Use modelparams.dev parameter descriptions in the Model parameters dialog instead of local hardcoded hints.
-
534ff60: Refresh the Model parameters dialog with grouped cards, inline descriptions, a compact slider with min/max markers, and a synced number field. Disabled parameters now keep their description and gain a help icon explaining how to enable them, while remembering the last user value for when they become available again.
-
6cd59c7: Resolve modelparams.dev provider aliases such as Z.ai’s
z-aicatalog ID when loading configurable model parameters. -
ec47903: Keep the OpenAI OAuth callback paste field visible while an OAuth flow is active, align the OpenAI authorize request with the current Codex CLI flow, and persist pending OpenAI OAuth exchanges across backend instances.
-
261769d: fix(proxy): re-inject cached reasoning_content for OpenAI-compatible tool turns
When reasoning providers return
reasoning_contentalongside tool calls, Manifest now caches the field and restores it on the next request if an OpenAI-compatible client dropped it from the assistant history. The replay is guarded to DeepSeek/Kimi/OpenCode Go-compatible targets and strict providers still have the field stripped. -
130eb3c: Remove the recorded-only filter from the messages dashboard.
-
96cdd40: Persist cached
reasoning_contentfor DeepSeek-compatible tool-call turns in Postgres so cloud deployments with multiple backend instances can re-inject the required field on follow-up requests. -
2bf3734: Render recorded OpenAI Responses API request input in the message log conversation tab instead of falling back to the raw-body hint.
-
d061461: fix(proxy): route xAI Responses API requests to xAI’s native /v1/responses endpoint
Adds native xAI Responses API forwarding and routes xAI multi-agent Grok models through /v1/responses instead of filtering them out of model discovery.
-
-
View release on GitHub →
🐛 Patch Changes
- 9d3f743: Stop recording Railway and proxy noise headers on every message. Headers injected by the hosting edge (x-railway-, x-forwarded-, x-real-ip, etc.) are dropped before storage, so the message Headers tab only shows headers the agent actually sent.
- 1173e30: Performance: bound the public usage-stats aggregations, add a composite
(key_prefix, is_active)index for agent-key auth lookups, reuse uPlot chart instances in place on data refresh instead of rebuilding them, and memoize the message log’s feedback overrides.
-
View release on GitHub →
✨ Minor Changes
- 400c195: Add opt-in per-agent message recording. Toggle in Settings → Recording captures the full request body, response body, and response headers for subsequent proxy calls. Recorded rows show a record-dot icon in the Messages log; clicking it opens a formatted modal with Parameters, Conversation turns, Tool calls, Reply, Usage pills, and Headers. Payloads capped at 2 MB and kept out of the hot message-list query via a separate
message_recordingstable. Defaults off; never included in anonymous telemetry.
- 400c195: Add opt-in per-agent message recording. Toggle in Settings → Recording captures the full request body, response body, and response headers for subsequent proxy calls. Recorded rows show a record-dot icon in the Messages log; clicking it opens a formatted modal with Parameters, Conversation turns, Tool calls, Reply, Usage pills, and Headers. Payloads capped at 2 MB and kept out of the hot message-list query via a separate
-
View release on GitHub →
🐛 Patch Changes
- 3b345e7: Fix provider disconnect cleanup so removing an OAuth subscription clears routes pinned to that auth type even when an API-key credential for the same provider remains connected.
- 492cf46: Preserve provider key labels and priorities when duplicating agents.
- 045907d: Preserve native Google
generationConfigfields when routing requests to Gemini, while keeping existing OpenAI-compatible generation aliases as explicit overrides. - 9438035: Serve model parameter specs from the MPS catalog API and support scoped per-route defaults.
- 4e780be: Make saved Manifest model parameters authoritative over overlapping client request parameters while preserving client parameters that Manifest does not configure.
- bea267e: Fetch model parameter specs per-model on demand instead of downloading the full MPS catalog on every Routing-page load, and add an ETag conditional GET to the catalog refresh. Keeps the dashboard payload flat as the catalog grows.
- 680feca: Stop slow startup model-catalog syncs from stalling boot past the deploy healthcheck. The OpenRouter, models.dev, GitHub, and modelparameters.dev fetches now run in the background instead of blocking
app.listen(), and the two that lacked a timeout (OpenRouter, GitHub) now abort after 10s. The pricing cache still warms up with real data once those fetches land.
-
View release on GitHub →
✨ Minor Changes
- c4571f7: Add Playground page: compare LLM responses from multiple models side by side for cost, output tokens, and latency. Includes request-headers popover, history drawer with replay, and markdown rendering of responses.
🐛 Patch Changes
- f2074dd: Make Anthropic OAuth token exchange diagnostics safe when fields are missing.
- 3ff3087: Persist Anthropic OAuth pending state in Postgres so production exchanges survive reloads, restarts, and multi-instance routing.
- 7913169: Align Anthropic OAuth state handling with the Claude Code PKCE flow.
- ed05898: Add Claude Code-compatible Anthropic OAuth token headers and safe request-shape diagnostics.
- 0421e0a: Fall back to the OAuth state when Anthropic pending verifier data is missing.
- d00e52b: Fix custom providers in the Playground. Selecting a model from a custom (OpenAI/Anthropic-compatible) provider now resolves its endpoint instead of failing with “Provider request failed”.
- 2b1c9b5: Hide the misleading empty “tier” label in the Playground model picker. The subtitle now only shows when a real routing tier applies.
-
View release on GitHub →
✨ Minor Changes
-
24832a3: Add Nanobot to the supported personal AI agents list. The setup screen renders a paste-ready
~/.nanobot/config.jsonblock that points themanifestprovider at the Manifest endpoint and selects modelautoby default. -
d7dc183: Move request body defaults (today: DeepSeek’s
thinkingtoggle) from tier-scoped storage to per-route storage. Settings now travel with the model identity (agent_id,provider,auth_type,model_name) wherever the model appears — default tier primary, specificity fallback, header-tier primary, anywhere. Behavior change: Manifest no longer auto-disables DeepSeek’s thinking mode on simple/standard/complex tiers. Users who never configured a value will see the provider’s natural default (thinking enabled) instead of Manifest’s previous cost-saving override. To get the old behavior back, configure thinking explicitly per-model from the Routing page once the frontend ships. Migration backfills the existing per-tier config to every compatible route in the assignment (primary + fallbacks) so no per-model setting is silently lost. Adds new endpointsGET/PUT/DELETE /api/v1/routing/:agent/model-paramsfor the upcoming frontend. -
4cba5b3: Routing UI: every model row (primary chip, fallback row, header-tier primary, header-tier fallback) now exposes the per-model Parameters affordance for any provider whose API consumes a known knob (today: DeepSeek’s
thinking). Settings travel with the model identity wherever it appears — saving DeepSeek’s thinking mode on one slot updates every other slot showing the same model. Closes the long-standing gap on the “custom” (header-tier) routing surface, which previously had no params support at all. Wires the newGET/PUT/DELETE /api/v1/routing/:agent/model-paramsendpoints shipped in the backend PR. -
a8e907e: Add full OAuth flow for the Anthropic Claude Pro / Max subscription. Connecting your Claude subscription is now a one-click “Sign in with Claude” → paste the authorization code, instead of running
claude setup-tokenin a separate terminal. Tokens auto-refresh through the same blob/refresh path used by OpenAI.Internally the OAuth code in
routing/oauth/was split into sharedcore/primitives (PKCE, token-blob storage, pending-state TTL, callback HTML) plus per-provider files. The OpenAI service now delegates to the same primitives, and a newoauth/anthropic/package implements the paste-code flow.
🐛 Patch Changes
-
a254c32: Add OpenCode to the Coding Assistant setup flow. The setup screen now renders a paste-ready OpenCode config block for the global or project config, registers Manifest as an OpenAI-compatible provider, and selects
manifest/autoby default. -
6f52fdd: Normalize Chat Completions
image_urlparts to Responses APIinput_imageparts before forwarding to/v1/responses. -
bbcfa50: Stop filtering the canonical
gemini-3.1-flash-lite-preview(and similar non-datedflash-lite-previewaliases) from Gemini model discovery. The previous regex was meant to drop deprecated dated snapshots likegemini-2.5-flash-lite-preview-09-2025but over-matched and removed live preview models too. Tightened to require a-MM-YYYYdate suffix so dated snapshots still get filtered while canonical previews surface. -
91088e2: Fix “Add another key” button for OAuth subscription providers
-
cedeba2: Extract Wingman to a standalone hosted SPA at
wingman.manifest.build. The dashboard’s bottom drawer stays dev-only (dead-code-eliminated from production / self-hosted bundles) and now embeds the hosted build by default. Contributors can still point it at a local Wingman withVITE_WINGMAN_URL. Dev-mode CORS allow-lists the hosted origin so contributors can use the hosted SPA against a local backend; production never enables CORS, so nothing Wingman-related ships to self-hosted deployments. Thepackages/wingman/workspace is removed; source moves to https://github.com/mnfst/wingman. -
abf3c15: Show a small “Last used” badge on the sign-in and sign-up pages so returning visitors can see at a glance which method (email or one of the social providers) they used last time. The hint is stored per-browser in
localStorageand is best-effort: it falls back silently when storage is unavailable. -
9b4a586: Accept MiniMax Coding Plan
sk-cp-tokens on the MiniMax subscription tile alongside the device-code OAuth flow. The region picker now applies to both paths, so CN Coding Plan tokens route toapi.minimaxi.comfor both model discovery and proxied requests. Closes #1467. -
d9e6232: Improve the dashboard layout on phone-sized screens with a compact navigation drawer, tighter header chrome, and mobile-sized chart stats.
-
828812c: Patch five high-severity Dependabot alerts in transitive dependencies.
fast-uri3.1.0 → 3.1.2 (path traversal + host confusion, dev-only via@nestjs/schematics).kysely0.28.14 → 0.28.17 viabetter-auth1.4 → 1.6 (JSON-path injection inJSONPathBuilder, runtime).undici5.x → 6.25 via@codecov/vite-plugin1 → 2 (HTTP smuggling + CRLF injection, dev/build only).
No behavior change. Better Auth bump is patch-compatible (1.4 → 1.6) — login, register, OAuth round-trips verified locally.
-
7792ef8: Coerce unknown Anthropic Messages tool types to custom tools instead of forwarding unsupported server-tool tags, and normalize missing array
itemsin forwarded tool schemas for OpenAI compatibility. -
504a7af: Route Anthropic and MiniMax subscription disconnects through provider-specific OAuth cleanup endpoints
-
47d143c: Rename the personal agent category label to “AI agents”.
-
ee47ba7: Strip adaptive thinking when Anthropic Messages requests are routed to Claude Haiku.
-
f4fb104: Preserve OpenCode Go reasoning content for known non-DeepSeek reasoning model families.
-
-
View release on GitHub →
✨ Minor Changes
- 74f6fb3: Add
GET /api/v1/public/agent-tokenspublic endpoint. Mirrors the shape of/provider-tokensbut groups daily-token usage by(agent_category, agent_platform)instead of by LLM provider, so the marketing site can show per-agent (OpenClaw, Claude Code, OpenAI SDK, etc.) charts alongside the existing per-provider ones. Excludes theotherplatform bucket andcustom:*models server-side. Gated byMANIFEST_PUBLIC_STATSand cached for 24h, same posture as the rest of the public-stats endpoints.
🐛 Patch Changes
-
c1fe19a: Fix GitHub Copilot routing for GPT-5 Codex models. Copilot serves Codex variants (
gpt-5-codex,gpt-5.2-codex,gpt-5.3-codex) only via/responses, so chat-completions requests now swap to that endpoint instead of returning “Unsupported API for model”. Also rewritesmax_tokenstomax_completion_tokensfor the GPT-5 / o-series family on Copilot, fixing the “Unsupported parameter: ‘max_tokens’” error reported alongside. -
786dd76: Preserve Responses stream classification during stream warm-up.
-
ae56a30: fix(proxy): preserve Anthropic server tools through /v1/messages double-conversion (#1886)
Claude Code requests routed through
POST /v1/messagesto an Anthropic upstream failed withtools.N.custom.input_schema: Field requiredbecause server tools (web_search, bash, text_editor, computer, code_execution) lost theirtypetag during the Anthropic → OpenAI → Anthropic translation and were re-emitted as custom tools missing the requiredinput_schema. Server tools are now stashed on the translated body and re-emitted unchanged when the upstream is Anthropic. -
d25320a: Preserve DeepSeek
reasoning_contenton every follow-up turn, regardless of which provider proxies it (OpenCode Go, custom providers, future aggregators). Fixes a hard failure on OpenCode Go’sdeepseek-v4-pro(“The reasoning_content in the thinking mode must be passed back to the API”) — issue #1862. -
e7cdfa1: Strip the non-standard
refJSON Schema keyword (no$prefix) from Google Gemini tool parameters. Some tool emitters drop the$prefix because Protobuf and similar parsers reject dollar-prefixed field names; without this fix Manifest forwardedrefverbatim and Google rejected the request withInvalid JSON payload received. Unknown name "ref". -
f21584a: Fix prompt-caching token counters on
/v1/messages.cache_controlmarkers always reached Anthropic (caching was working server-side), but the chat → Anthropic-Messages conversion intoAnthropicUsagehardcodedcache_creation_input_tokens: 0, and theparseUsageObjectAnthropic branch read cache reads from the wrong key. Result: client responses lost cache creation counts, andagent_messagesrows recorded0for both cache creation and cache reads even when Anthropic actually hit the cache.Also fixes the recorder’s duplicate-write detector, which summed
input_tokens + cache_read_tokens + cache_creation_tokenswhen computing a row’s total prompt tokens —input_tokensalready stored the chat-shape total, so the sum double-counted caches and caused legitimate duplicates to bypass dedup. AndtoAnthropicUsagenow reads OpenAI-compat nestedprompt_tokens_details.cached_tokensas a fallback so/v1/messagesrequests routed to OpenAI / DeepSeek / Z.AI / MiniMax / Mistral surface their cached-input counts too. -
9f64594: Update MiniMax “Where to get an API key” link to point to the actual key page (
/user-center/basic-information/interface-key) instead of the API docs overview.
- 74f6fb3: Add
-
View release on GitHub →
🐛 Patch Changes
- 562d105: Fix Groq model attribution in the routing UI so Groq-served prefixed model IDs stay selectable and show the Groq provider.
-
View release on GitHub →
🐛 Patch Changes
- 00784e3: Show the Model Parameters button on a routing tier when any route in the tier — primary or fallback — uses a params-compatible provider. Previously the button was gated to the primary route only, so a tier with DeepSeek configured as a fallback hid the toggle even though the proxy already applies tier-level
param_defaultsto whichever provider an attempt actually targets. The dialog’s provider-default hint follows the first compatible route in the ordered (primary, …fallbacks) list.
- 00784e3: Show the Model Parameters button on a routing tier when any route in the tier — primary or fallback — uses a params-compatible provider. Previously the button was gated to the primary route only, so a tier with DeepSeek configured as a fallback hid the toggle even though the proxy already applies tier-level
-
View release on GitHub →
✨ Minor Changes
-
ef46fa0: Per-assignment request body defaults: each tier and specificity slot now carries an optional
param_defaultsJSONB column that the proxy merges into the outbound provider request before forwarding. Initial knob is DeepSeek’s thinking-mode toggle ({ thinking: { type: 'enabled' | 'disabled' } }) — fixes empty-content responses on DeepSeek V4 Flash/Pro that consume themax_tokensbudget on reasoning. Precedence is presence-based: client-supplied fields in the request body always win, so explicit per-call overrides keep working.Configure from the routing UI via a new “Parameters” button on each model chip; persisted via
PATCH /api/v1/routing/:agent/tiers/:tier/paramsand…/specificity/:category/params. -
085431c: Per-message model parameter telemetry. Each
agent_messagesrow now carries arequest_paramsJSONB snapshot of the effective request body parameters that hit the provider (today: DeepSeek’sthinkingtoggle; future provider knobs and user-defined custom-provider params land here without a schema change). The dashboard’s expanded message detail shows a new “Model Parameters” accordion next to Request Headers, with an info tooltip explaining the field. Existing rows stay NULL — back-compat is preserved. -
d3b551f: Per-provider model refresh: a small refresh button next to each provider in the Connect Providers detail view and next to each section header in the model picker. Toasts now report the actual count or upstream error instead of a blanket “Models refreshed” lie. Empty discovery results no longer wipe a non-empty cache, so a transient API hiccup can’t silently empty the model list. The model picker subtitle now shows “Default tier” instead of just “tier”.
🐛 Patch Changes
-
ec7fc12: Restore the per-tier (and per-specificity) Model Parameters dialog that was inadvertently dropped during a stacked-PR merge. The sliders icon is back on every primary model chip in Routing for providers that consume known params (today: DeepSeek’s
thinkingtoggle). The dialog persists per-assignment, so a single configured value applies to the primary model AND every fallback the proxy tries — without per-route schema changes. Multi-key compatible: pinning a different key on the same route does not affect the stored params, and switching keys mid-flight keeps using whatever the proxy resolved for that iteration.Adds back:
PATCH /api/v1/routing/:agent/tiers/:tier/params,…/specificity/:category/params,TierService.setParamDefaults,SpecificityService.setParamDefaults, frontendsetTierParamDefaults/setSpecificityParamDefaults, andModelParamsDialog. -
c446856: fix(routing): attribute models by their connection’s provider, not by model-id prefix
The routing UI used to derive a model’s logo from the prefix of its model id, which broke for any provider that redistributes other vendors’ models. Most visibly, a Groq connection serving
qwen/qwen3-32brendered with the Qwen logo and Qwen-on-OpenRouter pricing (≈$0.08/$0.24 per 1M) instead of Groq’s own pricing ($0.29/$0.59).Two changes:
- Frontend (
RoutingTierCard.providerIdForModel): when a model row has a storedproviderthat resolves to a registered first-party provider, that wins over prefix inference. OpenRouter remains the documented exception because its rows really do represent vendor-prefixed models served on behalf of those vendors. - Backend (
ModelDiscoveryService.enrichModel):known-model-prices.tsis now consulted before models.dev and the OpenRouter cache, so curated per-provider prices win over upstream catalogs that may attribute the same model id to a different (cheaper) inference provider. Behaviour change for the existing entries (moonshot-v1, gemma-3-1b-it, gemini-pro-latest): they become authoritative instead of last-resort, which matches their intent.
Builds on #1772, which introduced
route.provideras the routing identity. - Frontend (
-
-
View release on GitHub →
✨ Minor Changes
- ab9f0cb: Add an Anthropic Messages-compatible endpoint at
POST /v1/messages. Anthropic SDK clients (Claude Code,@anthropic-ai/sdk) can now pointANTHROPIC_BASE_URLat a Manifest gateway and route through Manifest’s tier/specificity pipeline like any OpenAI client. The implementation translates Anthropic Messages requests into the internal chat-completions form (and back on the response side), reusing the existing routing, scoring, fallback, and recording machinery. - 1627493: Add a “Coding Assistant” category in the agent picker and move Claude Code into it. The Connect Agent / Change Agent Type modal now shows three columns instead of two: Personal AI Agent | App AI SDK | Coding Assistant. Claude Code is no longer mis-bucketed under personal agents — it sits in the new column with the existing copper-orange Claude mark. Picker order, icons, and the existing Claude Code setup wizard are unchanged.
- fb7d921: Add support for multiple API keys per provider per agent. Users with several accounts for the same provider (a personal + work OpenAI key, two ChatGPT Plus subscriptions, two Anthropic Pro tokens) can attach all credentials and pin specific tiers or fallback rows to a specific labeled key. Multi-key applies to both
api_keyandsubscriptionproviders; local providers (Ollama, LM Studio) stay single-row since they don’t carry credentials. Cap is 5 active keys per (agent, provider, auth_type). Single-key users see no UI change — the chip + “+ Add another key” affordance only appear once a provider has 2+ active keys. - c6efb87: Add Wingman, an in-dashboard gateway tester for contributors. Embedded as a half-screen iframe drawer behind a floating action button in dev mode, stripped from Docker / cloud bundles. Lets contributors send one-shot requests at the gateway while impersonating OpenClaw, Hermes, OpenAI SDK, Vercel AI SDK, LangChain, cURL, or Raw — with editable code panels that actually execute via stubbed SDKs.
🐛 Patch Changes
-
9a0e8c3: Fix silent failure when adding a fallback that shares a provider with an existing route. Adding an OpenAI API key model as a fallback to an OpenAI subscription model (or any other same-provider, different-auth combination) now persists correctly instead of showing a success toast and dropping the change. The frontend now sends the explicit
(provider, authType, model)tuple alongside the model name so the backend can disambiguate when the same model id is offered by two connected providers. Affects both complexity tier and specificity (“custom”) routing. -
30d19ab: Stop silently wiping the saved fallback list when an unresolvable model is added (issue #1790).
buildFallbackRoutes()intier,specificity, andheader-tierservices used to returnnullwhenever any single model couldn’t be resolved to a unique(provider, authType, model)tuple.setFallbacksthen persisted thatnull, so the user’s existingfallback_routesrow was overwritten withnulland the controller returned[]. The toast still said “Fallback added” — the only visible result was the previously-saved fallbacks disappearing.PR #1825 already plugged the most common trigger by sending an explicit
routespayload from the add handlers. This change removes the underlying footgun:buildFallbackRoutesnow throws400 Bad Requestinstead of returningnull, so the row is left untouched on resolution failure and the frontend shows the error.Scoped strictly to the backend wipe path. Does not change input validation, the
authType !== undefinedguard in the add handlers, or the discovery-fallback shape ofbuildFallbackRoutes. -
022529a: Fix MiniMax Token Plan activation redirecting to the homepage. The MiniMax
/oauth/codeendpoint returns averification_uripointing athttps://www.minimax.io/oauth-authorize?..., which 307-redirects to the homepage with no instructions. The real authorize page lives onplatform.minimax.io(andplatform.minimaxi.comfor the CN region). The MiniMax OAuth start flow now rewrites the host before returning the URI, so users land on the actual page where their 6-digit code can be entered. Closes #1796.
- ab9f0cb: Add an Anthropic Messages-compatible endpoint at
-
View release on GitHub →
🐛 Patch Changes
- cf98f70: Fix OpenAI subscription model discovery so newer Codex CLI models (e.g.
gpt-5.5) appear. The hardcodedclient_version=0.99.0query param madehttps://chatgpt.com/backend-api/codex/modelssilently return only the older subset; bump it to0.128.0and lift Codex/Copilot client identifiers into a shared constants file so future bumps are a one-line change. - a7a9c3b: Fix fallback success rows recording the primary route’s
auth_typeinstead of the fallback’s, which causedcost_usdto be miscomputed on mixed-auth chains (subscription fallbacks were charged, api_key fallbacks were stored as $0). - be679c4: Strip Codex-unsupported parameters on the OpenAI subscription proxy path. Requests forwarded to
chatgpt.com/backend-api/codex/responsesnow droptemperature,top_p,max_output_tokens,metadata,safety_identifier,prompt_cache_retention, andtruncationbefore the upstream call, and forcestore: false. Previously these fields propagated through and Codex returned400 unsupported_parameter, breaking OpenAI-SDK clients that set sampling defaults. Closes #1791.
- cf98f70: Fix OpenAI subscription model discovery so newer Codex CLI models (e.g.
-
View release on GitHub →
🐛 Patch Changes
-
e8162c3: Security hardening across the build pipeline and runtime: every GitHub Action is now pinned by commit SHA, the awesome-free-llm-apis data feed is pinned to an immutable commit and validated for HTTPS shape before render, the encryption-key cache no longer keeps the raw secret as a Map key, the Google Gemini API key moves from
?key=query param to thex-goog-api-keyheader (so it stays out of upstream proxy/LB access logs), OpenAI OAuth error logs run throughscrubSecrets, the OAuthbackendUrlnow prefersBETTER_AUTH_URLover the requestHostheader, the dev-loopback agent fallback prefers the seeded tenant over picking the first active key, rejected agent keys log only the fixedmnfst_prefix, and migrations log via the TypeORM logger instead ofconsole.log.npm audit fixresolved vite + postcss CVEs. A boot-time check counts active legacy static-salt API-key hashes and warns if any remain (no forced rotation).MANIFEST_ENCRYPTION_KEYis now documented and threaded throughdocker-compose.yml; if unset the runtime still falls back toBETTER_AUTH_SECRET. -
f0082d5: Fix: detect Podman and Kubernetes as self-hosted runtimes. Manifest now reads
/run/.containerenv(Podman) andKUBERNETES_SERVICE_HOSTin addition to/.dockerenv, so rootless Podman and Kubernetes installs no longer fall back to cloud-mode SSRF rules and rejecthttp://URLs to local LLM servers.Also narrows the cloud-metadata SSRF block to the actual IMDS addresses (
169.254.169.254,169.254.169.253,100.100.100.200,fd00:ec2::254) instead of the entire169.254.0.0/16link-local range, so self-hosted users can reachhost.containers.internal(which Podman maps to169.254.x.yunder pasta/slirp4netns). Cloud mode is unchanged: link-local space is still rejected via the private-IP guard.
-
April 2026
-
View release on GitHub →
💥 Major Changes
-
d4675ba: Drop the legacy routing identity columns from
tier_assignments,specificity_assignments, andheader_tiers. The structuredrouteshape introduced in #1772 is now the only persistence form.Schema: 13 columns dropped (
override_model,override_provider,override_auth_type,fallback_modelsfrom all three tables;auto_assigned_modelfrom tier and specificity tables). Migration1784000000000-DropLegacyRoutingColumnsruns on boot.down()re-adds the columns nullable but data is one-way lost — backup before upgrading if you maintain a hot-standby.API breaking change:
POST /api/v1/routing/resolveno longer returns the flatmodel,provider,auth_type,fallback_modelsfields. External callers must readroute.model,route.provider,route.authType, andfallback_routesinstead.Internals: removes the legacy inference cascade in
proxy-fallback.service.ts, the dual-write paths in routing services, and the?? legacyreads throughout. Same model name on different auth types stays correctly distinct (the #1708 fix).
✨ Minor Changes
- 1ce8ed9: Stable error codes for the proxy. Every user-facing
[🦚 Manifest]message now embeds anM###code (M001–M500) and a docs link atmanifest.build/errors/M###. Companion encyclopedia pages live in mnfst/docs. - 1d37134: Routing identity is now backed by a structured
ModelRoute = (provider, authType, model)shape stored alongside the existing legacy columns ontier_assignments,specificity_assignments, andheader_tiers. Reads prefer the new shape and fall back to legacy, so existing rows keep working without intervention. Selecting the same model name under different auth types (e.g.gpt-4oon subscription and on api_key) is now correctly treated as two distinct routes — fixes #1708. The/api/v1/routing/resolveresponse gains additiverouteandfallback_routesfields without breaking the existing flat shape. Per-fallback-attemptauth_typeis now recorded onagent_messagesinstead of inheriting the primary’s. No UI, API contract, or data is removed in this release; legacy columns and fields stay populated for one cycle before being dropped in a follow-up.
🐛 Patch Changes
- 4e7843a: Recreating an agent with a previously used name now produces a clean slate without losing the deleted agent’s history. Agent deletion is soft (the row stays with
deleted_atset, telemetry rows are preserved) and per-agent analytics scope to the live agent’s id, so the new agent starts at zero while the old data remains queryable in storage. - 2d4a06e: Show the Manifest version in the bottom-right corner of self-hosted Docker installs. Baked into the image at build time, no API call.
-
-
View release on GitHub →
✨ Minor Changes
- 992ae47: Add saved cost metric to the Overview dashboard showing how much money routing saves compared to using a single model
🐛 Patch Changes
- 7394235: Mark Manifest’s canned setup-prompt and limit responses as Failed in the Messages list. Requests that hit
no_provider,no_provider_key,limit_exceeded, orfriendly_error(the[🦚 Manifest] …stubs) now show a red Failed badge with a tooltip explaining why, instead of an ambiguous green Success. - 4bd4039: Fix two routing regressions caused by agent-wrapped user messages. Strip leading metadata envelopes (e.g.
Sender (untrusted metadata):blocks emitted by OpenClaw, NanoBot, Hermes) before scoring so simple greetings like “say hello” no longer route to standard/complex (#1766). Tighten coding specificity signals so generic agent tools (read,write,edit,bash, etc.) and tiny envelope code fences no longer hijack every prompt to the coding tier (#1767).
-
View release on GitHub →
✨ Minor Changes
- eacdc3a: Revert combined cloud + self-hosted message count on
/api/v1/public/usage. The endpoint goes back to reporting cloud-only counts. The self-hosted aggregate fetcher and itsTELEMETRY_AGGREGATE_KEYenv var are removed.
- eacdc3a: Revert combined cloud + self-hosted message count on
-
View release on GitHub →
✨ Minor Changes
- 97bfe4e: Public usage API combines cloud and self-hosted message counts. The
/api/v1/public/usageendpoint now adds the fleet-wide self-hosted total fetched from the peacock control plane (whenTELEMETRY_AGGREGATE_KEYis configured) to the cloud count, falling back to cloud-only if peacock is unreachable.
🐛 Patch Changes
-
114e684: Fix proxy recording 0 tokens and “—” cost for streaming requests against Mistral, Kimi (Moonshot), MiniMax, DeepSeek, Qwen, xAI, Z.AI, Copilot, OpenCode-Go, and custom OpenAI-compatible providers. The proxy now injects
stream_options.include_usage: truefor all OpenAI-format endpoints so usage data flows back from the upstream.Also fix the cache-tokens column staying empty for the same providers: usage extraction now reads
prompt_tokens_details.cached_tokens(DeepSeek, Z.AI, Mistral, MiniMax, OpenAI shape) in addition to the top-levelcache_read_tokensand Anthropic-nativeinput_tokens_details.cached_tokenskeys. -
bdb43df: Strip
reasoning_detailsfrom message history before forwarding to non-OpenRouter providers. Mistral, Groq, and other strict OpenAI-compatible providers were rejecting requests withextra_forbidden(422) when conversations contained extended-thinking blocks from a prior turn.
- 97bfe4e: Public usage API combines cloud and self-hosted message counts. The
-
View release on GitHub →
🐛 Patch Changes
- 40faabb: fix(dashboard): the OpenClaw setup snippet was generating a config with
api: 'openai-responses', but Manifest’s cloud proxy speaks Chat Completions. OpenClaw rendered empty assistant bubbles even though tokens were billed correctly. Snippet now writesapi: 'openai-completions'and the dashboard label reads “OpenAI Chat Completions-compatible”. Existing OpenClaw users who pasted the broken snippet need to re-run the updated config block (or flipmodels.providers.manifest.apimanually).
- 40faabb: fix(dashboard): the OpenClaw setup snippet was generating a config with
-
View release on GitHub →
🐛 Patch Changes
- b2f01c4: Drop bundled
@esbuild/linux-x64from the Docker image so CVE scanners no longer flag the embedded Go 1.23.12 stdlib (CVE-2025-68121 plus 10 high-severity CVEs). The binary was hoisted into the productionnode_modulesdespitenpm ci --omit=dev; adding--omit=optionalremoves it along with other unused platform-specific binaries.
- b2f01c4: Drop bundled
-
View release on GitHub →
🐛 Patch Changes
- 77a1db3: Backend hot-path and dashboard query optimization pass: 60s LRU session cache in SessionGuard, slimmed AgentKeyAuthGuard query with 30min cache, retuned specificity miscategorization index, batched proxy fallback inserts, merged agent-list stats+sparkline into a single query, bounded distinct-models scan to 90 days, plus typed SSE events so dashboard pages only refetch on relevant changes instead of every ingest ping.
- a5f0ef9: Security audit fixes (OWASP review).
- Auth: SessionGuard and AgentKeyAuthGuard now read
request.socket.remoteAddressfor the loopback bypass decision instead ofrequest.ip, which is forgeable viaX-Forwarded-Forwhentrust proxyis enabled. The productiontrust proxysetting is narrowed toloopback, linklocal, uniquelocal(override withTRUST_PROXYenv). - Proxy: custom-provider and subscription endpoint URLs are revalidated against the SSRF allowlist immediately before each forward (DNS-rebinding defense). All proxy
fetch()calls now useredirect: 'error'to block redirect-based escalation. - Auth rate limiting: added per-endpoint limits for
sign-up,forget-password/forgot-password/reset-password, andverify-email/send-verification-email(Better Auth runs outside NestJS soThrottlerGuarddoesn’t apply). - ApiKeyGuard: DB-API-key path now populates
request.user, so user-scoped controllers no longer crash with a 500.@CurrentUser()fails closed with a 401 when no user is attached. - Crypto: AES-GCM IV length set to the standard 12 bytes (was 16), scrypt-derived keys cached per (secret, salt) to remove the per-call ~50ms cost on the proxy hot path. Boots warns once when
MANIFEST_ENCRYPTION_KEYfalls back toBETTER_AUTH_SECRETin production. - OAuth:
backendUrlis validated against the allowlist at storage time instead of being trusted on the way out. - Telemetry:
routing_tierandauth_typebuckets are whitelisted against the shared enums; unknown values collapse to"other"instead of leaking verbatim. - Frontend: 401 responses no longer force a redirect to
/loginfor per-endpoint auth failures. Only session-shaped 401s log the user out. - HSTS: warns at boot when production runs without HSTS on a non-loopback bind. Silence with
MANIFEST_DISABLE_HSTS=1. - Dev CORS: defaults to a single origin (
http://localhost:3000); setCORS_ORIGINfor anything else.
- Auth: SessionGuard and AgentKeyAuthGuard now read
-
View release on GitHub →
🐛 Patch Changes
- 3173336: Bump Docker runtime to Node 24 LTS (
gcr.io/distroless/nodejs24-debian13). Active LTS through April 2028, replacing Node 22 (Maintenance LTS, EOL April 2027). Build and prod-deps stages move tonode:24-alpineandnode:24-slimto keep install and runtime majors aligned. CI and release workflows updated to Node 24. Dependabot is now pinned to ignore Node major bumps so non-LTS Current releases (Node 23, 25, 27…) won’t open noisy PRs — LTS upgrades happen on a deliberate cadence.
- 3173336: Bump Docker runtime to Node 24 LTS (
-
View release on GitHub →
🐛 Patch Changes
- f5c9af8: Polish auth flow accessibility and a few content fixes from a UX audit. Login, Register, and Reset Password inputs now have proper label/
forassociation,autocompleteattributes for password-manager autofill, andaria-describedbylinking errors to inputs. The cooldown intervals on resend buttons clean up on unmount. The Register page now links to real Terms and Privacy URLs (washref="#"). Section titles on Settings and Account use<h2>instead of<h3>to fix a heading hierarchy skip. Dark-variant logos use empty alt text so screen readers don’t read “Manifest” twice. The Limits “Create rule” button uses the same plus icon as Workspace’s “Connect Agent” button. - 4664b2d: Fix agent duplication not copying local/custom providers correctly
- cc09e4f: Expose the OpenAI-compatible Responses API proxy at
/v1/responsesand show Responses API setup snippets by default for OpenAI SDK users. - 0e8035c: Fix agent duplication not copying routing mode, local provider models missing from model picker, and local provider toggle errors
- f5c9af8: Polish auth flow accessibility and a few content fixes from a UX audit. Login, Register, and Reset Password inputs now have proper label/
-
View release on GitHub →
✨ Minor Changes
-
5bafaad: feat(providers): support Anthropic-compatible custom providers
Custom providers can now speak the Anthropic Messages API (
/v1/messages) in addition to OpenAI’s/v1/chat/completions. When adding a custom provider, pick the API format in the new segmented control on the form — Manifest’s existing Anthropic adapter handles the translation so agents continue to call the OpenAI-compatible proxy unchanged. Useful for Azure’s Anthropic endpoint and any other gateway that exposes the native Anthropic protocol.
🐛 Patch Changes
- d6afa94: Add a llama.cpp provider tile to the API Keys tab in the self-hosted version. Clicking it probes
http://localhost:8080/v1/modelson the default llama-server port, lists every model the server exposes, and lets you connect them in one click. Pre-b3800 llama.cpp builds that don’t expose/v1/modelsget a hint to upgrade or fall back to the custom-provider form. Messages and dashboard filters render llama.cpp and LM Studio as first-class providers instead of opaquecustom:<uuid>rows.
-
-
View release on GitHub →
✨ Minor Changes
- 466e4cf: Drop the
Enable routingrelic: remove the empty-state card on the Routing page so tabs and tier cards render by default, drop thecomplexity_routing_enabledcolumn and its endpoints/toggle (complexity scoring is always on), delete the bulk “Disable routing” button, rename cross-page CTAs from “Enable routing” to “Connect provider”, and add a Connect-providers CTA inside the model picker’s empty state. - d78828c: Surface local models (Ollama, LM Studio) as their own provider category. New
auth_type: 'local'joinsapi_keyandsubscription; messages routed to local runners now carry a grey house badge in the message log, routing cards, and cost-by-model table. The Add Provider modal gets a third Local tab that appears only on self-hosted installs. Backfill migrations re-tag existing Ollama/LM Studiouser_providersrows, and custom providers whose display name resolves to a canonical local runner are taggedlocalat insert time. Connecting/disconnecting a local provider works like the Subscription tab — click-to-disconnect flips the toggle and stops routing to it.
- 466e4cf: Drop the
-
View release on GitHub →
✨ Minor Changes
- 039afbe: Duplicate an agent in one click — hover any agent card on the Workspace to reveal a menu with Duplicate and Delete, or use the new “Duplicate agent” button on the Settings page. Creates a new agent with a fresh API key and carries over every provider credential, custom provider, tier override, and specificity override. Messages, logs, and notification rules stay with the original.
🐛 Patch Changes
-
5110901: Polish routing page copy and UX: rewrite tier descriptions, standardize casing and pluralization, always show the “How routing works” help button, toggle tiers by clicking the manage-modal row, and add a pen icon on custom tier cards to open the edit modal directly.
-
91a7467: Low-risk cleanups from the 2026-04-23 OWASP audit that cause no behaviour change for operators or users:
- Scope agent rename cascades by
tenant_idonagent_messages/notification_rules/notification_logs. Forward-only fix — no backfill — so any pre-existing row that was mislabelled when slugs collided across tenants stays as-is; new renames no longer touch other tenants’ data. - Replace
ApiKeyGuard.safeComparewithBuffer.from+ length-check +timingSafeEqual. Same observable behaviour; cleaner canonical pattern. - Add a snapshot test for
ThresholdAlertEmailagainst hostile agent names (angle brackets, attribute-context quote payloads) — verifies React’s existing escaping, no runtime change. npm audit fixfor the moderate@nestjs/coreadvisory (11.1.17 → 11.1.19).
All other findings from the audit are deferred — they required breaking changes or operator action and live in a separate tracking issue.
- Scope agent rename cascades by
-
View release on GitHub →
✨ Minor Changes
- f8e00c9: Make complexity routing optional. New agents now default to a single “Default” tier that handles every request — pick one model and you’re routing. Complexity routing (four tiers scored by request content) becomes an opt-in toggle on the Routing page alongside the existing task-specific routing. Existing agents keep complexity routing on with their tier picks preserved.
-
View release on GitHub →
✨ Minor Changes
- 910b191: Add custom header-triggered routing tiers. Configure a tier keyed to an HTTP header key+value pair (e.g.
x-manifest-tier: premium) and every matching request routes directly to that tier’s model, overriding specificity and complexity. Each tier gets a user-picked name + color that shows as a badge on the message row. The create modal autocompletes the header key from the keys Manifest has already seen in the last 7 days, grouped by the SDK that sent them, with example values. Sensitive headers (authorization,cookie, …) are blocked from being used as match rules.
- 910b191: Add custom header-triggered routing tiers. Configure a tier keyed to an HTTP header key+value pair (e.g.
-
View release on GitHub →
🐛 Patch Changes
- 37308ea: Fix cost column showing “—” for self-hosted custom provider messages. Prices entered via the custom provider form are now indexed into the shared pricing cache under
custom:<uuid>/<model>— the same key the proxy writes toagent_messages.model— so the cost recorder can look them up when a request is routed. The cache refreshes immediately on create, model edits, and delete, so new prices take effect without waiting for the daily 5am reload. Custom entries are scoped out of the public/api/v1/model-priceslist so one tenant’s providers can’t leak into another’s. Existing messages recorded withcost_usd = nullstay null (no price snapshot is stored per message); only new messages benefit.
- 37308ea: Fix cost column showing “—” for self-hosted custom provider messages. Prices entered via the custom provider form are now indexed into the shared pricing cache under
-
View release on GitHub →
✨ Minor Changes
- abd9dea: Promote LM Studio to a first-class provider tile alongside Ollama. In the self-hosted version, clicking the LM Studio tile opens a dedicated detail view that probes
http://{localLlmHost}:1234/v1, lists the loaded chat models, and connects them in one click — no URL typing, no manual pricing. A refresh icon re-probes after the user swaps models on the host. When the probe fails inside Docker, the detail view surfaces a two-path “Fix it” card: GUI toggle (LM Studio → Developer → “Serve on Local Network”) and CLI one-liner (lms server start --bind 0.0.0.0 --port 1234 --cors) with a Copy button and a “one-time setup” reassurance. Embedding / reranker / moderation models are filtered out of the discovered list so they don’t leak into the routing tier picker. Local-only tiles are disabled in cloud mode with an “Only available on self-hosted Manifest” hint. ThecustomProviderLogolookup now normalizes names against the shared registry, so an “LM Studio” custom provider shows the real logo everywhere (tier cards, Messages table, Model Prices, Fallback picker).
- abd9dea: Promote LM Studio to a first-class provider tile alongside Ollama. In the self-hosted version, clicking the LM Studio tile opens a dedicated detail view that probes
-
View release on GitHub →
🐛 Patch Changes
-
40e9f9f: Add
org.opencontainers.image.base.nameandorg.opencontainers.image.base.digestOCI labels to the Docker image so Docker Scout can evaluate the “No unapproved base images” and “No outdated base images” policies.The published image already ships SLSA provenance and SPDX SBOM attestations (the build workflow sets
sbom: trueandprovenance: mode=max), but Scout’s base-image policies key off the OCI base-image labels on the image config and buildkit does not auto-generate them. Without the labels, Scout reports “No data” for both policies and the image is stuck at a B health score even when it has no outstanding CVEs.The labels sit next to the matching
FROM … AS runtimeline so a future base-image bump updates both together. No change to build output size, runtime behavior, or the attestation manifests — pure metadata addition on the image config.
-
-
View release on GitHub →
🐛 Patch Changes
-
fec55cf: Bump Docker runtime to
gcr.io/distroless/nodejs22-debian13:nonrootto clear 9 CVEs (1 CRITICAL / 8 HIGH) that the published image inherited from the oldernodejs22-debian12base.Root cause: Google hasn’t rebuilt any tag on
gcr.io/distroless/nodejs22-debian12since Node 22.22.2 and Debian 12’sopenssl 3.0.19-1~deb12u2shipped. Everydebian12variant still bakes Node 22.22.0 on top of the vulnerableopenssl 3.0.18-1~deb12u2, so a digest refresh alone couldn’t clear the scan. Thenodejs22-debian13family already publishes Node v22.22.2 on a newer openssl, so moving the runtime stage to it fixes both CVE sources in a single base-image bump.The move is safe: the prod-deps stage runs
npm ci --ignore-scripts, so no native modules are compiled and the runtime’s glibc version is invisible tonode_modules.node:22-alpineandnode:22-slimdigest pins were also refreshed for hygiene — those layers don’t ship in the final image.CVEs cleared:
- CVE-2025-55130 (CRITICAL, CVSS 9.1) — Node
- CVE-2025-55131, CVE-2025-59465, CVE-2025-59466, CVE-2026-21637, CVE-2026-21710 (HIGH) — Node
- CVE-2026-28388, CVE-2026-28389, CVE-2026-28390 (HIGH) — Debian openssl
Verification: Local Trivy scan (
--severity HIGH,CRITICAL --ignore-unfixed) reports 0 findings post-bump (was 9).docker compose up -dpasses the healthcheck in ~14s and/api/v1/healthreturns{"status":"healthy"}.
-
-
View release on GitHub →
🐛 Patch Changes
-
19f6b0e: Four small Docker-compose quality-of-life fixes, all verified against an existing install without data loss:
- Project name pinned to
mnfst. Docker Compose used to infer the project name from the install directory’s basename (typicallymanifest), so two unrelated projects both happening to live in amanifest/directory would silently share container namespace — the user who reported this saw aFound orphan containerswarning from a completely unrelated container. Addedname: mnfstat the top ofdocker/docker-compose.yml. Container names move frommanifest-manifest-1/manifest-postgres-1tomnfst-manifest-1/mnfst-postgres-1. pgdatavolume name pinned tomanifest_pgdata. With the project rename, Docker would have created a fresh emptymnfst_pgdatavolume on nextup, orphaning every existing self-hoster’s database. Pinningvolumes.pgdata.nameto the historicalmanifest_pgdatakeeps the new compose file attaching to the existing data. Verified locally: tore down an existingmanifeststack, booted the new file from a different directory, confirmed themnfst-postgres-1container mountedmanifest_pgdatawith all 51 migrations intact.- Healthcheck
start_period45s → 90s. On a cold first pull, Docker was flipping the container tounhealthybefore the backend had finished pulling images + running migrations + warming the pricing cache. The 90s grace gives real installs room to boot. - Log rotation. Default Docker
json-filelogging is unbounded — a long-running install can silently fill the host disk. Both services now cap at 5 × 10 MB per container (~50 MB ceiling each).
CI: added an
install-scriptjob indocker-smoke.ymlthat runs the actualdocker/install.shend-to-end against the PR-built image. Caught the${p}healthcheck-escape regression retroactively — and will catch the next one before it ships. The installer now reads its source fromMANIFEST_INSTALLER_SOURCE(defaults tomainon GitHub), so the CI job can point it at a local HTTP server serving the branch under test. - Project name pinned to
-
321a644: Route OpenAI Codex,
-pro,o1-pro, and deep-research models to/v1/responsesfor API-key users. Closes #1660.OpenAI’s
gpt-5.3-codex,gpt-5-codex,gpt-5.1-codex*,gpt-5.2-codex,gpt-5-pro,gpt-5.2-pro,o1-pro, ando4-mini-deep-researchonly acceptapi.openai.com/v1/responses— they return HTTP 400 “not a chat model” on/v1/chat/completions. Manifest’s subscription path already routed these correctly via the ChatGPT Codex backend, but API-key users always hit/v1/chat/completionsand failed. Prod telemetry: 31 distinct users attempting Codex on API keys over the last 90 days, 36% error rate, one user stuck in a 1,400-call retry loop at 98% failure.- New
openai-responsesprovider endpoint targetingapi.openai.com/v1/responses, reusing the existingchatgptformat (sametoResponsesRequest/convertChatGptResponseconverters used by the subscription path — just with a plainAuthorization: Bearerheader instead of the Codex-CLI masquerade). ProviderClient.resolveEndpointswapsopenai→openai-responsesat forward time for any model matching the Responses-only regex. Subscription OAuth still routes toopenai-subscriptionas before; custom endpoints are never overridden.- Model discovery no longer drops Codex/-pro/o1-pro/deep-research — they’re kept so users can select them and the proxy routes them transparently.
gpt-image-*is moved to the non-chat filter (it was only incidentally caught by the old Responses-only filter; it’s image generation, not a chat model). OPENAI_RESPONSES_ONLY_REmoved tocommon/constants/openai-models.tswith a sharedstripVendorPrefixhelper, so discovery and the proxy read the same source of truth without cross-module coupling.
- New
-
-
View release on GitHub →
✨ Minor Changes
-
59bb203: New Docker installs get port 2099 (a nod to the peacock logo) by default. Existing installs keep their current port — no action required on upgrade.
How backward compatibility is preserved
- The backend’s own fallback stays at
3001(it’sprocess.env.PORT ?? 3001everywhere). - The Docker Compose file now sets
PORT=${PORT:-2099}explicitly. New installs frominstall.shget 2099 end-to-end: backend listens on 2099, compose binds127.0.0.1:2099:2099, andBETTER_AUTH_URLdefaults tohttp://localhost:2099. - Existing installs that pull the new image against their unchanged compose file continue to work: no
PORTenv, so the backend falls back to 3001, their old127.0.0.1:3001:3001binding still matches, and theirBETTER_AUTH_URL/ reverse proxy / OAuth callbacks all keep working. - If a user wants to upgrade their compose file but keep port 3001 (e.g., to avoid reconfiguring OAuth callbacks), they set
PORT=3001in.envand the compose file honours it — both the host binding and the internal listener now read${PORT:-2099}. - The Dockerfile
HEALTHCHECKreadsprocess.env.PORT || 3001at runtime so it follows whatever port the backend is actually listening on, regardless of which image-version pairs with which compose file.
Install script UX (closes #1643)
- Default install directory is now
$HOME/manifest(was./manifest), so the one-liner frominstall.shno longer litters whatever directory you happened to run it in. - The confirmation prompt reads from
/dev/ttywhen stdin is not a terminal (typical when pipingcurl | bashor running viabash <(curl ...)). If there is no terminal at all, the script exits with a clear message pointing at--yes. - Detects port conflicts up front: if
2099is already bound, the installer aborts with a pointer to editdocker-compose.yml, instead of lettingdocker compose upfail with a less obvious message. - Copy fix: “up to a couple of minutes” instead of “about 30 seconds” (the installer itself waits up to 120s).
- Prints a
curl -sSf http://localhost:2099/api/v1/healthsmoke-test line alongside the dashboard URL on success. - README now documents
--dir,--yes,--dry-runand shows the review-then-run idiom for security-cautious users.
Housekeeping
- Rename
packages/backend/src/common/utils/sql-dialect.ts→postgres-sql.ts. The file only emits Postgres SQL (no dialect switching), so the old name was misleading. 20 import sites updated.
- The backend’s own fallback stays at
-
-
View release on GitHub →
✨ Minor Changes
- b41c0a2: Connect the Dockerized self-hosted version to local LLM servers on the host. The bundled
--profile ollamaservice is gone; the Manifest container now reaches host-installed Ollama, vLLM, LM Studio, llama.cpp, text-generation-webui, and any OpenAI-compatible server athost.docker.internal:<port>via ahost-gatewayalias. Custom providers accepthttp://and private/loopback URLs in the self-hosted version (cloud metadata endpoints stay blocked). Adds preset chips for local servers and a server-side/v1/modelsprobe that auto-populates the model list. Renames the deployment concept from “local” to “self-hosted” across the codebase (MANIFEST_MODE=selfhosted,isSelfHosted());MANIFEST_MODE=localis still honored as a legacy alias. - 7de07d2: Capture incoming request headers on every proxied chat completion and surface them in the message detail drawer, with a new App/SDK meta row sourced from the existing caller attribution. Sensitive headers (authorization, cookie, proxy-authorization, x-api-key) are stripped before storage, and the Request Headers section is collapsed by default.
- 30adc95: Fix web_browsing false positives that misrouted coding sessions. Pruned generic web-dev vocabulary (html, dom, url, http, link, page) from the webBrowsing keyword list, added weighted scoring, URL detection, code-fence/file-path signals, session stickiness across recent turns, a confidence gate, and a “Wrong category?” feedback control in the Messages log that dampens repeatedly-miscategorized categories.
🐛 Patch Changes
-
2051a74: Code quality audit cleanup across backend, frontend, and shared packages:
- Consolidate the provider registry into a single source of truth at
packages/shared/src/providers.tsthat the backendPROVIDER_REGISTRYand frontendPROVIDERSboth consume, eliminating drift. - Drop the vestigial
DbDialect/detectDialect/portableSqlhelpers and the_dialectparameter threaded through seven services; Manifest has been Postgres-only for some time. - Port
NotificationRulesServiceoff rawDataSource.query()onto TypeORM repositories + QueryBuilder. - Remove the unused
TokenUsageSnapshot/CostSnapshotentities (tables remain; no data migration). - Extract scattered
if (provider === 'xai' | 'copilot' | ...)branches into data-driven hooks (provider-hooks.ts). - Split
scoring/keywords.ts(949 lines) into one file per specificity category underscoring/keywords/. - Split
ProxyService.proxyRequest,ProxyController.chatCompletions,MessagesQueryService.getMessages, andProviderClient.forwardinto focused helpers (all previously 130+ lines). - Consolidate the frontend API layer:
fetchMutatenow takes a path, and aroutingPath(agentName, suffix)helper replaces 30+ duplicated${BASE_URL}/routing/${encodeURIComponent(...)}literals. - Add
recordSafely()andbuildMessageRow()helpers in the proxy write path to dedupe seven fire-and-forget.catch(logger.warn)blocks and five near-identical message inserts. - Remove the deprecated
subscriptionOAuthflag (usesubscriptionAuthMode === 'popup_oauth'). - Drop the identity
sql()wrapper inEmailProviderConfigServiceand helpers.
- Consolidate the provider registry into a single source of truth at
-
4599c47: Shrink the Docker image by switching the runtime stage to distroless Node 22 (
gcr.io/distroless/nodejs22-debian12:nonroot):- Runtime drops the shell,
apk, and the unused yarn toolchain thatnode:22-alpinebakes in. - Production dependencies are now staged on
node:22-slimso glibc matches the distroless debian12 runtime (all runtime deps are pure JS). - Prune
sql.jsfrom the runtime node_modules — it’s an optional TypeORM peer only used by the legacy SQLite local mode, which is never active in Docker. - Add
--prefer-offline --no-audit --no-fundto all npm installs, and pin the two new base images by digest. - Result:
423MB → 362MBon disk (−14.4%),84.2MB → 71.9MBcompressed pull (−14.6%).
- Runtime drops the shell,
-
d5b23dc: Fix custom providers mangling upstream model IDs that contain
/characters (#1591, #1615). Multi-segment model names likeMiniMaxAI/MiniMax-2.7oraccounts/fireworks/routers/kimi-k2p5-turboare now forwarded to the upstream API unchanged instead of having a legitimate slash segment stripped. -
bb3dc29: Retire residual SQLite / sql.js / “local mode” references left behind after the local-mode path was removed:
- Drop the dead
isLocal()branch inRoutingInstructionModal(the/api/v1/healthendpoint never returnsmode, so the branch was unreachable) and the test that faked amode: "local"health response to exercise it. - Tighten the frontend
NotificationRule.is_activetype fromboolean | numbertoboolean, and drop thetypeof === 'number' ? !!x : xcoercion inLimits.tsxandLimitRuleTable.tsx(the integer boolean was a SQLite-era shape; the backend returns real booleans). - Remove the dead
connection: { options: { type: 'sqlite' } }mock inproxy.controller.spec.ts— no production code readsds.connection.options.type. - Remove the stale
vi.mock("../../src/services/local-mode.js", ...)inProviderSelectModal-opencode-go.test.tsx(module was deleted long ago). - Refresh the
packages/backend/src/common/utils/sql-dialect.tsheader (no dialect switching happens — the file is Postgres-only). - Fix comment/test-description rot: “dialect” wording in
query-helpers.ts+ spec, “local mode” inSidebar.test.tsx/session.guard.spec.ts/proxy-rate-limiter.ts, “PG & sql.js” incosts.e2e-spec.ts. - Update
CLAUDE.md: drop references to deleted files (local-bootstrap.service.ts,local-mode.ts,LocalAuthGuard), drop theMANIFEST_DB_PATH/MANIFEST_UPDATE_CHECK_OPTOUTenv vars (no-ops per the v2.x breaking changes), drop the “Local mode database uses sql.js” architecture note, and correct the “Better Auth database” section (Postgres always).
No behaviour change — all four test suites green (backend 4007, frontend 2267, e2e 123) and both packages typecheck clean.
- Drop the dead
- b41c0a2: Connect the Dockerized self-hosted version to local LLM servers on the host. The bundled
-
View release on GitHub →
🐛 Patch Changes
- 135b9e3: Fix blank dashboard when exposing Manifest on a LAN IP over HTTP. Helmet’s default CSP emitted
upgrade-insecure-requests, which browsers enforce on private IPv4 ranges (10.x, 172.16-31.x, 192.168.x) but relax for localhost — so the JS bundle was rewritten tohttps://and silently failed to load, leaving an empty<body>. The directive is now disabled; HTTPS deployments should enforce upgrades via HSTS at the reverse proxy instead.
- 135b9e3: Fix blank dashboard when exposing Manifest on a LAN IP over HTTP. Helmet’s default CSP emitted