Skip to content

Add Devin CLI as a supported coding agent - #873

Open
uhlhosting wants to merge 5 commits into
supabitapp:mainfrom
uhlhosting:feat/devin-agent
Open

uhlhosting wants to merge 5 commits into
supabitapp:mainfrom
uhlhosting:feat/devin-agent

Conversation

@uhlhosting

Copy link
Copy Markdown

Closes #602

Summary

  • Adds devin to SkillAgent (display name "Devin CLI", config dir ~/.config/devin, devin-mark asset) so it appears in the Coding Agents settings panel like every other agent.
  • New DevinSettingsInstaller merges the Supacode hook map into the "hooks" key of ~/.config/devin/config.json, reusing the shared prune-and-replace AgentHookSettingsFileInstaller so user settings and user-authored hooks survive install/uninstall.
  • New DevinHookSettings payload mirrors ClaudeHooksPayload with the deltas documented in the issue: no Notification event, and the PreToolUse awaiting-input matcher uses snake_case tool names (ask_user_question|exit_plan_mode).
  • PermissionRequest (which Devin does support) stands in for Claude's permission Notification: awaiting-input badge plus a fixed notification, since the payload carries no displayable text for the stdin-sourced notify. Stop emits idle and forwards last_assistant_message as the notify body. PostCompaction is deliberately unmapped (fires after compaction, can't drive the compacting badge).
  • Installs both bundled skills (supacode-cli, supacode-deeplinks) under ~/.config/devin/skills/ — Devin's optional SKILL.md frontmatter means the shared markdown works unmodified.
  • Extends the Cmd+V → Ctrl+V native image-paste routing to Devin, which pastes images on the same chord as Claude.
  • Adds devin-mark.svg (from the issue) with template rendering like the other monochrome marks.

Type of change

  • Bug fix (the linked issue is a bug report)
  • Feature (the linked issue is a feature request marked ready)
  • Documentation
  • Other (please describe)

How was this tested?

  • New DevinHookSettingsTests (event coverage, matcher ordering/casing, ownership sentinel, variable allowlist, OSC emit-to-parse round-trip) and DevinSettingsInstallerTests (install/uninstall state, sibling config.json keys and user-authored hooks preserved).
  • SkillAgentTests updated for the new case (display ordering, capabilities, relocatable custom-folder install).
  • GhosttySurfaceViewTests covers the Devin Cmd+V routing.
  • Additionally verified end-to-end on this machine by compiling the integration sources standalone and exercising AgentIntegrationFactory/DevinSettingsInstaller against a temp home: install writes ~/.config/devin/config.json hooks + skills, preserves sibling config keys and user hooks, uninstall removes only managed commands, and every generated hook command parses under sh -n.

Environment note: this checkout was verified with make check (format + lint) and the standalone compile/test above; the full app build needs an Xcode 26.x toolchain, which this machine doesn't have installed.

  • make check passes (format + lint)
  • make test passes
  • I built and ran the app to confirm the change works

AI tool disclosure (optional)

  • Model(s): SWE-2 High
  • Harness / tools: Devin CLI

Checklist

  • This pull request is linked to an issue with Closes # above.
  • For a feature, the linked issue is labeled ready.
  • I am the author of this work and accountable for it; no commit is authored or co-authored by an AI agent.
  • I have read the Contributing guide and the Code of Conduct.

Devin CLI reads hooks from the "hooks" key of ~/.config/devin/config.json
in Claude's shape, minus the Notification event and with snake_case tool
names in matchers. The integration mirrors Claude's: SessionStart /
UserPromptSubmit / PreToolUse drive busy, PostToolUse drives idle, the
ask_user_question|exit_plan_mode PreToolUse matcher drives
awaiting_input, and PermissionRequest stands in for Claude's permission
Notification (awaiting_input plus a fixed notify, since its payload
carries no displayable text). Stop emits idle and forwards
last_assistant_message as the notify body.

Also route Cmd+V image paste to Devin's Ctrl+V chord, the same native
paste translation Claude gets, and install both bundled skills under
~/.config/devin/skills.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

installState compared managed hook commands as a Set<String>, collapsing
identical command strings across slots. Payloads that legitimately reuse
one command — Devin's busy under both UserPromptSubmit and the catch-all
PreToolUse group — then read as installed after a user deleted a single
occurrence, so repair was never offered.

Compare occurrences keyed by (event, matcher, command) as a multiset
instead. The stricter slot-aware compare also catches a managed command
parked under the wrong event and duplicated groups, for every agent on
the shared installer.
@uhlhosting

Copy link
Copy Markdown
Author

Addressed the duplicate-hooks review finding in 167c8ca.

installState() now compares managed hook occurrences keyed by (event, matcher, command) as a multiset instead of a Set<String>. Removing one of the two canonical busy occurrences (UserPromptSubmit / catch-all PreToolUse) — or parking a managed command under the wrong event, or duplicating a group — now reads as .outdated, so Settings offers repair.

The fix lives in the shared AgentHookSettingsFileInstaller, so Claude/Grok/Kimi get the same stricter drift detection. Covered by new cases in AgentHookSettingsFileInstallerTests and DevinSettingsInstallerTests, plus the standalone end-to-end check against a temp home.

installState compared managed hook occurrences as an unordered multiset,
so reordering groups within an event read as installed. Hook groups
execute in array order, and Devin's payload depends on it: the catch-all
PreToolUse busy matcher must precede the ask_user_question|exit_plan_mode
awaiting-input matcher for the later emit to win. Reversed groups left
the badge stuck on busy while Settings showed the integration current.

Compare the ordered sequence of managed groups per event — matcher plus
managed commands in array order — instead. Only managed groups count,
so a user-authored group interleaved between ours still reads installed.
@uhlhosting

Copy link
Copy Markdown
Author

Addressed the reordered-hooks finding in 01eea53.

installState() now compares the ordered sequence of managed groups per event — (matcher, commands) in array order — instead of an unordered occurrence multiset. Reversing Devin's PreToolUse groups (catch-all busy before vs. after the ask_user_question|exit_plan_mode matcher) now reads as .outdated.

The sequence is scoped to managed groups only: a user-authored group interleaved between ours shifts absolute indices but not managed execution order, so it still reports .installed — important because install() appends canonical groups after pre-existing user groups in the same event.

New coverage: reorder → outdated and interleaved user group → installed cases in AgentHookSettingsFileInstallerTests, the reversed-PreToolUse scenario in DevinSettingsInstallerTests, and the same scenarios exercised end-to-end against a temp home.

installState still filtered managed hooks by command string and compared
only matcher + command list, so a change to `type`, `timeout`, or `env`
read as installed. Grok's env passthrough needed a separate additional
closure for that reason.

Change ManagedGroupOccurrence to keep the full managed hook JSONValue
objects in array order. That catches metadata drift alongside command,
occurrence-count, and ordering drift. Grok's env validation is now
handled by the same comparison, so the additionalOutdatedIfInstalled hook
and its closure are removed.
@uhlhosting

Copy link
Copy Markdown
Author

Addressed the hook-metadata drift finding in 6204b5b.

ManagedGroupOccurrence now stores the full managed hook JSONValue objects (not just command strings) in array order. installState() compares (matcher, full hook object) sequences per event, so changes to timeout, type, env, or any other execution-relevant field now read as .outdated. This also subsumes Grok's env-passthrough validation — the separate additionalOutdatedIfInstalled closure and the extra check in GrokSettingsInstaller are removed because the comparison already includes the env map.

New coverage:

  • Timeout change → .outdated and type change → .outdated in AgentHookSettingsFileInstallerTests
  • The existing Grok env-passthrough tests continue to pass via the full-object comparison
  • Smoke harness verifies a Devin timeout: 0 edit reads as outdated

The hook payload assumptions are now explicitly sourced from the local
Devin CLI documentation: event names, hook format, matcher semantics,
per-event stdin fields, Stop's last_assistant_message, and Ctrl+V image
paste. Add a test asserting that the Stop notify body is extracted from
last_assistant_message, matching the documented contract.
@uhlhosting

Copy link
Copy Markdown
Author

Verified the Devin contract assumptions and documented them in 0b89866.

Sources checked against the local Devin CLI stable docs (2026-06):

  • Event names and hook format: extensibility/hooks/overview.mdx
  • Per-event stdin fields: extensibility/hooks/lifecycle-hooks.mdx
  • Stop hooks receive last_assistant_message: changelog/stable.mdx
  • Image paste uses Ctrl+V: reference/keyboard-shortcuts.mdx

The DevinHookSettings comment block now cites those docs and summarizes the deltas from Claude's payload (no Notification, snake_case matcher names, PermissionRequest as the permission prompt stand-in). Added a test asserting the Stop notify body is sourced from last_assistant_message.

Existing tests already cover:

  • Core Devin event names and absence of Notification
  • PreToolUse matcher order ("" before ask_user_question|exit_plan_mode)
  • Every emitted command targets devin, carries the ownership sentinel, parses under sh -n, and round-trips through the OSC presence parser
  • Cmd+V is routed as Ctrl+V for Devin in GhosttySurfaceViewTests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Devin CLI as a supported agent

1 participant