Skip to content

feat: setup checks first, shows one plan, and asks only what is yours - #1125

Merged
REPPL merged 32 commits into
mainfrom
feat/setup-redesign
Oct 26, 2026
Merged

REPPL merged 32 commits into
mainfrom
feat/setup-redesign

Conversation

@REPPL

@REPPL REPPL commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Setup (abcd ahoy install) redesigned so the person running it knows what will be automated before anything changes.

What changes

  • Setup checks first, shows one plan, then asks. Git, the repository and an agent harness are checked up front. If any is missing, setup stops at once. One plan lists every change. Each question is short, and a person is asked only what is theirs to answer. The report ends in three parts: done, needs you, next.
  • Each person's commit identity lives on their own machine (itd-2610240918547728). The repository no longer pins an identity for everyone. The record is read through the guarded home reader, and a record that cannot be read is reported as uncheckable.
  • Tools come from downloads pinned in abcd's release (itd-2610240918594138). Each tool is fetched, checked against the release's checksums, and put in ~/.local/bin, with no admin rights or Homebrew needed. A copy found elsewhere is used only at a version abcd works with.
  • Setup asks before it edits the shell settings to put abcd's folder on PATH (itd-2610240919030303). The question names the exact line, and the file is checked again just before it is replaced.
  • Commit checks: in a clone that does not run them, setup asks whether to set core.hooksPath. It never sets it under --yes, off a terminal, or over another hooks path.

Records

  • Three intents shipped, with their specs closed in this change.
  • The setup flow intent (itd-2610240823055889) stays planned. Its question-budget criterion carries over to spc-2610242112593216 until the product thinker rules on dcn-2610241228598485.
  • The hold-ups met during the build are captured as issues.

Checks

make preflight passed on b79a72f, and the push receipt was minted.

Assisted-by: Claude:claude-opus-5-5

REPPL added 30 commits October 24, 2026 12:14
…issues behind them)

Assisted-by: Claude:claude-opus-5-5
…ings

When the folder abcd installs into is not on the PATH, `abcd ahoy install`
asks a person at a terminal, once, whether to add one marked line to the
startup file their login shell reads, naming the file and the line. On a
yes it keeps a copy of the file, adds the line, reads the file back and
says to open a new terminal; `abcd ahoy uninstall` removes that line and
nothing else. Settings that already add the folder are left alone, a file
that is a link kept elsewhere is never edited, and --yes or a run off a
terminal never asks: the line stays on the notes for the person to add.

internal/core/shellpath holds the plan, the edit and the removal (zsh and
bash, macOS and Linux). adr-2610241022330872 supersedes the rule that abcd
never edits a shell profile; the brief, the ahoy command page and the
install guide now describe the offer. The spec body is filled; the spec
stays open.

Assisted-by: Claude:claude-opus-5-5
A plain-terminal run after the README's install line resolves no plugin
root, and detection left install_mode empty for a working copy that
~/.abcd.noindex/path-entry records. The copy the record names, whose bytes
still match it, is now reported as pinned.

Resolves: iss-2610240916382802
Assisted-by: Claude:claude-opus-5-5
In a source checkout of abcd, go run is the sanctioned way to run abcd, and
go run never stamps a revision, so ahoy install refused every such run as an
unknown vintage. A go run build (a development build of the module's
cmd/abcd, unstamped, run from a go-build work directory) of the module the
checkout's go.mod declares is built from that tree as it stands, so the
refusal lets it through; every other unstamped binary is still refused.

Resolves: iss-2610240824047504
Assisted-by: Claude:claude-opus-5-5
…r own

ahoy install now stops before any question when git, a repository or an
agent harness is missing; shows one plan screen (approve.plan) listing every
change and every default with where to change it, and asks once: proceed,
customise or cancel; asks the abcd download, the shell settings (a seam for
itd-2610240919030303), the status line, the commit identity and each tool as
questions of their own; draws every question on one line with ? for the
whole of it; and ends on a three-part report, or one line when nothing is
left to do. The download is fetched through update.FetchVerified, checked
against the release's checksums and signed build provenance, before the
status line is offered, and the status line is never asked about when it
cannot be wired. An answers file's approve.<category> ids are refused,
naming approve.plan.

Resolves: iss-2610240824005655
Resolves: iss-2610240823574047
Assisted-by: Claude:claude-opus-5-5
adr-2610241101463288 records that setup asks short questions with ? for the
whole question and lists its defaults on one plan screen, and invariant 1
and the universal pattern for prompts now say so; invariant 7 names the
download setup makes on a yes. commands/ahoy.md and the brief's ahoy page
describe the flow, the answers file's approve.plan and the download; the
spec spc-2610241007434505 is filled; the generated surface appendix and CLI
reference carry --details.

Assisted-by: Claude:claude-opus-5-5
The commit check no longer reads an identity the repository commits. Each
person records their own identity under ~/.abcd.noindex (identity.json, or
identity/<root-sha>.json for one repository), read under the home-scoped
declaration guards; the Go check, `abcd ahoy --identity` and the committed
pre-commit gate hold the author and committer to that record, refuse a
machine identity in either role with or without one, and name only the
person's own record and how to change it.

Setup proposes a person's usual git identity at a terminal, as its own
question, and records it on a yes. A repository that still stores the
itd-131 pin has it moved to its owner's machine on a yes at a terminal; its
production_mode stays committed in .abcd/config/provenance.json, which
provenance.DeclaredMode now reads. The pin and the declared-mode files are
read through the guarded reader.

Records adr-2610241022541063; fills spc-2610241007568207 (left open).

Resolves: iss-2610240830397793
Assisted-by: Claude:claude-opus-5-5
A link put at the path after the file was judged is refused rather than
replaced by a regular file.

Assisted-by: Claude:claude-opus-5-5
# Conflicts:
#	.abcd/development/decisions/adrs/README.md
#	internal/core/ahoy/apply.go
#	internal/core/ahoy/install_summary.go
#	internal/surface/cli/ahoy_prompt_stdin_test.go
Setup no longer installs gitleaks or gh through Homebrew. Each tool has a
release table compiled into abcd (internal/core/tools/release.go): the
pinned version, and per platform (macOS and Linux, arm64 and amd64) the
full GitHub release download URL, its sha256 copied from the makers'
checksums file, and the program's path inside the archive. No version is
ever looked up.

An install downloads over https from GitHub's release hosts alone,
bounded in size and time, refuses bytes whose sha256 is not the pin,
verifies gh's signed build record in process against cli/cli's
deployment.yml on trunk, and only then writes the program into the
person's own bin folder ($XDG_BIN_HOME, $XDG_DATA_HOME/../bin, or
~/.local/bin) with no admin rights. gitleaks signs nothing, so it is
checked by checksum only, and setup says so. The copy is verified by its
version and recorded in ~/.abcd.noindex/tools.json; abcd runs that copy
whatever comes first on PATH, and ahoy uninstall removes it while it is
still the bytes abcd wrote.

A copy installed some other way is used when its version lies in the
range abcd works with; otherwise setup offers abcd's own copy, says which
of the two will run, and never changes the other copy. No step shown or
run needs admin rights, and nothing is installed in CI.

Records adr-2610241057124151, which graduates dcn-2610240845548776, and
fills spc-2610241008092356.

Resolves: iss-2610240824571059
Assisted-by: Claude:claude-opus-5-5
# Conflicts:
#	.abcd/development/decisions/adrs/README.md
#	commands/ahoy.md
#	internal/core/ahoy/apply.go
#	internal/surface/cli/ahoy_prompt_stdin_test.go
#	internal/surface/cli/cli.go
# Conflicts:
#	.abcd/development/decisions/adrs/README.md
#	internal/core/ahoy/ahoy.go
#	internal/surface/cli/cli.go
addsDir treated any startup-file line ending in abcd's marker as one that
adds the folder asked about, so a marked line for another folder
silenced the shell-settings offer. It now compares the line whole
against MarkedLine(home, dir), as Remove's lineIndex does; the person's
own spellings are still recognised as before.

Assisted-by: Claude:claude-opus-5-5
Plan returned UseOwned with Compatible true for any intact recorded
copy, so a copy outside the range kept running and was never replaced.
abcd's copy is now used only while its version is the pinned one; at
another version in the range it still runs and the pin is offered as an
upgrade that a no leaves alone, and outside the range it is not run and
the pinned copy is offered over it. Install replaces a file only while
it is still the bytes abcd recorded, and puts the earlier copy back if
the new one fails its verify. Resolve runs the recorded copy only when
its version is in range.

Plan also gains PathOnly, which counts a copy on the PATH as usable
without running its version command, for the detection pass the hooks
run.

Assisted-by: Claude:claude-opus-5-5
Review findings on the setup redesign:

- A change the person said yes to that then fails (a tool download that
  fails its sha256 or signed build record, the abcd download that does
  not verify, a shell-settings edit, including one abcd could not put
  back) is now a needs-you step in the default report with its reason
  and the step by hand, not only a note behind --details.
- The path.bin_dir_not_on_path step follows the shell-settings plan:
  once the startup file adds the folder it is to open a new terminal,
  where abcd will not edit the file it is the export line with the
  reason, and only where setup will ask does it name the question.
- The shell question's one line names the line and the file; ? says the
  folder goes ahead of the rest of the PATH.
- The plan lists a tool only where abcd offers its own copy and the shell
  question only where the run leaves an entry, and the run asks in the
  plan's order: download, shell settings, status line, identity, tools.
  At a terminal no dependency approval is asked, so customising never
  drops a tool's own question.
- A required tool's step no longer calls it optional.
- A bare Enter at the stdin door's plan screen asks again.
- Detect, which the hooks run, starts no tool; install, the dry run and
  doctor judge a copy's version.

Assisted-by: Claude:claude-opus-5-5
… them

Setup committed the name guard and the other hooks in .githooks and
reported clean in a clone whose core.hooksPath was unset, so git never
ran them. Where abcd's guard is committed and no hooks path is set at
any scope, setup now asks a person at a terminal, as its own question
after the shell settings ("Switch on this repository's commit checks,
setting core.hooksPath to .githooks in this clone's .git/config?"),
naming any .git/hooks hooks that would stop running and the command
that undoes it. A yes sets the key with git config --local, reads it
back and reports it in Done; the plan lists the question. --yes and a
run off a terminal never set it, and the report then lists the exact
command. A hooks path set outside the clone (a dispatcher) is never
offered a local one, and a local value naming another directory is
reported, not replaced. The install is partial, never clean or up to
date, while the committed hooks do not run.

Resolves: iss-2610241134315056
Assisted-by: Claude:claude-opus-5-5
…rovenance.json

commands/ahoy.md and the brief's ahoy page now say what setup does after
the review fixes: failures of approved changes on the needs-you list,
the PATH step that follows the shell settings, the shell question's one
line, the plan listing exactly the questions the run asks and in its
order, tools never behind an approval at a terminal, abcd's own tool
copy used only at a version in range, detection that starts no tool, a
bare Enter at the plan screen, and the commit-checks question. The spec
bodies' criterion notes name the tests that hold each. The intent page
said the default production mode came from .abcd/config/identity.json;
it comes from .abcd/config/provenance.json, with the legacy fallback,
and the identity page no longer calls identity.json the live pin.

Assisted-by: Claude:claude-opus-5-5
Resolves: iss-2610241158083013
Assisted-by: Claude:claude-opus-5-5
The setup-flow spec closes with a remainder for criterion 5, the question
budget, held for the product thinker's ruling (dcn-2610241228598485), so
that intent stays planned.

Delivers: itd-2610240918547728
Delivers: itd-2610240918594138
Delivers: itd-2610240919030303
Assisted-by: Claude:claude-opus-5-5
The whole-package run of the setup review fixes found what the narrow
runs missed:

- A forced mode switch (--dev over a pinned entry) wrote the dev shim
  but no longer recorded it, so every hook ignored it
  (symlink.unrecorded). stepPathEntry was gated on the settings approval,
  which used to arrive only because the identity gaps were approved with
  the settings; it now also records on the forced switch, the word
  stepSymlink already writes the entry on. This failed at the branch
  head before the review fixes too.
- The bare-Enter, approval-order and question-row tests: the dependency
  approval is not asked at a terminal, the shell and commit-checks
  questions are shortened to fit the 24-row limit, and the commit-checks
  question now reads "Run the commit checks: set core.hooksPath to
  .githooks in .git/config?".
- Waiting returns the commit-checks question, so an after-update run can
  put it.
- Tests that install into a real clone under --yes, about something
  else, read the status the run would have had but for the unarmed hooks
  (heldByHooks), or arm the clone first; the one-line rerun answers yes
  to the identity record as well as the commit checks.

Assisted-by: Claude:claude-opus-5-5
TestHookSessionEndRetriesATransientRootFailure failed in every run on
this branch, its head before the setup review fixes included: the hook's
1.2 s retry budget is spent by the first detection on a loaded machine,
so the hook says no time is left to ask again and stages nothing. The
test holds the retry, not the machine's speed, so it now runs with a 30 s
budget; the hook's own budget is unchanged.

Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
The tools registry and four test files spelled the home folder's name;
they now reach it through abcdhome.Display and abcdhome.Path. The go run
vintage check asks git's top level through gitutil.Toplevel and its test
runs git under gittest.Env. The identity, provenance and shellpath
functions no production code outside their package reaches are
unexported; ReadRecordAt, a bare wrapper, is gone, and the ahoy tests
read the identity record through identity.LoadRecordForTest. The stale
identity.LoadPin line leaves the reach baseline.

Assisted-by: Claude:claude-opus-5-5
# Conflicts:
#	.abcd/development/brief/06-delivery/03-out-of-scope.md
#	.abcd/development/decisions/adrs/README.md
#	internal/surface/cli/hook_subagent_stage_retry_test.go
@REPPL
REPPL enabled auto-merge October 26, 2026 00:24
Assisted-by: Claude:claude-opus-5-5
@REPPL
REPPL added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit 4e54326 Oct 26, 2026
15 of 16 checks passed
@REPPL
REPPL deleted the feat/setup-redesign branch October 26, 2026 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant