Development record
**Maintainer ruling, 2026-09-11: `ahoy install` must not write abcd by name into
Maintainer ruling, 2026-09-11: ahoy install must not write abcd by name into
a repository it adopts. This record exists to carry that decision to the change
that implements it.
What happens today
ahoy install defaults --docs-target to both
(internal/core/ahoy/detect.go:28), and stepMarker
(internal/core/ahoy/apply.go:866-900) plants
internal/core/ahoy/defaults/claude-md-marker-block.md into the target
repository's committed CLAUDE.md and AGENTS.md. That block opens
"Managed by abcd (Agent-Based Configuration for Development)" and carries a full
"## abcd rule loader" section.
So a default adoption commits abcd's name and its internals into somebody else's repository, and does so in files that repository's contributors read first.
Why it is wrong rather than merely surprising
prepare-this-repo promises the opposite in its own acceptance criteria: "Given
the adoption completes, then nothing from private-names.txt and no
abcd-internal content appears in any committed artefact", reinforced by a
Boundaries claim that the output is nameless and never mentions abcd.
The v0.8.0 release gate caught the contradiction and the prose was corrected to
describe what the code does
(.abcd/development/brief/04-surfaces/15-prepare-this-repo.md). That was the
right move for the record at the time and is now the wrong end to have fixed:
the ruling is that the PROMISE was correct and the BEHAVIOUR should change.
Implementing this therefore reverses that prose correction, deliberately.
It is the same stance as
the-users-directory-is-theirs
and adr-2609091248200336, one level in: a tool does not create directories in
space the user did not hand it, and it does not write its own name into files
the user will commit under their project's history either.
What the change has to settle
- The marker still has to be findable. Detection promotes a folder to
managed-repo on a marker block (
internal/core/ahoy/detect.go:139,strong := registered || markerFired), so whatever replaces the named block must still be recognisable toclassifyand must not silently downgrade every adopted repo to unmanaged. - The rule loader has to keep working. The block is not decoration; it is how a session learns the loader exists. If the committed half goes nameless, the loader's documentation has to live somewhere the adopting project chose.
- The default is the question, not just the text.
--docs-target bothis what makes this the out-of-the-box behaviour. Options include defaulting toskip, keeping the block but stripping the name and the internals, or moving the whole thing under.abcd/where the adopter already accepted a namespace. - Registry-only adoption already exists as the other strong signal, so a nameless install is not a new mechanism, only a different default.
Acceptance
- Given a repository adopted with default options, when the install completes, then no committed file in that repository contains the string "abcd" as a result of the install.
- Given that same repository, when
ahoyclassifies it afterwards, then it still reports managed-repo. - Given the
prepare-this-repoacceptance criterion about nameless output, when the change lands, then the criterion is true of the code and the v0.8.0 prose correction is reversed in the same diff.
Grounds
- pursued: a default adoption leaves the conventions files byte-identical and still classifies managed-repo; shown wrong if a default install plants the block, if an adopted repo reads unmanaged, or if a first install naming a target plants nothing
Frontmatter
| id | iss-2609110944498549 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | major |
.abcd/work/issues/resolved/iss-2609110944498549-ahoy-install-must-not-write-abcd-by-name.md
open on GitHub ↗ · commit history ↗
References1
- itd-2610031348087517Setup asks whether abcd keeps parts of the README current, and whichrelated
mentions7
- adr-2609091248200336A tool never creates directories in user-owned project space; the store's location binds now and its verbs bind when the store ships
- dcn-26092300000000192026-09-23 — The one sanctioned mention of abcd in an adopted repository (product thinker, ruling F of the run A interview, 14:38Z, on iss-2609231103413459). The 2026-09-11 ruling that `ahoy install` must not write abcd by name into a repository it adopts (carried by iss-2609110944498549) covers the name-guard hooks (`.githooks/pre-commit`, `.githooks/pre-merge-commit`) and the `.gitignore` fence, and they are its sanctioned exception: both keep their markers and their naming, documented as the one allowed mention of abcd in an adopted repository, because the hooks run the binary and the fence tells people not to hand-edit it. No rename and no migration: detection classifies an adopted repository by exactly that hook marker and fence, so a rename would have to migrate every repository already adopted. The product thinker ruled the markers, not abcd's record ids: the hook templates' citations of abcd's own records (itd-74, spc-20, itd-150, iss-370, and a path into the design record) resolve to nothing in an adopter's repository, so they are dropped from the templates and a test keeps them out. iss-2609231103413459 closes as wontfix on this ruling.
- dcn-26092300000000202026-09-23 — Three rulings from the product thinker's run A interview, 14:38Z to 14:41Z, on items F and G. F, abcd's name in an adopted repository's two name-guard hooks and its `.gitignore` fence (iss-2609231103413459): the 2026-09-11 ruling that the install does not write abcd by name into a target repository (iss-2609110944498549) covers them, but they are its sanctioned exception. The hooks run the binary and the fence tells people not to hand-edit it, so both keep their markers and naming as the one allowed mention of abcd in an adopted repository, with no rename and no migration; whether the record ids in the hook prose count as part of that mention is left to check, since the ruling named the markers, not the ids. G1, the em-dash-in-list-item house-style token in a prepared repository's docs lint: it is offered at install and the adopter chooses whether it blocks or warns, in the product thinker's words "It's offered at abcd install. the user chosen: Either blocking or warning"; not "off". An unattended (`--yes`) install seeds it as a warning (the 14:41Z follow-up). The run settled what the ruling left open: a bare Enter or end of input takes the displayed default, the warning; an answer naming neither choice, such as the `y` a piped `yes` sends, seeds the warning and the install result says what was heard rather than guessing a gate; the chosen severity is recorded as the token's severity in the seeded config itself; and the question is asked only when that config is being created, so a repository with its own config keeps its severity. G2, `docs lint` with nothing checked: warn, do not fail. The exit status stays 0, since an exit 2 would turn red the CI of every repository prepared before its config carried rules, and the run prints a loud warning that nothing was checked and why (no rule armed, or roots that hold no markdown document), on stderr and in the JSON envelope.
- iss-2609231103413459A default ahoy install still commits abcd's name, and abcd-internal record references, outside the .abcd/ namespace the adopter accepts: the two name-guard hooks (.githooks/pre-commit and .githooks/pre-merge-commit: the '# abcd-name-guard: v1' marker, prose naming abcd, 'abcd ahoy' and 'abcd banlist', and the itd-74 / spc-20 ids) and the .gitignore fence ('# BEGIN ABCD', '# abcd-managed block — do not hand-edit. Run /abcd:ahoy to refresh.'). Reproduced 2026-09-23 on a fresh git repo with 'abcd ahoy install --yes --adopt --visibility private': grep -ril abcd over the tracked result names both hooks and .gitignore. The 2026-09-11 ruling (iss-2609110944498549) is that ahoy install must not write abcd by name into a repository it adopts, and prepare-this-repo's acceptance promises no abcd-internal content in any committed artefact. The fix for that record removed the conventions-file block from the default (docs target skip); these writes remain. Major: this is the unmet remainder of iss-2609110944498549 (major), whose acceptance 1 (no committed file contains abcd after a default install) this record now holds; it carries that severity rather than a lower one, so the remainder still meets the release-cut guard. The hooks are not the files a repository's contributors read first, and the hooks run the abcd binary, so part of the naming is functional, but that bears on the fix, not on whether the ruling is met. What a fix has to settle: the hook marker and the fence are what detection classifies by (classifyGuardHook, gitignoreBlockDrifts), so a rename is a migration over every already-adopted repo, and the hooks are security-sensitive; whether the name in a hook that invokes the tool is in scope of the ruling at all is the product thinker's call.
- iss-2610020700529281The managed block ahoy install plants into an adopted repository's conventions file when a docs target is chosen (internal/core/ahoy/defaults/claude-md-marker-block.md) is abcd's own rule-loader section copied verbatim, and it breaks the repositories that receive it. (a) It ends 'For internals see .abcd/development/brief/05-internals/03-configuration.md' and says OPINIONS points at .abcd/development/principles/; both exist only in abcd's own repository, so they dangle in every adopted one. (b) At tip it is 98 lines with em dashes on 10 of them, so a repository whose own AGENTS.md rules bound file length, ban em dashes or require every link to resolve fails its own gate on the block. (c) Its header says /abcd:ahoy 'silently overwrites this block on drift (per itd-3)', citing an abcd-internal record id, so the adopter cannot trim it to fit. (d) It is inserted directly under the H1, ahead of the repository's own opening text. This record is intent-shaped: the ask is a capability, a short pointer variant of the block for adopted repositories (a few ASCII lines, no repository-internal links or record ids) or keeping the long text where consumer repositories never commit it; routing it to an intent is the product thinker's call. Related: iss-2609110944498549 (resolved, the default docs target is skip) and iss-2608210934566220 (the injected OPINIONS pointers dangle in managed repositories).
- iss-2610040350491915itd-2610030814013772 criterion A1 says 'when setup runs, then it writes AGENTS.md' with the example 'after setup in a new folder the root holds AGENTS.md', confirmed by the product thinker on 2026-10-03, but a bare setup writes no AGENTS.md: docsTargetDefault is skip (internal/core/ahoy/detect.go), so only an install at --docs-target agents_md, or prepare-this-repo, creates the file. The fidelity audit of 2026-10-04 judged A1 MET_WITH_CONCERNS on that difference. The spec (spc-2610031156364295, open design question 1) chose reading (a), keeping the standing ruling that a default install names abcd in no committed conventions file (iss-2609110944498549), and the facilitator decided it without a question; the criterion's example, as the product thinker confirmed it, reads the other way. Either the example is confirmed as holding at agents_md only, or the default is reopened; today the record carries both.
- spc-2610031156364295evaluate-whether-claude-md-can-be-removed-safely-now-that