Skip to content

[Bug]: Systematic build_exec_args() audit — CLI dispatch flags unverified for 11+ integrations #2416

Open

Description

@markuswondrak

Scope extends beyond opencode — systematic build_exec_args() audit

While investigating the opencode dispatch bug, I audited all 28 integrations and found that the root cause is not specific to opencode — it's a systematic architectural weakness in how build_exec_args() is inherited.

Current state

Only 4 out of 15 CLI-capable integrations have verified, correct build_exec_args() implementations:

Integration Base class CLI invocation Status
Claude SkillsIntegration claude -p "prompt" --model X --output-format json ✅ Verified (-p is documented)
Gemini TomlIntegration gemini -p "prompt" -m X --output-format json ✅ Verified (-p and -m are documented)
Codex SkillsIntegration codex exec "prompt" --model X --json ✅ Custom override with exec subcommand
Copilot IntegrationBase copilot -p "prompt" --agent X --yolo --model X --output-format json ✅ Custom override with dynamic --yolo

The remaining 11 integrations with requires_cli: True all inherit build_exec_args() from their base class without verification that the CLI actually supports the generated flags:

Integration Inherited invocation Risk
OpenCode opencode -p "prompt" --model X --output-format json ❌ Confirmed broken — should be opencode run "prompt" -m X
Amp amp -p "prompt" --model X --output-format json ⚠️ Unverified
Auggie auggie -p "prompt" --model X --output-format json ⚠️ Unverified
CodeBuddy codebuddy -p "prompt" --model X --output-format json ⚠️ Unverified
Forge forge -p "prompt" --model X --output-format json ⚠️ Unverified
iFlow iflow -p "prompt" --model X --output-format json ⚠️ Unverified
Junie junie -p "prompt" --model X --output-format json ⚠️ Unverified
Kiro CLI kiro-cli -p "prompt" --model X --output-format json ⚠️ Unverified
Pi pi -p "prompt" --model X --output-format json ⚠️ Unverified
QoderCLI qodercli -p "prompt" --model X --output-format json ⚠️ Unverified
Qwen qwen -p "prompt" --model X --output-format json ⚠️ Unverified

Additionally, 3 SkillsIntegration-based CLIs (Kimi, Shai, Vibe) and 1 TomlIntegration-based CLI (Tabnine) inherit the same -p pattern without verification.

There's also a data inconsistency: Goose has requires_cli: True but inherits from YamlIntegration, which doesn't override build_exec_args() — so it returns None, meaning CLI dispatch silently fails despite claiming CLI support.

Root cause

MarkdownIntegration.build_exec_args() hardcodes three assumptions that don't hold for all CLIs:

  1. Prompt mechanism: -p flag (works for Claude/Gemini) vs. run/exec subcommand (opencode/codex) vs. other formats
  2. Model flag: --model long form (most) vs. -m short form (Gemini, opencode) vs. not supported
  3. JSON output: --output-format json (most) vs. --json (Codex) vs. -f json (opencode) vs. not supported

Every deviation requires a full method override, which is easy to forget (as the opencode bug shows).

Proposed fix: Declarative batch-mode attributes

Instead of requiring each integration to override build_exec_args(), introduce class-level attributes on IntegrationBase that make the common variations declarative:

class IntegrationBase(ABC):
    exec_mode: str = "flag"           # "flag" | "subcommand" | "none"
    exec_prompt_flag: str = "-p"      # flag used when exec_mode="flag"
    exec_subcommand: str = ""          # subcommand when exec_mode="subcommand"
    exec_model_flag: str = "--model"   # "--model" or "-m"
    exec_json_args: tuple[str, ...] = ("--output-format", "json")  # or ("--json",) or ()

Then build_exec_args() on IntegrationBase uses these attributes, and most integrations need zero method overrides:

# OpencodeIntegration — just attributes, no method override
class OpencodeIntegration(MarkdownIntegration):
    key = "opencode"
    exec_mode = "subcommand"
    exec_subcommand = "run"
    exec_model_flag = "-m"
    exec_json_args = ()
    ...

# CodexIntegration — just attributes, no method override
class CodexIntegration(SkillsIntegration):
    key = "codex"
    exec_mode = "subcommand"
    exec_subcommand = "exec"
    exec_json_args = ("--json",)
    ...

Complex cases like Copilot (dynamic --yolo flag) still override build_exec_args() directly.

This makes CLI invocation patterns visible at a glance in the integration class, eliminates an entire class of bugs, and reduces boilerplate from ~15 lines per override to ~4 lines of attributes.


Originally posted as a comment on #2409

Activity

  1. github-actions commented on Sep 11, 2026

    @github-actions
    Contributor

    This issue has been automatically marked as stale because it has not had any activity for 60 days. It will be closed in 30 days if no further activity occurs.

  2. markuswondrak commented on Sep 11, 2026

    @markuswondrak
    ContributorAuthor

    @mnriem — before the stale bot closes this in ~30 days: is this still worth pursuing?

    Status since filing: opencode (#2409) and goose (#3781) were fixed as one-off
    overrides. But 13 integrations with requires_cli: True still inherit the
    unverified -p / --model / --output-format json pattern (amp, auggie, codebuddy,
    forge, junie, kiro-cli, pi, qodercli, qwen, kimi, shai, vibe, tabnine), and new
    instances keep appearing — agy (#4480) is broken despite having an override,
    and Bob (#4491) can't dispatch at all.

    Fix sketch: make CLI dispatch declarative on IntegrationBase instead of
    per-class method overrides:

    exec_mode = "flag"            # "flag" | "subcommand" | "none"
    exec_prompt_flag = "-p"
    exec_subcommand = ""
    exec_model_flag = "--model"
    exec_json_args = ("--output-format", "json")

    Deviations become visible at a glance and most integrations need zero overrides.
    #2424 already implements this — I'd be happy to rebase/revive it if there's interest.

    Would you prefer the declarative approach or should we keep fixing integrations
    one by one?

    AI disclosure: this comment was drafted with AI assistance and reviewed by me.

  3. mnriem commented on Sep 14, 2026

    @mnriem
    Collaborator

    Thanks @markuswondrak for the audit and for following up. For now, I’d prefer to continue with focused, evidence-backed integration fixes rather than undertake a blanket audit or revive the declarative-dispatch refactor.

    We should address the concrete reports already open—agy, Bob, and Amp each have proposed fixes. For the remaining unverified integrations, we’ll assess issues or PRs when someone encounters and demonstrates a problem. “Unverified” does not necessarily mean broken, and moving the settings into declarative attributes would still require verifying the actual CLI behavior.

    Please don’t spend more time rebasing the broader refactor solely for this request. If subsequent fixes demonstrate a shared defect that genuinely needs a common architectural change, we can revisit it with that evidence.

    The audit remains useful context for those future reports; we’re just not committing to completing the whole matrix now.

    Drafted for @mnriem by GitHub Copilot (model: GPT-6 Astra).

  4. added
    triage-nice-to-haveVerdict: evidence-backed fix or greenlit feature — land after review
    on Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    triage-nice-to-haveVerdict: evidence-backed fix or greenlit feature — land after review

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions