Repository navigation
feat(isolation): add personal-kit template for the scope-layers pattern - #442
Conversation
24ddfed to
e742469
Compare
4a86b4e to
b3a91f6
Compare
3169aee to
a1822c3
Compare
mogul
left a comment
There was a problem hiding this comment.
Address now
- Blocking:
integrations/isolation/acq-kits/examples/personal-kit/spec.yaml:88usesgrep -Eqs '^[^#]*\\\\.rc\\\\.d' "$HOME/.bashrc"to detect whether a lower layer has already wired~/.rc.d. In ERE, the doubled backslashes make this look for literal backslashes before the characters aroundrc, so it does not match a normal existing loop such ascase $- in *i*) for f in "$HOME"/.rc.d/*.sh; do .... That means the personal kit will append its own loop even when a team kit already wired one, so drop-ins can be sourced twice despite the docs/spec saying the personal kit skips lower-layer loops. The commented zsh example atintegrations/isolation/acq-kits/examples/personal-kit/spec.yaml:108has the same pattern and should be corrected too. - Blocking:
integrations/isolation/acq-kits/examples/personal-kit/scripts/verify:220repeats the same over-escaped detection pattern when deciding whether another layer wired the loop. If this template is stacked on a team kit with a normal~/.rc.dloop and this kit did not add its marker, the verifier reportsnoneinstead ofother, so it does not validate the documented skip behavior reliably. Please use a single escaped dot in the guest-side grep pattern, e.g.^[^#]*\\.rc\\.das the actual script text passed togrep -E.
Track later
- Consider adding a tiny static regression test for the rc-loop detection pattern, because this is easy to over-escape across YAML, shell, and nested
acq execquoting layers. - The live
scripts/verifystill depends on a sandbox-capable host plus network behavior; CI covers static validation, but not the end-to-end stack.
Checks run
- Confirmed local
HEADmatches GitHub PR head SHAa1822c3c3ea6cbd6d21f8d52d5e33d6a157f9ec1. - Reviewed PR timeline/comments/reviews and diff with
gh pr view,gh api .../pulls/442/reviews,gh api .../issues/442/timeline --paginate, andgh pr diff. /tmp/opencode/pr442-venv/bin/python scripts/validate_repo.pypassed./tmp/opencode/pr442-venv/bin/python scripts/generate_index.py --checkpassed./tmp/opencode/pr442-venv/bin/python integrations/isolation/acq-kits/validate-kits.py --strictpassed./tmp/opencode/pr442-venv/bin/python scripts/scan_unsafe_shell.py integrations/isolation/acq-kits/examples/personal-kitpassed.shellcheck -S warning integrations/isolation/acq-kits/examples/personal-kit/scripts/verify integrations/isolation/acq-kits/examples/personal-kit/files/home/.rc.d/50-example.shpassed.bash -n integrations/isolation/acq-kits/examples/personal-kit/scripts/verify && git diff --checkpassed.- Reproduced the grep issue locally: the intended single-backslash ERE matches
.rc.d, while the current doubled-backslash ERE misses it.
a1822c3 to
222b152
Compare
222b152 to
347cc1c
Compare
347cc1c to
fcde6b4
Compare
fcde6b4 to
b958e69
Compare
b958e69 to
c4f8396
Compare
c4f8396 to
c07f170
Compare
c07f170 to
aebe34e
Compare
4d38a5b to
dfec5b5
Compare
8c14645 to
42d1c47
Compare
wz-gsa
left a comment
There was a problem hiding this comment.
AI-assisted review (OpenCode), advisory — needs a human to confirm before it drives a change. Reviewed head 42d1c47d, stacked on patterns#441 at 7e4c2031.
The two blockers from mogul's Oct 1 review are fixed. The rc-loop regex now carries the correct single escaped dots through both quoting layers, and the new 11-case regression test executes the real grep -E against bash/zsh loops, comments, and a wildcard lookalike. shellcheck and bash -n are clean. I also exercised the commented zsh-handoff guard under real Bash 3.2 modes; it behaves as documented:
bash -lc -> command runs, no handoff
bash -ic without a TTY -> command runs, no handoff
bash -ic with a TTY -> command runs, no handoff (BASH_EXECUTION_STRING)
plain interactive bash with TTY -> hands off to zsh
plain interactive + handoff mark -> stays bash
One new blocker remains because the quickstart contract changed after this stack was authored.
Blocker — quickstart v4.0.0 already owns the neutral ~/.rc.d bridge; this template now sources every drop-in twice on MSB login
The PR's central premise is now stale. docs/scope-layers.md:211 says:
Neither the image nor the global layer sources
~/.rc.d, so one kit must wire the loop
and spec.yaml:81-95 appends an interactive loop to ~/.bashrc when .bashrc itself does not mention .rc.d.
But GSA-TTS/agentic-coding-quickstart#482 is closed/completed and shipped in quickstart v4.0.0 through GSA-TTS/agentic-coding-quickstart#474. Current acq now owns a backend-neutral bridge on both backends:
common.sh:1180-1200emitsacq_login_profile_rc_block, which directly sources every readable~/.rc.d/*.shin C-collation order.msb.sh:3789-3852writes.profilewith both:. "$HOME/.bashrc"- the direct rc.d block immediately after it.
sbx.sh:650-704writes the same direct rc.d block into.profile.docs/CONCEPTS.md:314-372documents the shipped contract and explicitly says old team-kit.bashrcappend steps should be dropped once the built-in bridge exists.
The personal template only searches .bashrc, so it does not see acq's .profile bridge and appends its own loop. On MSB login, acq then sources .bashrc (first copy) and immediately sources .rc.d itself (second copy).
I reproduced the actual startup chain locally using the current origin/main acq_login_profile_rc_block plus this PR's .bashrc loop and a drop-in that increments a counter:
$ HOME=<fixture> bash --rcfile <generated-current-msb-profile> -ic 'echo RC_COUNT=$RC_COUNT'
RC_COUNT=2
This is exactly the outcome the PR's docs say must not happen: aliases may be harmless, but PATH edits, hooks, shell options, prompt functions, tool initialization, and the commented exec zsh handoff can all have non-idempotent behavior. It also means the new regex test proves the obsolete append-if-absent mechanism rather than the current acq integration.
Fix direction
The template should consume the v4.0.0 neutral bridge rather than install a second one:
- Remove the live startup command that appends the bash
.rc.dloop. - Update
docs/scope-layers.md, the personal README, troubleshooting, and ADR 0005 to state that current acq owns the bash login bridge on both backends. The template only delivers snippets. - Change the verifier from
bash -ic/ inspecting its own marker to the real supported contract: a login bash invocation (bash -lic ...) sees the drop-in through acq's.profilebridge, while scriptedbash -lcand command-stringbash -icdo not get hijacked by the optionalexec zshdrop-in. - Retain zsh-native wiring as a documented optional step where needed: quickstart's current contract says bash is built-in, while zsh-capable images must wire the same directory from native zsh startup files.
- Replace the current regex regression test with one that prevents the duplicate bridge from returning — e.g. assert the personal template has no active
.bashrcloop command and that docs point to the acq-owned bridge. The old over-escaping test no longer protects a live mechanism after this change.
If backward compatibility with pre-v4 acq is required, make that an explicit versioned compatibility path rather than unconditional .bashrc mutation; as written the template targets acq v4.0.1 in its own test record, so the built-in bridge is available.
Reviewer ask: Nix personal-tool exception
The exception is acceptably bounded as documentation, not live config: the entire step is commented; only personal, not team-wide, tools qualify; it requires an image that already ships Nix; it pins the image's exact NIXPKGS_REV; runs at startup rather than install; checks the binary name separately for package/binary mismatches; treats failure as non-fatal; and registers dependent git config only when the tool is present. ADR 0005 records the exception, so it is not an undocumented erosion of "toolchains in the image."
One operational cost remains by design: nix profile install can still make every startup slow or noisy if the binary name/pin is wrong, but the comments call out the package-vs-binary trap and the step is opt-in. No finding on this part.
Checks
test_personal_kit_rc_loop_pattern.py: 11/11 pass.shellcheck --severity=warningonscripts/verifyand50-example.sh: clean.bash -n scripts/verify: clean.- Strict kit validator: all 10 kits + 2 templates valid.
- Repo validators: pass.
- Nested verifier quoting reproduced locally: personal guarded loop ->
n; lower-layer loop ->other; comment/lookalike ->none; unguarded personal marker ->y. - No existing issue duplicates this exact conflict. quickstart#482 is the completed dependency whose landing created it; patterns#421 is the parent template proposal. This fix belongs in the PR, not a new issue.
Unverified: no live sandbox here. The reported 18-pass MSB run predates or does not reflect the current duplicate-bridge integration; I did not rerun it. SBX was not live-tested by the author for this revision either.
wz-gsa
left a comment
There was a problem hiding this comment.
Blocker — current acq already owns the backend-neutral ~/.rc.d login bridge, so this template sources every drop-in twice. The two regex findings from the prior review are fixed at head 42d1c47da; this is a separate cross-repo integration defect.
Quickstart main now defines acq_login_profile_rc_block() in acq.backends/common.sh:1180-1201 as the single shared bridge for both backends. MSB writes .profile with this sequence (msb.sh:3843-3853): source .bashrc, then execute that bridge, which sources every readable ~/.rc.d/*.sh. SBX installs the same bytes through _acq_sbx_ensure_rc_bridge (sbx.sh:651-692).
This template’s startup command checks only $HOME/.bashrc (spec.yaml:88), so it cannot see the existing bridge in .profile; it appends its own .bashrc loop. On the supported MSB login path the resulting order is: .profile sources .bashrc → the personal-kit loop sources each drop-in once → control returns to .profile → acq’s bridge sources each drop-in again. Non-idempotent PATH edits, hooks, prompt setup, and the example exec zsh handoff can therefore run twice. This contradicts scope-layers.md:211 and the template README’s claim that exactly one layer wires the directory.
The verifier misses it because scripts/verify:252-266 probes bash -ic and searches .bashrc, bypassing the acq-owned login path in .profile entirely.
Suggested fix: remove the active bash startup command and rely on acq’s v4 backend-neutral login bridge; retain only optional native-zsh wiring if needed. Change verification to exercise a login shell, and replace/revise scripts/tests/test_personal_kit_rc_loop_pattern.py, which currently protects the obsolete .bashrc mechanism. Also update the docs that tell a personal kit to own the loop.
Evidence was read against quickstart main, not inferred: the shared bridge is explicitly documented as the ONE text used by both MSB and SBX. All seven PR checks pass, but none models this cross-repo login chain. AI-assisted review (OpenCode), requesting changes with the maintainer’s explicit authorization.
63aedf2 to
e8f30b7
Compare
acq v4.0.0 and later writes ~/.profile so every bash login shell sources ~/.rc.d/*.sh on both backends. A kit that also appends a loop to ~/.bashrc makes every drop-in run twice, so the pattern doc no longer tells a kit to wire one. acq's loop has no interactive guard, so drop-ins must be safe in scripted bash -lc runs. Reported in review of #442.
acq v4.0.0 and later sources ~/.rc.d/*.sh from ~/.profile in every bash login shell on both backends, after sourcing ~/.bashrc. The template's startup step appended a second loop to ~/.bashrc, so on msb every drop-in ran twice in a login shell (reproduced on msb 0.7.7 with acq v4.0.1). - Drop the .bashrc loop step; keep the commented zsh step, since acq's loop runs only in bash. - verify: check the drop-in in a bash login shell, count how many times it is sourced (exactly once), and check a scripted bash -lc still runs, instead of probing bash -ic and the template's own loop. - Docs: acq's loop has no interactive guard, so drop-ins also run in scripted bash -lc and must guard interactive-only lines themselves. - Test: no kit or template wires ~/.rc.d into a bash startup file; the zsh step's grep pattern keeps its regression cases. Reported in review of #442.
e8f30b7 to
05bcf97
Compare
|
Thanks — confirmed and fixed. I reproduced it live on msb 0.7.7 with acq v4.0.1: a counter drop-in ran twice under
verify on msb 0.7.7 with acq v4.0.1: personal 19 passed / 0 failed / 1 skipped, team 20 / 0 / 1. |
wz-gsa
left a comment
There was a problem hiding this comment.
Re-review of 05bcf970: the duplicate Bash bridge blocker is closed. Approving the stacked personal-kit change, contingent on merging #441 first (this PR's current base is feat/team-kit-template).
Verified:
- The active
.bashrcrc.d append step is gone fromspec.yaml. - The only remaining startup-file wiring is the commented optional zsh example, which current acq does not provide.
- README/troubleshooting now state that acq owns the Bash login bridge, warn against adding a second loop, and explain the custom-image
.profilecaveat. - The live verifier uses
bash -lic, requires exactly one xtrace source event, and confirms scriptedbash -lccompletes. - The replacement repository-wide regression test scans every kit and template, rejects active rc.d wiring in Bash startup files, asserts discovery is non-empty, and preserves real
grep -Epositive/negative cases for the zsh pattern.
Executed locally at the current head:
test_kit_rc_d_wiring.py: 19 passed
strict kit validator: all 10 kits + 2 templates valid
repo validators: all pass
The earlier two regex blockers remain fixed, and the optional zsh handoff guard still behaves correctly under Bash 3.2 (bash -lc, bash -ic with/without TTY, plain interactive TTY, and handoff-marker cases were exercised in the prior review).
No remaining finding. Merge order: #441, then retarget/rebase this stacked PR onto main and confirm refreshed CI.
Add the copy-and-rename template acq-kits/examples/personal-kit/: a hybrid/v1 mixin stacked last, with a shell drop-in and the ~/.rc.d loop wired for interactive bash, a git preference, and an OpenCode TUI theme through OPENCODE_TUI_CONFIG. Its scripts/verify stacks it on a team kit (the team-kit template by default) and asserts the three-layer stack. The pattern doc gains the personal-layer guidance the template relies on (the exec-zsh guards, the one personal-tool exception to "tools belong in the image"), ADR 0005 records the commented Nix install step as a deliberate exception, and acq-kits/README.md lists the template.
acq v4.0.0 and later sources ~/.rc.d/*.sh from ~/.profile in every bash login shell on both backends, after sourcing ~/.bashrc. The template's startup step appended a second loop to ~/.bashrc, so on msb every drop-in ran twice in a login shell (reproduced on msb 0.7.7 with acq v4.0.1). - Drop the .bashrc loop step; keep the commented zsh step, since acq's loop runs only in bash. - verify: check the drop-in in a bash login shell, count how many times it is sourced (exactly once), and check a scripted bash -lc still runs, instead of probing bash -ic and the template's own loop. - Docs: acq's loop has no interactive guard, so drop-ins also run in scripted bash -lc and must guard interactive-only lines themselves. - Test: no kit or template wires ~/.rc.d into a bash startup file; the zsh step's grep pattern keeps its regression cases. Reported in review of #442.
05bcf97 to
967008f
Compare
wz-gsa
left a comment
There was a problem hiding this comment.
Approving retargeted head 967008f7 after #441 merged.
GitHub rewrote the stacked branch onto main; the personal-kit files are byte-identical to reviewed fix 05bcf970:
git diff 05bcf970 967008f7 -- integrations/isolation/acq-kits/examples/personal-kit \
scripts/tests/test_kit_rc_d_wiring.py \
integrations/isolation/docs/decisions/0005-kit-templates.md
(empty)
The duplicate Bash bridge blocker is closed: no active .bashrc/.profile rc.d loop remains in the kit; acq's v4 login bridge owns Bash sourcing; zsh wiring remains commented/optional; the verifier uses bash -lic, requires exactly one source event, and confirms scripted bash -lc completes. The repository-wide regression suite passes 19/19, strict kit validation passes all 10 kits + 2 templates, and all repo validators pass.
All seven refreshed CI checks pass on this retargeted head. The old changes-requested reviews refer to superseded heads (42d1c47d) and both their regex and duplicate-bridge findings are now fixed.
|
@mogul — #441 is merged and GitHub retargeted this stack to |
Summary
Adds the
personal-kittemplate for the scope-layers pattern: a copy-and-rename hybrid/v1 mixin for the personal layer, stacked last inACQ_EXTRA_KITSon top of the global kits and a team kit.It ships a shell drop-in (acq v4's
~/.profilesources~/.rc.din bash login shells, so the kit only delivers it), a git preference, an OpenCode TUI theme throughOPENCODE_TUI_CONFIG, and ascripts/verifythat asserts the three-layer stack.Third of three stacked PRs for #421: #476 (examples/ container), #441 (pattern doc and team-kit template), then this one.
Reviewer ask: is the shell guidance right? acq v4.0.0+ sources
~/.rc.d/*.shfrom~/.profilein every bash login shell, scriptedbash -lcincluded, so the template adds no loop of its own. Drop-ins guard interactive-only lines themselves, and the commentedexec zshdrop-in guards on$-, a terminal,BASH_EXECUTION_STRING,ZSH_VERSION, and a handoff marker. Also: is the commented Nix tool-install step an acceptable exception to "tools belong in the image" (ADR 0005 records it)?Eligibility & Accountability
@GSA-TTS/agentic-coding-teamcode-owner approval; eligibility is attested here, not authenticated). Anyone may open issues without this.AI Assistance Disclosure
Type of Change
integrations/)Motivation
The team-kit template covers the layer a team owns. The personal layer on top has its own recurring mistakes: shipping a whole
~/.bashrcor~/.gitconfigthat clobbers the image's, anexec zshdrop-in that swallows scripted runs, binary terminfo payloads, and personal variables that silently shadow the team's. This template is a validated starting point that avoids them.What lands:
acq-kits/examples/personal-kit/: one live, harmless value per extension point (egressexample.net, the~/.rc.ddrop-in andtui.jsonc, one git alias,OPENCODE_TUI_CONFIG), commented examples for a~/.zshrcloop, terminfo compiled withtic, aninclude.pathgitconfig, and Nix-installed personal tools; README, TROUBLESHOOTING,scripts/verify. Teammates apply it through the team kit'senv.sh(PERSONAL_KITS).docs/scope-layers.md: the personal-layer rows point at the template, theexec zshguard is spelled out, and "Neither" names the one personal-tool exception.acq-kits/README.md: the template is listed, and the commented Nix step is recorded as a deliberate exception.Testing
make validatelocally (all checks pass)make test(if applicable): 448 passed, includingscripts/tests/test_kit_rc_d_wiring.py, which fails if any kit or template wires~/.rc.dinto a bash startup file and runs the commented zsh step's detection pattern through the realgrep -Eexamples/personal-kit/scripts/verifyon msb 0.7.7 with acq v4.0.1: 19 passed, 0 failed, 1 skipped (the empty PERSONAL section). It stacks the team-kit template and this template on the pinned built-in bundle and asserts that the global and team layers survive, each live value landed, the drop-in is sourced exactly once by a bash login shell, a scriptedbash -lcstill runs its command, and both kits' env vars, files, and egress hosts coexist against a denied control host. Not re-run on sbx for this revision (the host's sbx session neededsbx login).Also run:
validate-kits.py --strict(All 10 acq-kits + 2 template(s) valid.),acq kit validateon the template,make generate-check, markdownlint.Safety Checklist
prohibited_contentin output contract (if applicable): not applicable, no SKILL.md patternQuality Checklist
Validation Results
Related Issues
Relates to #421 (the personal-kit template)
Depends on #441
Relates to GSA-TTS/agentic-coding-quickstart#482 (acq's
~/.rc.dlogin hook, which the template relies on)