When a later-loaded MCP config (e.g., .claude/.mcp.json) marks a server
as disabled, it now properly removes that server from both the servers
object and loadedServers array.
Previously, disabled servers were only skipped during loading, which
meant they wouldn't override servers loaded from earlier configs. This
made it impossible to disable project-level MCPs using local overrides.
Now the disabled flag works as expected: local configs can disable
servers defined in project or user configs.
Use setSessionAgent (first-write wins) instead of updateSessionAgent in chat.message handler. This prevents the default agent from overwriting a custom agent that was set via UI switch.
Fixes#893
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refresh documentation across all AGENTS.md files and update configuration documentation with latest features.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Minor updates to config handler, plugin detector, index entry, and builtin command templates.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add new toast types and improve state management for background task notifications. Update tests to cover new scenarios.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Multiple files were hardcoding ~/.config/opencode paths instead of using
getOpenCodeConfigDir() which respects the OPENCODE_CONFIG_DIR env var.
This broke profile isolation features like OCX ghost mode, where users
set OPENCODE_CONFIG_DIR to a custom path but oh-my-opencode.json and
other configs weren't being read from that location.
Changes:
- plugin-config.ts: Use getOpenCodeConfigDir() directly
- cli/doctor/checks: Use getOpenCodeConfigDir() for auth and config checks
- tools/lsp/config.ts: Use getOpenCodeConfigDir() for LSP config paths
- command loaders: Use getOpenCodeConfigDir() for global command dirs
- hooks: Use getOpenCodeConfigDir() for hook config paths
- config-path.ts: Mark getUserConfigDir() as deprecated
- tests: Ensure OPENCODE_CONFIG_DIR is properly isolated in tests
- Change skill directory from 'skill' (singular) to 'skills' (plural) to match OpenCode standard
- Use getOpenCodeConfigDir() to respect OPENCODE_CONFIG_DIR environment variable
- Update documentation and tests to reflect correct paths
Fixes#810
- Rename agent name from 'atlas' to 'Atlas' (PascalCase like Sisyphus, Metis, Momus)
- Add migration for lowercase 'atlas' -> 'Atlas' for backward compatibility
- Keep hook name as 'atlas' (lowercase) to match other hook naming conventions
- Update all references in types, schema, hooks, commands, and tests
- Delete document-writer.ts agent file
- Remove from types, schema, utils, index exports
- Remove tool restrictions entry
- Remove migration mappings
- Update atlas.ts to use category="writing" instead of agent="document-writer"
- Update init-deep command template
- Update all documentation (AGENTS.md, README.*, docs/)
- Regenerate schema.json
document-writer functionality is now handled via delegate_task with
category="writing" which uses the writing category's model config.
Update plugin handlers, commands, and integration points to use 'atlas' agent name. Start-work command and config handler now reference 'atlas'.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Add session.status re-check in stability detection before completing
- Reset stablePolls if session is not idle (agent still working)
- Fix statusText to show CANCELLED instead of COMPLETED for non-completed tasks
- Root AGENTS.md: Updated timestamp, commit hash, line counts
- src/agents/AGENTS.md: Updated to 50 lines, current structure
- src/cli/AGENTS.md: Updated to 57 lines, current structure
- src/features/AGENTS.md: Updated to 65 lines, current structure
- src/hooks/AGENTS.md: Updated to 53 lines, current structure
- src/shared/AGENTS.md: Updated to 52 lines, core utilities
- src/tools/AGENTS.md: Updated to 50 lines, tool categories
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
- Added withOperationRetry<T>() helper method that retries operations up to 3 times
- Catches "Not connected" errors (case-insensitive)
- Cleans up stale client before retry
- Modified callTool, readResource, getPrompt to use retry logic
- Added tests for retry behavior (3 new test cases)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
fix: pass model parameter when resuming background tasks
Ensure resumed tasks maintain their original model configuration
from category settings, preventing unexpected model switching.
Previous test was setting mainSessionID to 'main-session-123' and the
next test expected undefined. The outer beforeEach wasn't properly
resetting state between tests in the nested describe block.
Adding a nested beforeEach ensures proper test isolation.
category-default is the intended behavior for builtin categories,
not a fallback. Only show toast warning when:
- inherited: model from parent session (custom category without model)
- system-default: OpenCode's global default model
User-defined and category-default are both expected behaviors,
so no warning is needed.
The transform hook was failing to inject synthetic parts because
message.info.sessionID is not always available in the OpenCode SDK.
Fix: Use getMainSessionID() as fallback when message.info.sessionID is undefined.
This ensures keyword-detector and claude-code-hooks content (like ulw/ultrawork)
is properly injected even when the SDK doesn't provide sessionID in message.info.
- Remove injectPendingContext function (no longer needed)
- Remove createContextInjectorHook function (chat.message hook removed)
- Change transform hook from prepend to synthetic part insertion
- Follow empty-message-sanitizer pattern (minimal field set)
- synthetic: true flag hides content from UI but passes to model
- Synthetic part inserted BEFORE user text part
The resume method was not passing the stored model from the task,
causing Sisyphus-Junior to revert to the default model when resumed.
This fix adds the model to the prompt body in resume(), matching
the existing behavior in launch().
Fixes#826
OpenCode API returns different structures for user vs assistant messages:
- User: info.model = { providerID, modelID } (nested)
- Assistant: info.modelID, info.providerID (flat top-level)
Previous code only checked nested format, causing model info loss when
continuation hooks fired after assistant messages.
Files modified:
- todo-continuation-enforcer.ts
- ralph-loop/index.ts
- sisyphus-task/tools.ts
- background-agent/manager.ts
Added test for assistant message model extraction.
The prometheus-md-only hook was not enforcing file restrictions because
getSessionAgent() returned undefined - setSessionAgent was only called
in message.updated event which doesn't always provide agent info.
- Add setSessionAgent call in chat.message hook when input.agent exists
- Add session state tests for setSessionAgent/getSessionAgent
- Add clearSessionAgent cleanup to prometheus-md-only tests
This ensures prometheus-md-only hook can reliably identify Prometheus
sessions and enforce .sisyphus/*.md write restrictions.
The watermark (commit footer and co-author) was inconsistently applied because:
1. The skill tool didn't receive gitMasterConfig
2. The approach was 'default ON, inject DISABLED override' which LLMs sometimes ignored
This refactors to 'inject only when enabled' approach:
- Remove hardcoded watermark section from base templates
- Dynamically inject section 5.5 based on config values
- Default is still ON (both true when no config)
- When both disabled, no injection occurs (clean prompt)
Also fixes missing config propagation to skill tool and createBuiltinAgents.
feat(concurrency): prevent background task races and leaks
Summary
Fixes race conditions and memory leaks in the background task system that could cause "all tasks complete" notifications to never fire, leaving parent sessions waiting indefinitely.
Why This Change?
When background tasks are tracked for completion notifications, the system maintains a pendingByParent map to know when all tasks for a parent session are done. Several edge cases caused "stale entries" to accumulate in this map:
1. Re-registering completed tasks added them back to pending tracking, but they'd never complete again
2. Changing a task's parent session left orphan entries in the old parent's tracking set
3. Concurrent task operations could cause double-acquisition of concurrency slots
These bugs meant the system would sometimes wait forever for tasks that were already done.
What Changed
- Concurrency management: Added proper acquire/release lifecycle with cleanup on process exit (SIGINT, SIGTERM)
- Parent session tracking: Fixed cleanup order. Now clears old parent's tracking before updating parent ID
- Stale entry prevention: Only tracks tasks that are actually running; actively cleans up completed tasks
- Renamed registerExternalTask → trackTask: Clearer name (the old name implied external API consumers, but it's internal)
Update BackgroundManager to rename the method for tracking external tasks, improving clarity and consistency in task management. Adjust related tests to reflect the new method name.
Previously, continuation hooks (todo-continuation, boulder-continuation, ralph-loop)
and background tasks resolved model info from filesystem cache, which could be stale
or missing. This caused session.prompt to fallback to default model (Sonnet) instead
of using the originally configured model (e.g., Opus).
Now all session.prompt calls first try API (session.messages) to get current model
info, with filesystem as fallback if API fails.
Affected files:
- todo-continuation-enforcer.ts
- sisyphus-orchestrator/index.ts
- ralph-loop/index.ts
- background-agent/manager.ts
- sisyphus-task/tools.ts
- hook-message-injector/index.ts (export ToolPermission type)