Repository navigation
Conversation
…ing (TH-8294) Cascade hook recipe for Devin Desktop on the shared hook-to-OTLP emitter (decision N-10: Cascade only, Devin Local is a follow-up): - adapters/devin_desktop.py maps the documented Cascade hooks (https://docs.devin.ai/desktop/cascade/hooks): trajectory_id is the session, execution_id the turn (pre_user_prompt opens it, post_cascade_response closes it), post_read_code / post_write_code / post_run_command / post_mcp_tool_use become tool spans. model_name is kept as a display label. Other pre-hooks, post_setup_worktree and post_cascade_response_with_transcript are not mapped; transcript paths are never opened. - Contract tests on doc-shaped payloads, including a transcript canary and a hosted-Devin insights payload that must not map. - examples/coding-agents/devin-desktop: user-level ~/.codeium/windsurf/hooks.json, install.sh, run_e2e.sh (runs the hooks.json commands through bash -c, as Devin Desktop does). - Page integrations/coding-agents/devin-desktop and its nav entry. Co-Authored-By: Claude Opus 5.5 <[email protected]>
… (TH-8294) With b88b852 a Cascade turn whose post_cascade_response never arrives is closed as incomplete when the next pre_user_prompt opens a turn, so its tool spans keep their parent. Document that on the page and in the adapter, and test it (no orphan spans, turn marked incomplete). Co-Authored-By: Claude Opus 5.5 <[email protected]>
nik13
force-pushed
the
feat/th-8294-devin-desktop
branch
from
October 15, 2026 02:50
8b386c5 to
9a37d58
Compare
- hooks.json and the page now use the canonical guarded command `python3 -B ".../emit.py" devin_desktop <event> 2>/dev/null || true`: python3 exits 2 when the emitter file is missing, and Cascade treats exit 2 from pre_user_prompt as "block". New test runs every shipped command via bash -c with no emitter and with no python3 (exit 0, empty stdout), and after install.sh against a loopback receiver. - respond() prints nothing (Cascade decides on the exit code). - post_run_command spans keep status unset (no exit code in the hook); read/write/MCP post-hooks fire after a successful action and stay OK. - pre_user_prompt also sends a SESSION UPDATE so the core sweeps state of old conversations (Cascade has no session-end hook); tested. - The command's cwd is no longer part of captured tool input; drop the attributes that duplicated coding_agent.hook.event / coding_agent.turn.id. - Page: Uninstall section, platform row, "may not" inherit the shell env (shell FI_* wins over the env file), troubleshooting without show_output, captured-content paths stated, transcript hook named as the excluded turn-end hook, test that the page JSON equals hooks.json. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…vin-desktop Co-Authored-By: Claude Opus 5.5 <[email protected]>
…acy page truth (TH-8294) - hooks.json and the page use the subshell form `(python3 -B ".../emit.py" devin_desktop <event> 2>/dev/null || true)`. Without the parentheses a host that passes the payload as a trailing heredoc binds it to `true` and the emitter reads nothing. - test_devin_desktop_hooks_config runs every shipped command through /bin/sh and bash, with the payload on stdin and as a trailing heredoc: emitter missing and python3 missing exit 0 with empty stdout; after install.sh each hook exits 0, prints nothing and exports its span. The un-parenthesised form fails the heredoc case. - New adapter test: an MCP error and a command naming a home path with a user name are absent by default; with content on the path is kept with <user> and the cwd is never captured. Opt-in fixture paths are scrubbed. - Page: state file holds only open/incomplete turn content (core 6513a26), opted-in paths carry <user>, why pre_user_prompt is registered (exit 0 is "proceeds normally"), dashboard hooks run first. - run_e2e.sh writes no bytecode. Co-Authored-By: Claude Opus 5.5 <[email protected]>
nik13
added a commit
that referenced
this pull request
Oct 15, 2026
…#921 (TH-8293) The two Devin Desktop mentions said a Future AGI recipe was "in progress and not published yet", which becomes false once docs#921 adds /docs/integrations/coding-agents/devin-desktop. They now say tracing Devin Desktop is a separate setup that this page does not describe, with no link (the Desktop page is not on this branch, so a link would fail the link audit here). test_page.py: the Desktop check no longer requires a link when the Desktop page exists. It forbids stale "not published" / "in progress" claims and a support claim in both trees, forbids the link while the Desktop page is absent, and accepts either the neutral pointer or a link once it exists. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…vin-desktop Co-Authored-By: Claude Opus 5.5 <[email protected]>
… from recheck (TH-8294) Page: - Troubleshooting step 1: "no lines" also means the emitter found no keys (env file missing or misnamed, keys only in the shell) or FI_HOOK_DISABLED=1; the turn start alone never logs. - Troubleshooting step 2: the manual run sends one test trace (session fi-hook-test, one read_code span); prefix FI_HOOK_DISABLED=1 to check the emitter without sending. FI_HOOK_DUMP_FILE is not offered because it does not stop the send. - Common fields are on every tool and turn span; the Cascade session span has no turn id and carries the model as llm.model_name. - The 24 h state sweep runs at the next prompt; Uninstall now deletes the state directory and, if unused, ~/.config/fi-hook-to-otlp/env. - install.sh prints the same uninstall steps. Tests: the page's manual-run command (disabled: nothing sent, logged or written; enabled: exactly that test trace, one http=200 line), no keys or FI_HOOK_DISABLED=1 log nothing, the page's Uninstall block removes the emitter, the TMPDIR state dir and the env file, and common fields are on tool and turn spans but not on the session root. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…tatus (TH-8294) Co-Authored-By: Claude Opus 5.5 <[email protected]>
nik13
marked this pull request as ready for review
October 21, 2026 22:59
Co-Authored-By: Claude Code <[email protected]>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TH-8294, decision N-10: Cascade hook recipe only. Adds a
devin_desktopadapter for the shared hook-to-OTLP emitter (#912), a user-level~/.codeium/windsurf/hooks.json, an installer, and the pageintegrations/coding-agents/devin-desktopplus its nav entry (after// coding-agents:devin-desktop).pre_user_prompt(turn start),post_read_code,post_write_code,post_run_command,post_mcp_tool_use,post_cascade_response(turn end).show_output: false.(python3 -B "$HOME/.codeium/windsurf/fi-hook-to-otlp/emit.py" devin_desktop <event> 2>/dev/null || true). Cascade runscommandviabash -cwith the event on stdin and treats exit 2 from a pre-hook as "block";python3exits 2 when the script is missing. The guard makes every hook exit 0 with empty stdout even when the emitter orpython3is missing, sopre_user_promptnever blocks. Exit 0 is documented as "action proceeds normally".post_setup_worktree, andpost_cascade_response_with_transcript. Transcript paths are never opened (tested with a canary and spies onopen,io.openandos.open).model_nameis kept asllm.model_nameanddevin_desktop.model_label, documented as a display label, not a stable id ("Unknown" dropped).post_run_commandspans keep status unset (the hook has no exit code). Read, write and MCP post-hooks fire after a successful action and are OK.pre_user_promptalso sends a SESSION UPDATE (exports nothing) so the core sweeps state files of old conversations after 24 h (tested).Deliberate deviation from PRD R-03 / journey 1:
post_cascade_responseis registered. R-03 and journey 1 say it is not. It is Cascade's only usable turn-end hook: the other one,post_cascade_response_with_transcript, writes the whole conversation to disk and is never registered. The PRD's own outcome (oneexecution_idturn span) needs a turn end; without the hook, turns close only as incomplete at the next prompt and the last turn of a conversation is never exported. With content capture off the emitter never exports theresponsemarkdown it receives on stdin, so R-03's boundary ("response markdown absent") holds. Re-probed at this head: the response marker is 0 in the OTLP bodies, the stored spans and the state files.Vendor update since the PRD: Devin Local now has a first-party hooks page (https://docs.devin.ai/cli/extensibility/hooks/lifecycle-hooks, shared with Devin CLI). The N-10 follow-up is unblocked; this PR stays Cascade-only.
Review fixes (2026-10-15)
test_devin_desktop_hooks_configruns every shipped command through/bin/shandbash, with the payload on stdin and as a trailing heredoc: emitter missing andpython3missing give exit 0 and empty stdout; afterinstall.sheach hook exits 0, prints nothing and exports its span. The un-parenthesised... || trueform fails the heredoc case (checked). The page's JSON block is tested to equal hooks.json.cwdis no longer captured; a test puts a path with a user name in an MCP error and a command line and asserts it is absent by default, and kept as/Users/<user>/...with content on.devin_desktop.action/devin_desktop.execution_id(duplicatedcoding_agent.hook.event/coding_agent.turn.id).FI_*wins over the env file, troubleshooting viaFI_HOOK_LOG_FILEinstead ofshow_output, dropped the unsourced "failing system hook" claim, transcript hook named as the excluded turn-end hook, opt-in path and state-file wording matched to the core, common fields stated once under the capture table,**Term**:style.Recheck fixes (2026-10-15, round 2)
FI_HOOK_DISABLED=1, and says the turn start alone never logs.fi-hook-test, oneread_codespan) and offers aFI_HOOK_DISABLED=1prefix to check the emitter without sending.FI_HOOK_DUMP_FILEis not offered: it is written in the send path and does not stop the send.Cascade sessionspan has no turn id and carries the model asllm.model_name(matches the stored spans).${TMPDIR:-/tmp}/fi-hook-to-otlp-$(id -u)/devin_desktop) and, if no other app uses it,~/.config/fi-hook-to-otlp/env; install.sh prints the same steps.http=200line), no keys orFI_HOOK_DISABLED=1log nothing, the page's Uninstall block removes the emitter, the TMPDIR state dir and the env file, and the common fields are on tool and turn spans but not on the session root. Each page-backed test fails when its page line is removed (checked).How to run
E2E evidence
agent_action_name,tool_info,trajectory_id,execution_id,model_name) and the.devin/hooks.json/.windsurf/hooks.jsonpaths. The bundled agent binary contains every Cascade hook name.hooks.jsoncommands exactly as Cascade runs them (bash -c, payload on stdin), into local Future AGI at a0bf68e (core 9c6acd6), projectth8103-coding-devin-desktop-r3.fi_verifyPASS, trace408aeb0b-1cba-02fd-c058-26626a9ccfd3, 8 spans:Cascade session(model Claude Sonnet 4) > turn 1 (read_code,run_command,write_code,list_commits) and turn 2 (run_command). Stored status: read/write/MCP OK,run_commandUNSET. Every hook exited 0; the 7 span-producing hooks loggedhttp=200andpre_user_promptlogged nothing. Earlier run at 653ec9e: trace3cf4a2af.FI_HOOK_CAPTURE_CONTENT=1, projectth8103-coding-devin-desktop-content):fi_verifyPASS, tracef5743450-31c6-5d70-6887-4d918a0e05f9. On core 9c6acd6 the opt-in path scrubbing is covered by the unit tests.npm run buildexit 0,npm run audit-links0 broken content links.Privacy proof
408aeb0b, this head): prompt, tool-input, tool-output and response markers, the transcript and worktree canaries, the local user name, the host name,/Users/,/home/,/tmp/andinput.value/output.valueare all 0 in both the stored spans and the OTLP bodies as sent. The four markers are also 0 in the state files.f5743450): prompt, tool-input and response markers present; the read path is stored as/Users/<user>/project/README.md; the fixture user name, transcript and worktree canaries and the local user name are 0.Verification (2026-10-20)
How others support Devin Desktop/Windsurf: only Cascade hooks are a tracing path (KiroGraph uses
post_cascade_response). Braintrust has an MCP connection only; Arize's harness tracing lists Devin CLI, not Desktop; Langfuse, LangSmith, Datadog, Honeycomb, SigNoz, Laminar, Opik, Helicone, PostHog and AgentOps have no page. Sources are on the page.install.shinto an isolated HOME; installedhooks.jsoncommands run viabash -c, all exit 0, empty stdout. Projectth8103-livefill-th8294, trace7a6a0978-c3cd-0dba-4f92-f77d76132f88(8 spans, 2 turns),fi_verifyPASS. Privacy scan: 0 hits for prompt/command/MCP-arg/response markers,/Users/, user and host name.tool_infoexamples from the Cascade Hooks page (no signed-in Cascade run). Unverified in real Cascade: loading of~/.codeium/windsurf/hooks.json, realpost_mcp_tool_usepayload,post_cascade_responseon cancel, one trace per realtrajectory_id.Not available / limitations
No tokens, cost, model-request spans, tool durations, tool call ids, or command exit codes (not in Cascade hook input). No session start/end hook; the root is re-sent with every span and the next prompt deletes per-conversation state unused for 24 h (Uninstall deletes the rest). If Cascade skips
post_cascade_responsefor a turn (e.g. a cancel), the core closes that turn as incomplete when the next prompt starts, so its tools keep their parent (tested). The last turn of a conversation still needs the hook, since Cascade has no session-end hook. macOS and Linux only; Windows would run the bash-syntaxcommandviapowershell -Commandand is not supported or tested. Devin Local and hosted Devin are not covered.🤖 Generated with Claude Code