Development record
abcd reaches the harness's user settings only for the status line, with consent
Context
On 2026-10-05, after the person had renamed ~/.abcd to ~/.abcd.noindex, the old folder reappeared three times within an hour, and each time the guard refused every shell command and every question in two sessions at once. The cause was a SubagentStop entry in the person's harness user settings that ran a locally built abcd-darwin-arm64, old enough to reject --version, with hook subagent-stop. Whenever a subagent stopped, that build staged the transcript under the old home and recreated it. The plugin already registered its own SubagentStop hook with the current binary, so the settings entry was a stale duplicate, and nothing in abcd noticed it (iss-2610050556323779).
The same file holds the one entry abcd writes there on purpose: statusLine, which abcd ahoy install points at '<entry>' statusline after the person consents (itd-200). The status line is essential for product thinkers, and a plugin cannot set it: the harness's plugin manifest reference admits only agent and subagentStatusLine in a plugin's settings. Every hook abcd needs, by contrast, can live in the plugin's own hooks/hooks.json.
The product thinker ruled the same day (iss-2610050556383525). The status line runs on every refresh in every session, so the ruling names seven risks the write must be guarded against: a stale or missing binary at the wired path; a status verb that writes state; a line left behind after an uninstall; the previous status command recorded once and gone stale; a concurrent write corrupting the settings file so the harness ignores all of it; a wired path a project or another account can replace; and settings synced to a machine without that path.
Decision
abcd does not touch the person's harness configuration folder, and nothing in it calls abcd, with one exception the person consents to: the statusLine entry in the harness's user settings. Hooks live only in the plugin.
The one write is guarded:
- It happens only after an explicit yes to an offer that shows the entry's value now and after, and
--yesnever gives that yes. - A copy of the file goes into
~/.abcd.noindex/backups/first, which keeps the newest ten; no copy, no write. - The file is replaced atomically with every other key untouched, read back, and put back from the copy when it does not say what was written.
- Only the PATH install
~/.abcd.noindex/path-entryrecords is wired, and only when it passes the trust checks: the binary, a link's target when the entry is a link, is owned by the caller and writable by nobody else; every directory it is reached through, the link's and the target's, is writable by neither its group nor every account and is owned by the caller or root; and none of them is inside the working tree. That is the plugin's hook shims' bar with the directory held to the binary's standard, where the shims test only the every-account write bit. Never the plugin's versioned copy. - A command that reaches abcd's own status verb, under any build name, is never recorded as the previous one.
abcd statuslinewrites nothing and is time-bounded (500ms for abcd's own work, 5s for the previous command), held by tests.abcd ahoy uninstallrestores the previous command, and the install guide says to run it before removing abcd.
abcd reports, and never edits to remove, any hook in those settings that runs abcd, and an abcd status line whose binary fails the trust checks. Session start names such an entry in one line. The one repair abcd makes there is to its own status line, when that line dangles or runs an untrusted abcd, and it is done under the same guards with config-change approval.
Alternatives Considered
- One consented, guarded write for the status line, and report-only for everything else (chosen): it keeps the line product thinkers need, which a plugin cannot set, and puts every hook where a plugin update replaces it with the current binary.
- No writes to the harness settings at all, with the person wiring the status line by hand: removes the risk, but leaves the person to copy a path and a verb, and nothing would notice when that path goes stale.
- abcd removes stray abcd hooks from the settings itself: would have fixed the incident automatically, but edits the person's own configuration without a consent that describes the change, the stance adr-2609091248200336 and adr-2610030720195401 take for the person's folders and settings.
- Keep hooks in the user settings as well as in the plugin: duplicates every hook, and the copy in the settings names a binary no plugin update refreshes, which is the defect that recreated the old home.
Consequences
- The status line survives plugin updates, because it names the recorded PATH install rather than a versioned plugin folder; a machine without that install is refused before anything is offered.
- The backups folder grows by at most ten copies, and a copy that cannot be pruned is noted without failing the write.
- A stray hook stays in place until the person removes it; abcd's part is to name it in
abcd ahoyand at session start for as long as it is there. - Settings synced to a machine where the wired path is missing or untrusted read as
statusline.danglingorstatusline.untrustedthere, and install repairs the line on that machine. - Any future need to call abcd from the harness's user settings is a new decision; the default answer is the plugin's own hooks.
Frontmatter
| id | adr-2610050711287503 |
|---|---|
| type | adr |
| status | accepted |
| date | 2026-10-05 |
.abcd/development/decisions/adrs/2610050711287503-abcd-reaches-the-harness-s-user-settings.md
open on GitHub ↗ · commit history ↗
References3
- adr-2609091248200336A tool never creates directories in user-owned project space; the store's location binds now and its verbs bind when the store shipsrelated
- adr-2610030720195401abcd keeps its own folders out of desktop indexing only by changing those folders, never the computer's search settingsrelated
- itd-200A managed repository shows it is managed, and whose answer the loop is waiting on, in the host's status linerelated
Referenced by1
- adr-2610241022330872Setup edits the shell settings to put abcd's folder on the PATH, on a yesrelated
mentions3
- iss-2610050556323779On 2026-10-05, after the person had renamed ~/.abcd to ~/.abcd.noindex, ~/.abcd reappeared three times within an hour, and each time the guard refused every shell command and every question in two sessions at once (this one and gropiusllm-a3), because one stray folder blocks every session on the account. The cause was a SubagentStop entry in the person's ~/.claude/settings.json that ran a locally built ~/ABCDevelopment/abcd/bin/abcd-darwin-arm64 (old enough to reject --version) with 'hook subagent-stop'. Whenever any subagent stopped, it staged that subagent's transcript under ~/.abcd/transcripts/<root-sha>/staging/, recreating the old home. Evidence: the stray folder held only transcripts/488a0aa9…/staging/20261005T054848.953201000Z-a765320031b9991b5.stage.json and .raw (a subagent of this session, staged at 05:49:05Z) and an empty sessions/ marker. The plugin already registers its own SubagentStop hook with the current binary, so the settings entry was a stale duplicate. Removing it and moving the staged files into ~/.abcd.noindex stopped the recurrence. The rename's guard (itd-2610030720038073, D2) only notices the old folder after something has written it. Nothing in abcd, ahoy included, notices an abcd command wired into the host's settings outside the plugin, so a binary built before a migration keeps writing the old layout in every session until a person hunts it down by hand.
- iss-2610050556383525Product thinker ruling, 2026-10-05: abcd does not touch a person's ~/.claude/ folder, and nothing in it calls abcd, with one exception the person consents to: the status line, which is essential for product thinkers and which a plugin cannot set (a plugin's settings may set only agent and subagentStatusLine; the hooks abcd needs can all live in the plugin's hooks/hooks.json). Today ahoy install offers and writes the statusLine entry, and the person's settings had also gained a SubagentStop entry that called a stale abcd build (the defect that recreated ~/.abcd the same day). Because the status line runs on every refresh in every session, the risks the ruling accepts are: a stale or missing binary at the wired path; a status-line verb that writes state; a line left behind after an uninstall; the person's previous status command recorded once and gone stale; a concurrent write corrupting settings.json so the harness ignores the whole file; a wired path a project or another user can replace; and settings synced to a machine without that path.
- spc-2610120941441282a-person-hands-an-item-from-their