v3.5.4 — The Reliability Patch
Background agents used to silently die. Stale tasks would haunt your session like ghosts — spawned but never finished, timing out on tasks that were still actively running. This release kills that bug dead, alongside 30+ fixes that make oh-my-opencode rock-solid for daily driving.
200 files changed. +10,921/−4,755 lines.
Highlights
Background Agent Staleness Overhaul
- Fix stale timeout from killing actively running background tasks — the core bug that made agents appear to "hang"
- Detect stale tasks that never received progress updates (true zombies vs. active workers)
- Refresh
lastUpdateon allmessage.part.updatedevents, not just tool events - Add
TaskHistoryclass for persistent task tracking across compaction boundaries - Wire
TaskHistoryintoBackgroundManagerand compaction pipeline
Session & Tool Inheritance
- Add
session-tools-storefor tracking tool restrictions per session - Inherit parent session tool restrictions in background task notifications
- Apply
parentToolsin all parent session notification paths - Store tool restrictions at prompt-send sites for consistent enforcement
Stop Hooks & Continuation Fixes
- Execute all Stop hooks instead of returning after first non-blocking result (critical correctness fix)
- Fire todo continuation for all sessions with incomplete todos, not just the current one
- Add cooldown and stagnation cap to prevent re-injection loops
Performance
- Rules injector: mtime-based parse cache and dirty-write gate — skip redundant filesystem writes
- Directory injectors: skip
writeFileSyncwhen no new paths injected - Session messages: event-based caching to prevent memory leaks from repeated
.messages()calls - Comment checker: hard process reap and global semaphore to prevent CPU runaway
Doctor Redesign
- 3-tier output (default/status/verbose) with consolidated checks
- Proper oMoMoMoMo branding, removed stale providers check
Community Bug Fixes (10 contributors)
- Guard against non-string tool output in afterToolResult hooks (@ojh102)
- Load LSP config from JSONC configuration files (@COLDTURNIP)
- Parse config sections independently — one invalid field no longer discards the entire config (@kaizen403)
- Detect GPT models behind proxy providers like litellm/ollama (@solssak)
- Fix
process.cwd()usage for project skill discovery (@willy-scr) - Resolve symlink realpath on macOS (@bvanderhorn)
- Execute all Stop hooks correctly (@raki-1203)
- Reduce memory leaks from session message caching (@popododo0720)
- Block remote URLs in look-at file_path validation (@devxoul)
- Add
file://URI support inprompt_appendconfiguration (@devxoul) - Fix Google Auth docs link (@G36maid)
Other Fixes
- Parse
load_skillswhen passed as JSON string - Disable thinking parameter for Z.ai GLM models
- Normalize Windows separators for skill source globs
- Bounded shutdown wait for event stream processor (
cli-run) - Fix LSP Windows binary availability check
- Resolve
subagent_typefor TUI display - Add session agent resolver for subagent_type lookup
Patch it, ship it, boulder on.
- 6dc8b7b fix(ci): sync publish.yml test steps with ci.yml to prevent mock pollution
- 361d9a8 @iyoda has signed the CLA in #1845
- d8b4dba @liu-qingyuan has signed the CLA in #1844
- 7b89df0 chore(schema): regenerate JSON schema
- dcb76f7 test(directory-readme-injector): use real files instead of fs module mocks
- 7b62f0c test(directory-agents-injector): use real files instead of fs module mocks
- 2a7dfac test(skill-tool): restore bun mocks after tests
- 2b4651e test(rules-injector): restore bun mocks after suite
- 37d3086 test(atlas): reset session state instead of module mocking
- e7dc372 test(prometheus-md-only): avoid hook-message storage constant mocking
- e995443 refactor(call-omo-agent): inject executeSync dependencies for tests
- 3a69096 test(todo-continuation-enforcer): stabilize fake timers
- 74d2ae1 fix(shared): normalize macOS realpath output
- a0c9381 fix: prevent stale timeout from killing actively running background tasks
- 65a06aa Merge pull request #1833 from code-yeongyu/fix/inherit-parent-session-tools
- 754e6ee Merge pull request #1829 from code-yeongyu/fix/issue-1805-lsp-windows-binary
- affefee Merge pull request #1835 from code-yeongyu/fix/issue-1781-tmux-pane-width
- 90463ba Merge pull request #1834 from code-yeongyu/fix/issue-1818-agents-skills-path
- 073a074 Merge pull request #1828 from code-yeongyu/fix/issue-1825-run-never-exits
- cdda08c Merge pull request #1832 from code-yeongyu/fix/issue-1691-antigravity-error
- a8d26e3 Merge pull request #1831 from code-yeongyu/fix/issue-1701-load-skills-string
- 8401f0a Merge pull request #1830 from code-yeongyu/fix/issue-980-zai-glm-thinking
- 32470f5 Merge pull request #1836 from code-yeongyu/fix/issue-1769-background-staleness
- c3793f7 @code-yeongyu has signed the CLA in #1699
- 3de05f6 fix: apply parentTools in all parent session notification paths
- 8514906 fix: inherit parent session tool restrictions in background task notifications
- f20e1aa feat: store tool restrictions in session-tools-store at prompt-send sites
- 936b51d feat: add parentTools field to BackgroundTask, LaunchInput, ResumeInput
- 38a4bbc feat: add session-tools-store for tracking tool restrictions per session
- 7186c36 fix(skill-loader): discover skills from .agents/skills/ directory
- 121a3c4 fix(tmux): thread agent_pane_min_width config through pane management
- 072b305 fix(parser): wrap parseAnthropicTokenLimitError in try/catch
- dd9eeaa test(session-recovery): add tests for detect-error-type resilience
- 3fa543e fix(delegate-task): parse load_skills when passed as JSON string
- 9f52e48 fix(think-mode): disable thinking parameter for Z.ai GLM models
- 26ae666 test(lsp): use explicit BDD markers in Windows spawn test
- 422db23 fix(lsp): remove unreliable Windows binary availability check
- b7c32e8 fix(test): use string containment check for ANSI-wrapped console.log output
- c24c4a8 fix(cli-run): bounded shutdown wait for event stream processor
- f3ff32f fix(background-agent): detect stale tasks that never received progress updates
- daf011c fix(ci): isolate loader.test.ts to prevent CWD deletion contamination
- c8bc267 fix(ci): isolate all mock-heavy test files from remaining test step
- a4a5502 Merge pull request #1799 from bvanderhorn/fix/resolve-symlink-realpath
- 4ab93c0 fix: refresh lastUpdate on all message.part.updated events, not just tool events
- a809ac3 @cloudwaddie-agent has signed the CLA in #1827
- ac99f98 make agents to load skills more
- c8cd637 Merge pull request #1817 from code-yeongyu/fix/todo-continuation-always-fire
- 3a68a89 @Strocs has signed the CLA in #1822
- 32d4697 @professional-ALFIE has signed the CLA in #1820
- f876d60 Merge pull request #1750 from ojh102/fix/guard-non-string-tool-output
- 4e5321a Merge pull request #1765 from COLDTURNIP/fix/load_lsp_from_jsonc
- 7a3df05 fix(todo-continuation-enforcer): fire continuation for all sessions with incomplete todos
- c6bea11 Merge pull request #1771 from kaizen403/fix/partial-config-parsing
- 9fe48d2 Merge pull request #1787 from popododo0720/fix/memory-leak-session-messages-caching
- adf8049 Merge pull request #1790 from raki-1203/fix/stop-hooks-early-return
- b520eac Merge pull request #1791 from G36maid/patch-1
- f722fe6 Merge pull request #1809 from willy-scr/fix/project-skills-process-cwd
- 9742f7d fix(slashcommand): exclude skills from tool description to avoid duplication with skill tool
- e392443 feat(compaction): wire TaskHistory into BackgroundManager and compaction pipeline
- 0946a6c feat(compaction): add delegated agent sessions section with resume directive
- a413e57 feat(background-agent): add TaskHistory class for persistent task tracking
- a7b56a0 fix(doctor): oMoMoMoMo branding, remove providers check, fix comment-checker detection
- 2ba148b refactor(doctor): redesign with 3-tier output and consolidated checks
- 6df24d3 Merge pull request #1812 from code-yeongyu/refactor/remove-subagent-question-blocker-hook
- b58f3ed refactor: remove redundant subagent-question-blocker hook
- 0b1fdd5 fix(publish): make enhanced summary optional for patch, mandatory for minor/major
- 4f3371c fix(publish): use generate-changelog.ts for contributor thanks
- f9ea9a4 fix(project): use directory param instead of process.cwd() for agents, commands, and slash commands
- b008a57 Merge pull request #1810 from code-yeongyu/fix/resolve-subagent-type-for-tui-display
- 1a5c9f2 fix(tool-execute-before): resolve subagent_type for TUI display
- 6fb933f feat(plugin): add session agent resolver for subagent_type lookup
- f6fbac4 perf(comment-checker): add hard process reap and global semaphore to prevent CPU runaway
- 4c10723 @willy-scr has signed the CLA in #1809
- 10a6085 perf(todo-continuation): add cooldown and stagnation cap to prevent re-injection loops
- a6372fe Merge pull request #1794 from solssak/fix/isGptModel-proxy-providers
- 6914f2f fix(skills): use directory param instead of process.cwd() for project skill discovery
- c8851b5 Merge branch 'perf/rules-injector-parse-cache' into dev
- 75f35f1 perf(rules-injector): add mtime-based parse cache and dirty-write gate
- e99088d Merge branch 'perf/directory-injector-dirty-flag' into dev
- 492029f perf(directory-injectors): skip writeFileSync when no new paths injected
- 58b7aff fix: detect GPT models behind proxy providers (litellm, ollama) in isGptModel
- 4a991b5 Merge pull request #821 from devxoul/prompt-append-file-uri
- 60b4d20 feat(agents): add file:// URI support in prompt_append configuration
- b8c1249 Merge pull request #1807 from code-yeongyu/fix/skills-sources-schema
- 5a83c61 fix(skills): normalize windows separators for source globs
- ad468ec Merge pull request #1758 from devxoul/lookat-remote-block
- 0001bc8 feat(skills): load config sources in runtime discovery
- aab8a23 fix(schema): generate full JSON schema with Zod v4
- 1511886 fix: use fs.realpath instead of manual path.resolve for symlink resolution
- 6c7b611 docs: Fix link in Google Auth section of configurations.md
- 5c8d694 fix: execute all Stop hooks instead of returning after first non-blocking result
- eb56701 fix: reduce session.messages() calls with event-based caching to prevent memory leaks
- d3978ab fix: parse config sections independently so one invalid field doesn't discard the entire config
- f80b72c fix(config): load lsp config from jsonc configuration files
- 3eb7dc7 block remote URLs in look-at file_path validation
- bb6a011 fix(hooks): guard against non-string tool output in afterToolResult hooks
Thank you to 10 community contributors:
- @ojh102:
- fix(hooks): guard against non-string tool output in afterToolResult hooks
- @devxoul:
- block remote URLs in look-at file_path validation
- @COLDTURNIP:
- fix(config): load lsp config from jsonc configuration files
- @kaizen403:
- fix: parse config sections independently so one invalid field doesn't discard the entire config
- @popododo0720:
- fix: reduce session.messages() calls with event-based caching to prevent memory leaks
- @raki-1203:
- fix: execute all Stop hooks instead of returning after first non-blocking result
- @G36maid:
- docs: Fix link in Google Auth section of configurations.md
- @bvanderhorn:
- fix: use fs.realpath instead of manual path.resolve for symlink resolution
- @solssak:
- fix: detect GPT models behind proxy providers (litellm, ollama) in isGptModel
- @willy-scr:
- fix(skills): use directory param instead of process.cwd() for project skill discovery
- fix(project): use directory param instead of process.cwd() for agents, commands, and slash commands