Skip to content

bug(adapters): continueagent and devin missing UninstallHooks/AreHooksInstalled — orphaned hooks persist after session cleanup #271

@fireddd

Description

@fireddd

Bug

The continueagent and devin agent adapters delegate GetAgentHooks to the claude-code adapter (writing hooks into .claude/settings.local.json), but neither implements UninstallHooks or AreHooksInstalled. The grok adapter uses the same delegation pattern and correctly implements both methods. Without them, installed hooks are never cleaned up — they remain in the workspace as orphaned AO hook commands that fire after AO stops managing the session.

Analyzed against: 96d1649 (current main)
Confidence: High — compared continueagent, devin, and grok adapters side-by-side.

Root Cause

continueagent (backend/internal/adapters/agent/continueagent/continueagent.go):

  • Has GetAgentHooks at line ~117, delegating to claudecode.Plugin{}
  • Missing UninstallHooks and AreHooksInstalled

devin (backend/internal/adapters/agent/devin/devin.go):

  • Has GetAgentHooks at line ~125, delegating to claudecode.Plugin{}
  • Missing UninstallHooks and AreHooksInstalled

grok (correct reference implementation, backend/internal/adapters/agent/grok/grok.go):

  • Has GetAgentHooks at line ~109
  • Has UninstallHooks at line ~119 — delegates to claudecode.Plugin{}
  • Has AreHooksInstalled at line ~127 — delegates to claudecode.Plugin{}

The framework invokes UninstallHooks and AreHooksInstalled via type assertion on the agent adapter. When the assertion fails (for continueagent/devin), the call is silently skipped.

Reproduction

  1. Start a session with the continueagent or devin adapter
  2. AO installs hooks in .claude/settings.local.json via GetAgentHooks
  3. Kill or cleanup the session
  4. Check .claude/settings.local.json in the workspace — AO hooks persist
  5. If the workspace is reused (e.g., session restore or new session on same branch), the orphaned hooks fire ao hooks commands that may interfere with the new session

Impact

  • Orphaned hooks in workspace after session cleanup
  • Hooks fire for the wrong session context on workspace reuse
  • Only affects continueagent and devin adapters

Suggested Fix

Add UninstallHooks and AreHooksInstalled to both adapters, delegating to claudecode.Plugin{} just like grok does:

func (p *Plugin) UninstallHooks(ctx context.Context, inv ports.AgentInvocation) error {
    return (&claudecode.Plugin{}).UninstallHooks(ctx, inv)
}

func (p *Plugin) AreHooksInstalled(ctx context.Context, inv ports.AgentInvocation) (bool, error) {
    return (&claudecode.Plugin{}).AreHooksInstalled(ctx, inv)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions