You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
session: titles never generated in v2 (no auto trigger + free-tier rejection) #58176
opencode session list → new session shows Untitled session; session_v2.title is NULL.
Force generation: opencode api patch /api/session/<id> --data '{"title":""}' → title stays NULL; no output, no log line.
Reproduces with a fresh data dir and --standalone, so it is not migration or DB related.
Expected Behavior
The session gets a generated title after the first user message, as in v1 (which logged agent=title small=true).
Actual Behavior
Two separate defects:
1. The title request is rejected by the free-tier gate.
opencode run --standalone --agent title "say ok"# Error: OpenCode's free tier can only be used from within OpenCode. Download it at https://opencode.ai and keep building.
opencode run --standalone --agent summary "say ok"# same error
opencode run --standalone --agent build "say ok"# works
opencode run --standalone --agent compaction "say ok"# works
Same for every opencode/* model, so it is the maintenance request shape, not the model. SessionTitle.attempt swallows provider errors and returns undefined without logging, so the failure is invisible.
2. No automatic trigger.
Inspecting the 2.1.3 binary, the only caller of title generation is the session.update handler when title is an empty string, and the only UI caller of that is /rename submitted empty (session.title.generate). Nothing runs after the first message.
Additional Context
opencode debug agents resolves the agent correctly: title → {providerID: "opencode", id: "big-pickle"}.
Removing small_model changes nothing; it is deprecated in favor of agents.title.model.
v1 logs contained message=stream ... small=true agent=title; v2 logs contain no title activity at all.
Thanks for the detailed report. I reproduced this on 2.1.3 with a fresh data dir and only the free opencode/big-pickle model:
opencode run --standalone --agent build "say ok" works.
opencode run --standalone --agent title "say ok" fails with OpenCode's free tier can only be used from within OpenCode....
After opencode run --standalone "reply with exactly: hi", session_v2.title stays NULL, and nothing is logged.
One correction on the second point: I don't think the automatic trigger is missing. With the same 2.1.3 build and a local mock provider, a title request is sent automatically after the first message and the session gets a title. That request has the same x-opencode-* headers and user-agent as a normal turn; its body has no tools and no output limit. So the missing titles look like the free-tier rejection of the title request (your first point), which SessionTitle.attempt then drops silently.
I couldn't test the free tier from a source build of the latest dev (09a1db3), because the free tier rejects every request from a local build. 2.1.3 is the current release, and the title code is unchanged on dev. The script below reproduces it.
Related: #49592 (the same rejection of the title/compaction agents on v1, fixed on the server at the time) and #55575.
Reproduction script (repro.sh)
#!/usr/bin/env bash# Repro for #58176: v2 session titles stay NULL on the free `opencode` provider.# Needs network access to opencode.ai (free tier, no credentials).# OC="opencode" by default; set OC to run another build, e.g. from source.set -u
OC=${OC:-opencode}
ROOT=$(mktemp -d /tmp/opencode/r58176.XXXX)export XDG_DATA_HOME=$ROOT/data XDG_CONFIG_HOME=$ROOT/config XDG_STATE_HOME=$ROOT/state XDG_CACHE_HOME=$ROOT/cache
mkdir -p "$XDG_CONFIG_HOME/opencode""$ROOT/project"echo'{"model":"opencode/big-pickle"}'>"$XDG_CONFIG_HOME/opencode/opencode.json"cd"$ROOT/project"$OC --version
echo"== normal turn (build agent): works"$OC run --standalone --agent build "say ok"2>&1| tail -2
echo"== same model, title agent: rejected by the free-tier gate"$OC run --standalone --agent title "say ok"2>&1| tail -2
echo"== new session: the automatic title request is sent, but the title stays NULL"$OC run --standalone "reply with exactly: hi"2>&1| tail -1
sleep 5
DB=$(find "$XDG_DATA_HOME" -name opencode.db | head -1)
bun -e "const {Database}=require('bun:sqlite');console.log(new Database('$DB',{readonly:true}).query('select id,title from session_v2').all())"
Additional data point from a $0-balance Console account (provider opencode), Windows 11, npm global install.
The default small model is paid, and it fails
opencode run --agent title --model opencode/gpt-6-luna "say ok"
-> Error: Upstream request failed: Insufficient account funds
opencode run --agent title --model opencode/deepseek-v4.1-flash-free "say ok"
-> responds normally
Model.small("opencode") resolves to gpt-6-luna (family gpt-luna, paid). So on this account the first title attempt can never succeed, and the fallback to the primary model does not produce a title either.
What I could rule out
Pointing agents.title.model at the free model that works above does not restore titles (2.1.3). The same config also fails on 2.1.2, so in this setup this is not a 2.1.3-only regression.
PATCH /api/session/<id> with {"title":""} returns 204, leaves the title NULL, and writes no log line at any level.
/api/agent/title correctly reports the configured model (not null), so the override is being applied.
GET /api/session/<id> reports model: null on the affected sessions while the messages carry the model (flint-40b-free, deepseek-v4.1-flash-free).
Why nothing surfaces
In SessionTitle.generate, attempt marks failed on a provider error and returns undefined, and the caller (FiberMap.run in session/runner/llm.ts) discards failures. Any early return (!selection, no first user message, empty title) is equally silent. Logging the failure reason / early-return branch there would make this class of report diagnosable from the log alone.
Additional data point from the Windows desktop app (2.1.3, free opencode/deepseek-v4.1-flash-free). The automatic title request is sent, and it fails at the free-tier gate.
Environment: Windows 10.0.19044 x64, desktop app 2.1.3 (channel latest), no plugins, no custom config.
I instrumented the session http.request / http.response hooks. Title request:
POST https://opencode.ai/inference/openai/v1/chat/completions
body keys: model, messages, stream, stream_options
headers identical to a normal turn: authorization: Bearer public, user-agent: opencode/latest/2.1.3/desktop, x-opencode-client: desktop, same x-opencode-* session headers
response: 403 {"type":"error","error":{"type":"FreeTierError","message":"OpenCode's free tier can only be used from within OpenCode. Download it at https://opencode.ai and keep building."}}
Same session and model:
normal turn: model, messages, tools, stream, stream_options, max_completion_tokens → 200
POST /api/session/<id>/generate: model, messages, tools, stream, stream_options → 200
The only meaningful difference is the missing tools (and max_completion_tokens), so this points at the request body shape rather than auth/headers. The title request is tool-less by design (packages/core/src/session/title.ts), and SessionTitle.attempt swallows the provider error.
PATCH /api/session/<id> with {"title":""} returns 204 and leaves title NULL; a non-empty title renames correctly.
Workaround for free-tier users: a title hook that calls ctx.generate.text (a tool-bearing request, same shape as the 200 /generate call) and assigns event.result. I haven't run that end-to-end yet, but the captured /generate request is accepted.
The control result supports the free-tier-gate root cause discussed here and rules out my initial "title call races the first turn" hypothesis (#58411) — the non-opencode provider titles fine even though its title call also runs concurrently with the first turn.
Source-level confirmation of the silence (dev branch)
packages/core/src/session/runner/llm.ts (~L171): the title fiber is started via FiberMap.run(titles, sessionID, title.generate(sessionID), { onlyIfMissing: true }) with no failure observer.
packages/core/src/session/title.ts: every failure path exits silently — providerError → failed = true, Effect.catchTag("AI.Error", ...) → failed = true, then if (failed) return and if (!title) return — and the module contains no log calls at all.
Title attempts persist no session message record in either the failing or the successful arm, so nothing is observable session-side.
On v1.19.3 the server logged automatic title generation for every top-level session (message=stream ... agent=title small=true); the last example is dated 2026-10-22.
After the automatic update to v2.1.4, new sessions keep title = null ("New session - ").
Verified live through the HTTP API with a fresh session and the same free model: the model answered normally, the turn completed with idle, outcome: succeeded, and the session title was still null more than 75 seconds later. No error surface anywhere (server log clean, consistent with FreeTierError being silently dropped).
Matches the described root cause: the title request is sent, the free tier rejects it with 403, and the failure is not logged or surfaced.
Happy to test a build with #57624 or any other fix on Windows if useful.
Confirming on 2.1.4, Linux desktop (opencode/deepseek-v4.1-flash-free, 5/5 sessions with title IS NULL after the upgrade) and adding a workaround, since the previous confirmations only describe the symptom.
The automatic trigger does work in 2.1.4. Only the title model is the problem: point the title agent at a non-opencode provider and titles come back while the chat stays on the free gateway.
Terminal: TERM=xterm-256color (no COLORTERM / TERM_PROGRAM)
Shell: /bin/bash
Active plugins: none
Providers: no authenticated integrations; only the built-in free opencode provider
Steps
opencode run "reply with exactly: ok" in a fresh cwd (default model opencode/big-pickle)
opencode api get /api/session
Observed
New session created 2026-10-28T00:33:08Z: the turn completes normally (ok), title = null.
Interactive session on opencode/deepseek-v4.1-flash-free: same, title = null.
Sessions created on v1.x on the same machine still carry titles (e.g. opencode 卸载后重新安装, Version query), so this is a v2 regression and not a migration artifact.
No FreeTierError / 403 line appears in ~/.local/share/opencode/log/opencode.log, consistent with the title request failing silently.
Workaround that works today: Ctrl+R (session.rename) renames manually.
Related: #57624 would at least label such sessions from the first prompt when generation fails.
Closing this issue as resolved. Automatic session title generation is now functioning correctly.
I initially worked around the issue by manually using /rename <session-title>, but verified on October 30, 2026, that auto-generation has recovered across both macOS and WSL environments.
Verification Details
Version:v2.1.3 (identical across environments)
Configuration: No changes made to opencode.config
The command opencode session list --max-count 1 --format json was run after executing test prompts on both machines. Here are the individual results:
Activity
opencode-agent commentedon Oct 22, 2026
Thanks for the detailed report. I reproduced this on 2.1.3 with a fresh data dir and only the free
opencode/big-picklemodel:opencode run --standalone --agent build "say ok"works.opencode run --standalone --agent title "say ok"fails withOpenCode's free tier can only be used from within OpenCode....opencode run --standalone "reply with exactly: hi",session_v2.titlestays NULL, and nothing is logged.One correction on the second point: I don't think the automatic trigger is missing. With the same 2.1.3 build and a local mock provider, a title request is sent automatically after the first message and the session gets a title. That request has the same
x-opencode-*headers and user-agent as a normal turn; its body has notoolsand no output limit. So the missing titles look like the free-tier rejection of the title request (your first point), whichSessionTitle.attemptthen drops silently.I couldn't test the free tier from a source build of the latest
dev(09a1db3), because the free tier rejects every request from a local build. 2.1.3 is the current release, and the title code is unchanged ondev. The script below reproduces it.Related: #49592 (the same rejection of the title/compaction agents on v1, fixed on the server at the time) and #55575.
Reproduction script (repro.sh)
Run it:
bash repro.shmartinochoaarboin commentedon Oct 23, 2026
Additional data point from a
$0-balance Console account (provideropencode), Windows 11, npm global install.The default small model is paid, and it fails
Model.small("opencode")resolves togpt-6-luna(familygpt-luna, paid). So on this account the first title attempt can never succeed, and the fallback to the primary model does not produce a title either.What I could rule out
agents.title.modelat the free model that works above does not restore titles (2.1.3). The same config also fails on 2.1.2, so in this setup this is not a 2.1.3-only regression.PATCH /api/session/<id>with{"title":""}returns204, leaves the titleNULL, and writes no log line at any level./api/agent/titlecorrectly reports the configured model (notnull), so the override is being applied.GET /api/session/<id>reportsmodel: nullon the affected sessions while the messages carry the model (flint-40b-free,deepseek-v4.1-flash-free).Why nothing surfaces
In
SessionTitle.generate,attemptmarksfailedon a provider error and returnsundefined, and the caller (FiberMap.runinsession/runner/llm.ts) discards failures. Any early return (!selection, no first user message, empty title) is equally silent. Logging the failure reason / early-return branch there would make this class of report diagnosable from the log alone.sinneycz commentedon Oct 23, 2026
Additional data point from the Windows desktop app (2.1.3, free
opencode/deepseek-v4.1-flash-free). The automatic title request is sent, and it fails at the free-tier gate.Environment: Windows 10.0.19044 x64, desktop app 2.1.3 (channel latest), no plugins, no custom config.
I instrumented the session
http.request/http.responsehooks. Title request:POST https://opencode.ai/inference/openai/v1/chat/completionsmodel, messages, stream, stream_optionsauthorization: Bearer public,user-agent: opencode/latest/2.1.3/desktop,x-opencode-client: desktop, samex-opencode-*session headers{"type":"error","error":{"type":"FreeTierError","message":"OpenCode's free tier can only be used from within OpenCode. Download it at https://opencode.ai and keep building."}}Same session and model:
model, messages, tools, stream, stream_options, max_completion_tokens→ 200POST /api/session/<id>/generate:model, messages, tools, stream, stream_options→ 200The only meaningful difference is the missing
tools(andmax_completion_tokens), so this points at the request body shape rather than auth/headers. The title request is tool-less by design (packages/core/src/session/title.ts), andSessionTitle.attemptswallows the provider error.PATCH /api/session/<id>with{"title":""}returns 204 and leavestitleNULL; a non-empty title renames correctly.Workaround for free-tier users: a
titlehook that callsctx.generate.text(a tool-bearing request, same shape as the 200/generatecall) and assignsevent.result. I haven't run that end-to-end yet, but the captured/generaterequest is accepted.xhugoliu commentedon Oct 23, 2026
Cross-posting extras from #58411 (auto-flagged as a duplicate of this one):
Control-arm observation (2.1.3, same machine/day, 5 runs without
--title)opencode/glm-5.3-flash-freeNew session — <ts>), still NULL at t+30sopencode/deepseek-v4.1-flash-freegemini-3.5-flash-lite(control)The control result supports the free-tier-gate root cause discussed here and rules out my initial "title call races the first turn" hypothesis (#58411) — the non-opencode provider titles fine even though its title call also runs concurrently with the first turn.
Source-level confirmation of the silence (dev branch)
packages/core/src/session/runner/llm.ts(~L171): the title fiber is started viaFiberMap.run(titles, sessionID, title.generate(sessionID), { onlyIfMissing: true })with no failure observer.packages/core/src/session/title.ts: every failure path exits silently —providerError→failed = true,Effect.catchTag("AI.Error", ...)→failed = true, thenif (failed) returnandif (!title) return— and the module contains no log calls at all.Two notes that may help triage beyond this issue:
Model.small→ paidgpt-6-lunaselection failure mode reported above is the same territory as title generation: Model.small selects a metered model even when the provider offers a free one #52004 / fix(model): make Model.small prefer free/cheap models and respect enabled state #56761.armandolazarte commentedon Oct 26, 2026
Adding an occurrence on Windows with the free
opencode/*gateway models.Environment
latest, updated automatically from v1.19.3 between Oct 22 and Oct 26)opencode/glm-5.3-flash-free(free provider, session model)What we observed
message=stream ... agent=title small=true); the last example is dated 2026-10-22.title = null("New session - ").idle, outcome: succeeded, and the session title was stillnullmore than 75 seconds later. No error surface anywhere (server log clean, consistent withFreeTierErrorbeing silently dropped).Matches the described root cause: the title request is sent, the free tier rejects it with 403, and the failure is not logged or surfaced.
Happy to test a build with #57624 or any other fix on Windows if useful.
flaviovich commentedon Oct 27, 2026
Confirming on 2.1.4, Linux desktop (
opencode/deepseek-v4.1-flash-free, 5/5 sessions withtitle IS NULLafter the upgrade) and adding a workaround, since the previous confirmations only describe the symptom.The automatic trigger does work in 2.1.4. Only the title model is the problem: point the
titleagent at a non-opencodeprovider and titles come back while the chat stays on the free gateway.{ "small_model": "google/gemini-3.5-flash-lite", "agent": { "title": { "model": "google/gemini-3.5-flash-lite" } } }iamlijiu commentedon Oct 27, 2026
Confirming this still reproduces on v2.2.0 with the free
opencodeprovider.Environment
@opencode/cli, channel latest)opencodeproviderSteps
opencode run "reply with exactly: ok"in a fresh cwd (default modelopencode/big-pickle)opencode api get /api/sessionObserved
ok),title = null.opencode/deepseek-v4.1-flash-free: same,title = null.opencode 卸载后重新安装,Version query), so this is a v2 regression and not a migration artifact.FreeTierError/ 403 line appears in~/.local/share/opencode/log/opencode.log, consistent with the title request failing silently.Workaround that works today:
Ctrl+R(session.rename) renames manually.Related: #57624 would at least label such sessions from the first prompt when generation fails.
LucienChu commentedon Nov 1, 2026
Closing this issue as resolved. Automatic session title generation is now functioning correctly.
I initially worked around the issue by manually using
/rename <session-title>, but verified on October 30, 2026, that auto-generation has recovered across both macOS and WSL environments.Verification Details
v2.1.3(identical across environments)opencode.configThe command
opencode session list --max-count 1 --format jsonwas run after executing test prompts on both machines. Here are the individual results:WSL Environment:
[ { "id": "ses_e6849c53affeP3hJEoH0j6QFF0", "title": "Christmas 2026 date", "updated": 1793546667095, "created": 1793546664652, "projectId": "84bc16e9e6e61777ce8b35999354d42a1cfe5c55", "directory": "/home/lucienchu" } ]Mac
[ { "id": "ses_e7028250cffeK20SOl9sz427sE", "title": "Zustand guide for React", "updated": 1793414664175, "created": 1793414650675, "projectId": "cf26dc619c2b1e8cb5a0dfe0849513026b6ff957", "directory": "/Users/lucien" } ]