Remove non-store tool names from the metadata recovery warning gate so call_omo_agent and dead aliases fail open without warning spam. Keep warnings for tools backed by the recovery store: background_output, edit, and task.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Root cause: tool.execute.after attempted metadata recovery for every tool, including built-in tools that never publish recoverable OMO metadata. On Windows this produced repeated recovery warnings across read/bash/glob/grep/todowrite/lsp/apply_patch and amplified stalled-session diagnostics, while metadata-linked tools still needed diagnostic visibility when their linkage was stale.
Limit the warning to tools expected to publish recoverable metadata and keep all other built-in tools fail-open after missing metadata.
Fixes#4449
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
default-mode (system-transform):
- e5463e2db introduced auto-activation of ultrawork+ralph-loop, and
dc2e082ac then skipped the ultrawork system prompt whenever ralph_loop
was also enabled. Net effect: the keyword-detector still showed
'Default ultrawork mode enabled' to the user, but the first turn had
none of the ultrawork behavior. Loop continuation kept the ultrawork
prefix, so the contract was honored only on later iterations.
- Drop the skip so the initial turn matches what the toast advertises.
New matrix test pins all four (ultrawork, ralph_loop) combinations.
multimodal-looker:
- Prompt claimed 'read' and 'call_omo_agent' were available, but the
look_at invocation runtime explicitly disables both via READ_ENABLED
and createAgentToolAllowlist([]). Small VL models trusted the prompt
and looped on rejected tool calls (#4116).
- Rewrite the agent prompt to describe direct-attachment analysis and
forbid tool/agent calls. Add a consistency test that extracts the
prompt's 'available tools' claim and compares it against the
configured allowlist.
delegate-task (skill-resolver):
- 088693697 filtered per-agent restricted skills at the skill tool and
builtin agent prompt layers, but delegate-task itself happily injected
whatever skill name a caller passed. A target agent could be force-fed
a skill marked agent: oracle just by listing it in load_skills.
- Thread the target agent through resolveSkills and silently filter
skills whose definition.agent does not include it. Public skills with
no restriction are unaffected. Regression test pins the bypass.
notepad-write-guard:
- The hook was created by create-tool-guard-hooks but tool-execute-before
never invoked it, so the guard was inert.
- It also only matched .sisyphus/notepads, missing the current
.omo/notepads layout introduced by the workspace migration.
- Add the dispatch call alongside writeExistingFileGuard, and extend
NOTEPAD_ROOTS to cover both paths via normalize() + sep. New
integration test pins the wire and the .omo block; the existing unit
test now asserts both paths.
start-work session-plan-affinity:
- PLAN_PATH_PATTERN only matched .sisyphus/plans, so sessions referring
to plans under .omo/plans returned null and start-work missed the
current session's own plan.
- Extend the regex to .(sisyphus|omo)/plans and add findPrometheusPlans
in packages/boulder-state to scan both directories during the
transition. New regression test pins .omo/plans matching; legacy
.sisyphus/plans coverage preserved.
The model emits tool names like mcp_background_output but the runtime
registry has them as background_output. While transformToolName already
handles the prefix for display purposes, the tool dispatch path in
tool-execute-before was not stripping it, causing 'unavailable tool' errors.
This adds mcp_ prefix stripping at the earliest point in the tool
execution pipeline, fixing background_output, background_cancel, and
all nocturne-memory_* tools.
Closes#2697
- Strengthen Prometheus plan template with FORMAT constraint
- Add task label format check to Oracle phase-2 (N/6 → N/7)
- Add format checks to self-review checklist
- New plan-format-validator hook: compares raw checkbox count
against getPlanProgress() after plan writes, warns agent when
labels are malformed (0/0 or partial skip scenarios)
Accept apply_patch edits from nested result/metadata file lists and from raw patchText args when OpenCode does not provide direct metadata.files.
Forward tool args through the after-hook pipeline so comment-checker can inspect raw apply_patch inputs while preserving existing write, edit, and multiedit routing.
Tests: bun test src/hooks/comment-checker/hook.apply-patch.test.ts src/hooks/comment-checker/hook.before-after.test.ts src/plugin/tool-execute-after.test.ts
Tests: bun test src/hooks/comment-checker
Tests: bun run typecheck
Tests: bun run build
OpenCode now treats session.status idle as the durable completion boundary, but the plugin only dispatched the synthetic session.idle through the main hook chain. Idle-only side effects such as tmux forwarding and team member idle continuations were skipped.
Route synthetic idle through the same idle-only hook path used by real session.idle events and pin the behavior with a regression test.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
When both default_mode.ultrawork and default_mode.ralph_loop are true,
the ralph loop handles ultrawork behavior via its continuation mechanism
(prepends 'ultrawork' to each iteration prompt). Injecting the ultrawork
system prompt on top would be redundant — the continuation prompt
re-triggers keyword detection, which defeats the purpose of invisible
system prompt injection.
The ultrawork flag still controls loop behavior (500 max iterations +
Oracle verification gate) via chat-message.ts startLoop({ ultrawork }).
When default_mode.ultrawork is enabled, inject the ultrawork behavioral
instructions into the system prompt (experimental.chat.system.transform)
instead of prepending them to the user's visible chat message.
- system-transform.ts: No-op handler now injects ultrawork message into
output.system[] when defaultMode.ultrawork is active. Checks for existing
<ultrawork-mode> tag to avoid re-injection after compaction.
- keyword-detector/hook.ts: Removes the visible text injection
(output.parts[].text prepend) for default_mode.ultrawork path. Only
shows the toast as the user-facing indicator.
- plugin-interface.ts: Wires getUltraworkMessage from keyword-detector
into createSystemTransformHandler.
Result: Ultrawork mode activates silently via system prompt — the chat
stays clean, and only a toast shows 'Ultrawork Mode Active'.
Add new `default_mode` config section with two boolean fields:
- `ultrawork`: Auto-inject ultrawork mode prompt on main session start
without requiring the "ultrawork"/"ulw" keyword. Wired through the
keyword-detector hook — injects once per session, respects existing
guards (non-OMO agents, planner agents, subagent sessions).
- `ralph_loop`: Auto-start ralph loop on first main session message
without requiring /ralph-loop or /ulw-loop commands. When ultrawork
is also enabled, the loop starts in ultrawork mode.
Usage:
```jsonc
{
"default_mode": {
"ultrawork": true, // Always get ultrawork prompt on start
"ralph_loop": true // Auto-start ralph loop
}
}
```
Files: 7 modified/added, ~65 LOC added.
Include Vertex Anthropic in the assistant-tail prefill guard after Cubic flagged the strict provider check. Keep the non-Anthropic opencode negative control covered by tests.
Plan: plans/fix-anthropic-assistant-prefill-tail.md
Tighten the assistant-tail repair after review so only the Anthropic provider is treated as prefill-rejecting, and so assistant-tail model metadata is evaluated independently from the last user model.
Add regression coverage for an allowed user model followed by a rejecting Anthropic assistant tail, plus a non-Anthropic provider carrying a Claude-looking model id.
Plan: plans/fix-anthropic-assistant-prefill-tail.md
Claude Opus 4.7 rejects requests whose final message is an assistant turn, because Anthropic treats that as unsupported assistant prefill. Add a transform guard that appends the existing synthetic user recovery turn only for Anthropic prefill-rejecting model IDs, while preserving assistant-prefill behavior for supported and unknown models.
Tests cover Opus 4.7, Opus 4.6 assistant metadata fallback, direct Sonnet 4.6 model fields, allowed OpenAI/Sonnet 4.5 tails, missing metadata, and compaction continuation compatibility.
Plan: plans/fix-anthropic-assistant-prefill-tail.md
The bundled createTodoDescriptionOverrideHook returns { 'tool.definition': fn }, but plugin-interface.ts never exposes 'tool.definition' as an OpenCode hook handler. Result: the hook is constructed by createToolGuardHooks (line 132-134 of src/plugin/hooks/create-tool-guard-hooks.ts) but the function is never invoked, so todowrite keeps using OpenCode's core 7 KB description instead of the 1.4 KB TODOWRITE_DESCRIPTION. User-defined plugins under ~/.config/opencode/plugin/*.js use the same hook contract and work fine, confirming the contract itself is functional in opencode 1.14.28+.
Fix: add src/plugin/tool-definition.ts (createToolDefinitionHandler) that forwards the OpenCode 'tool.definition' input/output pair into hooks.todoDescriptionOverride. Wire it into plugin-interface.ts alongside tool.execute.before/after.
Regression coverage: src/plugin/tool-definition.test.ts covers (a) todowrite override applied, (b) other tools left untouched, (c) null hook is a no-op.
Address Oracle review feedback: refactor 4 aliased mutations via argsObject
in plugin/tool-execute-before.ts and 1 via toolOutput in atlas/tool-execute-before.ts.
Strengthen audit test regex to catch Output.args mutations regardless of the
variable name prefix (toolOutput, argsObject aliases).
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>