fix: accept cwd alias in SessionStart hook + fix doctor false-positive warnings#72
Conversation
**Bug 1: SessionStart hook ignores Claude Code payloads (sessions table stays empty)** Claude Code sends `"cwd"` as the working directory field in SessionStart hook payloads. The HookInput struct only accepted `"workingDirectory"` and `"working_directory"`, causing serde deserialization to fail silently with `[omni] parse error`. As a result, no sessions were ever written to the DB, `omni doctor` always reported 0 records, and session context injection (hot files, previous errors) never worked. Fix: add `#[serde(alias = "cwd")]` to the `working_directory` field. Adds regression test `test_claude_code_cwd_alias_accepted` with the actual Claude Code hook payload format (snake_case fields + cwd). **Bug 2: omni doctor always shows ATTENTION NEEDED (false positive)** All 11 optional agent integrations (Cursor, Zed, Cline, Roo Code, Copilot, Gemini, OpenCode, Codex, OpenClaw, Antigravity, VS Code) returned false from doctor_check() when not configured. Since all_ok is AND-ed with every agent result, any non-Claude-Code agent not installed caused the doctor to report ATTENTION NEEDED even when everything was working correctly. Fix: return true (not an error) when an optional agent is simply not configured. Only a broken/partial configuration should indicate failure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fajarhide
left a comment
There was a problem hiding this comment.
Hi @tomraider4720, thank you so much for this PR and for catching these two critical issues!
Bug 1 (cwd alias): Spot on! This is a great catch and the fix with #[serde(alias = "cwd")] is perfect.
Bug 2 (Doctor False Positive): You are absolutely right about the root cause (the all_ok &= ... logic causing false positives if optional agents aren't configured). However, changing all 11 agents to return true when they are not configured isn't the ideal architectural fix, as the return value of doctor_check() is supposed to accurately represent whether the agent is successfully configured or not.
Instead of changing all the agents, the better fix is to update the logic in src/cli/doctor.rs to not require every agent to be true. We just need at least one agent to be configured:
let mut any_agent_ok = false;
for agent in integrations {
if agent.doctor_check(fix_mode, &mut warnings) {
any_agent_ok = true;
}
}
if !any_agent_ok {
all_ok = false;
// maybe push a warning
}Would you be open to updating this PR to revert the agent files and apply the fix to doctor.rs instead? Let me know, or I can also merge the cwd fix first and handle the doctor logic in a separate commit. Thanks again!
|
Thanks for the detailed review! Totally agree on the architectural feedback for Bug 2. Would you be happy to merge the |
Well noted. i'll to merge the bug 1. Thanks to contribute! |
fajarhide
left a comment
There was a problem hiding this comment.
rollback true to false and merged fixed bug 1 accept cwd.
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Signed-off-by: Fajar Hidayat <fajarhide@gmail.com>
Summary
Two bugs fixed that together caused
omni doctorto always show⚠ ATTENTION NEEDEDand prevented session tracking from working with Claude Code.Bug 1: SessionStart hook silently fails with Claude Code payloads
Claude Code sends
"cwd"as the working directory field in SessionStart hook payloads. TheHookInputstruct insession_start.rsonly accepted"workingDirectory"and"working_directory", soserde_json::from_strfailed on every real Claude Code invocation, printing[omni] parse errorand returning early — before thestore.upsert_session()call on line 151.Result: The
sessionstable stayed permanently empty.omni doctorreported0 recordsandLast session: none. Session context injection (hot files, previous errors at SessionStart) never worked.Fix: Add
#[serde(alias = "cwd")]to theworking_directoryfield.Verified by inspecting actual Claude Code hook transcripts in
~/.omni/transcripts/which confirmed the"cwd"field name, and by a new regression testtest_claude_code_cwd_alias_acceptedusing the real payload format.Bug 2: Optional agents return
falsewhen not configured → spurious ATTENTION NEEDEDAll 11 optional agent integrations (Cursor, Zed, Cline, Roo Code, Copilot, Gemini, OpenCode, Codex, OpenClaw, Antigravity, VS Code) returned
falsefromdoctor_check()when simply not configured. Indoctor.rs,all_okis AND-ed with every agent's result:This means any system that only uses Claude Code (the most common case) would always have
all_ok = falseand see⚠ ATTENTION NEEDED— even with a perfectly healthy installation.Fix: Return
truewhen an optional agent is not configured. Only a broken or partial configuration (e.g. config file exists but"omni"is missing) would be a real problem.Test plan
omni doctorshows✓ ALL OKon a system with only Claude Code configuredSessionStarthook creates a session record in the DB when Claude Code sends its standard payloadcargo testpasses (all 46 tests, including newtest_claude_code_cwd_alias_accepted)test_continue_session_inject_summarystill passes (session continuation unaffected)🤖 Generated with Claude Code
PR Auto Describe
Summary
Added support for the
cwdalias in SessionStart payloads to accommodate Claude Code’s output format. Updated tests to verify correct parsing, persistence, and that no parse errors arise whencwdis supplied.Key Changes
HookInputnow acceptscwdas an alias forworking_directory.test_claude_code_cwd_alias_acceptedensures:cwdparse successfully.None) is produced for a fresh session without a toolchain.Detailed Breakdown
#[serde(alias = "cwd")]toworking_directoryfield.renameandaliasforworkingDirectoryandworking_directoryintact.cwd.process_payloadand expectsNone(no watch paths).store.find_latest_session().cwddoes not trigger a parse error or prevent persistence.Notes
cwd) and snake_case usage, mirroring real Claude Code transcripts.Last updated: 2026-05-03 10:53:12