Skip to content

feat: submodule support in IDD config — let parent config route submodule operations #162

@kiki830621

Description

@kiki830621

Problem

Original suggestion (verbatim):
「我在想 idd 要能夠支持 submodule 的設定,可能最上層的 idd 設定可以用來調整 submodule 吧?」

When working inside a git submodule, IDD's walked-up config resolution (Step 0.5.B) finds the parent repo's .claude/issue-driven-dev.local.json and uses its github_repo field — which targets the parent repo, not the submodule. The submodule's own GitHub remote is silently ignored.

The user is asking for: the topmost (parent) IDD config could declare per-submodule routing, so a single parent config drives both parent-repo issues and submodule-repo issues without the user having to maintain a separate config file inside each submodule.

Type

feature / enhancement (config-protocol)

Concrete pain point (encountered 2026-05-26)

Setup:

  • Parent repo: PsychQuant/IRT_variacne_bootstrapping_estimtor (code + sims)
  • Submodule at manuscript/parametric_bootstrapping_se/ → remote kiki830621/PB-of-IRT-ability (manuscript)
  • Parent config: article2_standard_error/.claude/issue-driven-dev.local.json"github_repo": "PsychQuant/IRT_variacne_bootstrapping_estimtor"

Sequence:

  1. cd manuscript/parametric_bootstrapping_se/05xx-2026/ (inside submodule)
  2. /idd-issue ... for a manuscript-content change
  3. Step 0.5.B walks up, hits parent config → GITHUB_REPO = PsychQuant/IRT_variacne_bootstrapping_estimtor (WRONG — should be kiki830621/PB-of-IRT-ability)
  4. The submodule's own git remote get-url origin (which would derive the correct target) is ignored because Step 0.5.B's walked-up config wins over derivation
  5. Workaround: manually create manuscript/parametric_bootstrapping_se/.claude/issue-driven-dev.local.json with "github_repo": "kiki830621/PB-of-IRT-ability"

Same friction applies to idd-diagnose / idd-implement / idd-verify / idd-close — every IDD skill walking-up from submodule cwd hits the wrong parent config.

Expected

A parent IDD config should be able to declare per-submodule routing in one of these forms (proposing two designs, not mutually exclusive):

Option A — Reuse existing candidates + path predicates (documentation pattern)

The candidates mechanism + path_contains predicate already handles this case; it's a discoverability gap, not a missing feature. Document the pattern explicitly:

{
  "github_repo": "PsychQuant/IRT_variacne_bootstrapping_estimtor",
  "candidates": [
    {
      "label": "Manuscript submodule",
      "github_repo": "kiki830621/PB-of-IRT-ability",
      "when": { "path_contains": "manuscript/parametric_bootstrapping_se" }
    }
  ]
}

Step 0.5.C predicate pre-resolve already picks the candidate when cwd matches the path. The friction is that users (incl. me today) don't know this pattern handles submodules — README and CLAUDE.md call candidates "monorepo sub-package" routing, not "submodule" routing. Fix could be docs-only.

Option B — Native submodule awareness (submodules field in config schema)

Add a first-class field that consumes the parent repo's .gitmodules and auto-routes:

{
  "github_repo": "PsychQuant/IRT_variacne_bootstrapping_estimtor",
  "submodules": {
    "manuscript/parametric_bootstrapping_se": {
      "github_repo": "kiki830621/PB-of-IRT-ability",
      "attachments_release": "attachments"
    }
  }
}

Or with auto-derive (parse .gitmodules, use submodule's git remote get-url origin):

{
  "github_repo": "PsychQuant/IRT_variacne_bootstrapping_estimtor",
  "submodules": "auto"
}

Resolution algorithm: Step 0.5 checks if cwd is inside a registered submodule path → use submodule's mapped github_repo; otherwise fall through to parent's github_repo. The submodule's .claude/ directory does NOT need its own config.

Actual (current behaviour)

The fallback chain in Step 0.5 (config-protocol six mechanisms):

  1. --target flag (per-invocation override) — works but heavyweight
  2. ask_each_time menu — only fires if config has candidates / groups
  3. Predicate pre-resolve — works if candidates are set up (user has to know)
  4. Cascading config (walk up) — finds parent config, uses parent's github_repo (silent wrong target)
  5. git remote fallback — never reached because step 4 already resolved
  6. Groups — orthogonal, doesn't help

Submodule users currently must either (a) pass --target ... every invocation, (b) set up candidates manually, or (c) duplicate config inside the submodule. None is discoverable from the failure mode (silent wrong-target).

Impact

  • Affects any user with git subtree/git submodule workflow (e.g. manuscript + code projects, Overleaf-synced manuscripts, multi-repo monorepos)
  • Particularly painful when the submodule's GitHub remote differs from parent's owner (cross-org submodules)
  • Silent failure mode: target goes to wrong repo, user only notices after issue is filed in wrong place

Proposed scope (please confirm)

  • Docs (Option A): README + CLAUDE.md section "Submodule support" showing candidates + path_contains pattern. Probably 1 commit, zero code changes.
  • Native (Option B): submodules field in config schema + Step 0.5 resolution algorithm update + tests + docs. Larger; depends on whether maintainer prefers extending schema vs steering users to candidates.
  • Fallback safety net: if Step 0.5.B's walked-up config exists but cwd is inside an UNregistered submodule (not in candidates, not in submodules), emit a warning citing the parent target + suggesting the candidates/submodules pattern — instead of silent wrong-target.

Related

  • config-protocol.md Step 0.5 six-mechanism resolution (this issue proposes extension to mechanism 4)
  • candidates + path_contains (existing, under-documented for submodule case)
  • Pain point context: today's session converted manuscript/parametric_bootstrapping_se/ from git subtreegit submodule (per parent repo CLAUDE.md update 2026-05-26). The mode switch surfaced this gap.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    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