Skip to content

Two harnesses, one repo: the collision is at the root docs and in our unguarded delete — not in the tool directories #516

Description

@BaseInfinity

Maintainer, 2026-08-08: "we should make sure that we never nuke the skills or overwrite files
— like Codex fucks up a file for Claude and vice versa, cuz maybe both write to the same
AGENTS.md file. CLAUDE.md should be isolated and there should be a Codex one too right?"

I scanned both installers before writing this. The premise is right and the specific worry is
mostly already handled — but there are two real problems, and neither is the one named.

What is already safe (do not spend work here)

The two harnesses write to disjoint namespaces:

writes
claude-sdlc-harness (cli/init.js) .claude/settings.json, .claude/hooks/*.sh, .claude/skills/{sdlc,setup,update,feedback}/, CLAUDE_CODE_SDLC_WIZARD.md
codex-sdlc-wizard (install.sh) .codex/hooks.json, .codex/hooks/*, $CODEX_HOME/skills/, AGENTS.md, START-SDLC.md

Neither installer touches the other's directory. Skills in particular are not at risk from the
other tool: ours go to repo-local .claude/skills/, theirs to $CODEX_HOME/skills/ (user
level, not repo level). Both also protect installed files by content hash — ours marks a
changed file PRESERVE unless --force; theirs backs a skill up to
backups/skills/<name>.bak.<epoch> before replacing it.

And AGENTS.md specifically already has the most carefully designed policy of anything either
side does. install.sh distinguishes generated this run / matches the wizard baseline /
wizard-managed / user-owned or customized, and preserves the last. We have no equivalent
for any shared file.

Problem 1 — the repo root is a shared namespace and nobody declared it one

Both harnesses generate documents into the consumer's repo root, under the same filenames,
from different doctrines. codex-sdlc-wizard ships templates/ for AGENTS.md,
SDLC.md, TESTING.md, ARCHITECTURE.md, GOALS.md. Our setup skill generates SDLC.md,
TESTING.md, ARCHITECTURE.md too.

So the collision is not .claude/ vs .codex/. It is TESTING.md — a file both sides believe
they author, whose content encodes each tool's testing doctrine, in a repo where a user may
reasonably run both. Second install wins, or the user is left hand-merging two philosophies.

There is a read-side version of this that is worse, and it is the one worth researching
first: recent Claude Code reads AGENTS.md. If that is true here, a Codex-authored AGENTS.md
is loaded into Claude's context alongside CLAUDE.md — two SDLC doctrines active at once,
free to contradict each other on model/effort guidance, the review protocol, or the merge
policy, with no precedence rule anywhere. Nothing writes over anything; the damage is entirely
in what the agent believes. Verify this against the installed Claude Code version before
designing anything
— the whole shape of the fix depends on the answer.

Problem 2 — our obsolete-path delete has no customization guard, and theirs does

cli/init.js:

const OBSOLETE_PATHS = [ '.claude/skills/testing' ];   // consolidated into /sdlc in v1.17.0
fs.rmSync(fullPath, { recursive: true, force: true });

Recursive, forced, unconditional. No hash check, no backup, no PRESERVE branch — the
protection every installed file gets does not apply to a retired one. A user who wrote
their own .claude/skills/testing/SKILL.md loses it silently on upgrade. Today the list has
one entry, so blast radius is small; the defect is that the mechanism has no guard at all, and
lists grow.

codex-sdlc-wizard/lib/remove-retired-files.cjs solves the same problem properly: hash the
file against a managed-files manifest, and emit Preserved customized retired file or
Preserved retired file still referenced by a retained hook instead of deleting. It also
refuses to proceed when a retained hook still references a retired path.

Their design is better than ours and this is a direct port, not a redesign. Same lesson as
the opencode sweep: when the sibling is a literal port, diffing against it beats a fresh audit.

Research split

  • This repo (done, above): what each installer writes and deletes, where the namespaces
    actually overlap, and which retirement logic is safer.
  • codex-sdlc-wizard (maintainer to run there): the same audit from the other side —
    what it assumes about a repo that already has CLAUDE.md/.claude/, whether its
    AGENTS.md policy anticipates a second harness, and whether $CODEX_HOME/skills being
    user-level rather than repo-level is deliberate.
  • Then consolidate into one shared-surface contract.

Open questions for that contract

  1. Does Claude Code read AGENTS.md at the installed version? If yes, is a shared AGENTS.md
    the feature (one cross-tool standard, as CLAUDE_CODE_SDLC_WIZARD.md already argues) or
    the bug (two doctrines, no precedence)?
  2. Should root docs be namespaced per tool, or shared with per-tool sections and one owner per
    section? Namespacing duplicates facts, which is exactly what this milestone exists to stop.
  3. Should either installer detect the other harness and say so, rather than each behaving
    as if it is alone in the repo? Cheapest real improvement, and it needs no shared format.
  4. Is TESTING.md divergence actually harmful, or do both harnesses say close enough to the
    same thing that one file with two contributors is fine?

Not in scope

Merging the two harnesses, or a shared format spec. Refs #429 (portable sdlc-mcp vs per-host
skills), #433 (Codex CLI parity), #499 (AGENTS.md audit — overlaps, resolve together).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions