Skip to content

verify --preview routes init to the repo root on monorepos, producing an unusable manifest #363

Closed

Description

@pengfei-threemoonslab

Summary

verify --preview routes the user to run init at the workspace root. In a monorepo this produces an unusable manifest, and the information needed to pick the right directory (changed_files) is already in the preview payload.

Evidence (reproduced 2026-08-10, CLI 0.16.0b7)

Preview on google/adk-samples PR #1917 returned:

"next_action": {"kind": "initialize",
  "command": "shipgate init --workspace /…/adk-samples --write --json"}

Following it verbatim produced:

  • shipgate.yaml: 797 lines, 252 tool_sources — every ADK-looking file in the repo, including non-agent files such as python/agents/RAG/deployment/run.py and eval/test_eval.py
  • agent.name: "ask_rag_agent" — auto-filled from the first of 160+ Agent(name=…) literals; unrelated to the PR under review
  • framework detection score: 752.0 (vs 5.0 for the correct subdirectory)
  • M .gitignore — the managed block was appended to the repo's tracked root .gitignore, adding an unrelated modification to the PR's diff

Running init in python/agents/crypto-payroll-agent/ instead produced a 30-line manifest, one tool_source, agent_name_candidates: [{"value": "crypto-payroll-agent", "source": "workspace_dir"}], and a self-contained new .gitignore.

Measured cost of the wrong scope: root-scoped verify takes ~4 min (whole head tree is archived) vs ~5 s for the subdirectory scan. The PR's 4 CRITICAL findings would also be diluted among findings from ~160 unrelated agents, and the alignment layer (agent.name / declared_purpose vs observed capability) is meaningless when one manifest covers 160 agents.

Impact

This is the first instruction a new adopter receives, and the tool's own routing is what produces the bad outcome. The user cannot tell that the result is wrong — the JSON reports manifest_status: "written", is_agent_project: true, confidence: "high", and a higher detection score. A coding agent has no signal at all that it has just been misconfigured.

Proposal

  1. When changed_files is available, derive the suggested --workspace from the deepest common ancestor of the changed paths that contains a project marker (pyproject.toml, package.json, go.mod, …). For this PR that yields python/agents/crypto-payroll-agent.
  2. When init detects multiple root-agent candidates (>1 distinct Agent(name=…) literal across disjoint project markers), do not silently pick the first. Report agent_scope: "ambiguous" with the candidate project directories and route the user to choose.
  3. Never append the managed .gitignore block to a tracked file outside the resolved manifest directory without an explicit opt-in.

Before / After

Before: "command": "shipgate init --workspace /…/adk-samples --write --json"

After:

"command": "shipgate init --workspace /…/adk-samples/python/agents/crypto-payroll-agent --write --json",
"why": "The changed files share one project root; a repo-root manifest would cover 160+ unrelated agents."

Acceptance criteria

  • Preview on the repro suggests the crypto-payroll-agent directory.
  • init --workspace . at the repo root with >1 candidate project reports ambiguity instead of writing a 252-source manifest with an arbitrary agent.name.
  • The single-agent repo case (samples/google_adk_agent) is unchanged (golden test).
  • Root .gitignore is not modified when the resolved manifest directory is a subdirectory.

Scope / non-goals

Not a monorepo/multi-manifest feature — one manifest per run stays the model. This only changes which directory we suggest, and refuses to guess when the answer is ambiguous.

Headline metric

First-adoption success rate on multi-agent repositories (currently 0% unguided — the routed command yields a manifest naming the wrong agent). No new command or schema field; changes a computed next_action value plus one new init refusal path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Picked up inside the current milestone window; keep about 15 openarea:initinit / detect / manifest generationbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions