Constructor Pattern fix replacing v0.47-v0.48 patch series. The "is the
user interactive?" logic was previously duplicated across 15+ places:
bootstrap.sh x4 ([ -t 0 ] gates on profile/onboard/launch/etc)
install.sh x1 (PATH wiring decision)
install/lib-hooks.sh (activate-hooks prompt)
install/lib-plan.sh (auto-confirm gate)
install/lib-menu.sh (skip-menu gate)
install/lib-wizard.sh (sleep-wizard gate)
install/lib-onboarding.sh x2 (onboarding_should_run + preflight retry)
install/lib-preflight.sh (install-tool prompt)
Every duplicated check was a chance to get curl|bash semantics wrong.
v0.47 used `[ -t 1 ]` (broke under tee'd stdout). v0.48 used `[ -t 0 ]`
(broke under curl pipe stdin). Each fix was a patch on top of the same
architectural defect: scattered truth.
ARCHITECTURAL FIX (Rule Zero — 1 cube = 1 responsibility):
scripts/kei-prompt.sh (NEW, ~110 LOC, public API):
kei_is_interactive → 0 if user is at a terminal, 1 if headless
kei_prompt Q [DEFAULT] → answer or default to stdout
kei_prompt_yn Q [Y|N] → exit 0=yes, 1=no, with [Y/n] hint
kei_prompt_secret Q → no-echo input (tokens, keys)
Truth signal: /dev/tty accessibility, with [ -t 0 ] as second-choice
fallback. KEI_NONINTERACTIVE=1 for CI override. Same contract as the
inline rules — now in ONE place.
bootstrap.sh + install.sh: source the cube at the top, with self-
contained inline fallback (mirrors the kei_is_interactive contract
only) so they remain self-bootable even if scripts/ is missing.
All 15+ inline gates replaced with `kei_is_interactive` calls.
All 3 `read -r -p` prompts in installer cubes replaced with
`kei_prompt` / `kei_prompt_yn`.
Existing copy_pet_scripts() in lib-scaffold.sh installs scripts/*.sh
into ~/.claude/scripts/ automatically — no install logic change needed.
WHAT THIS PREVENTS:
- Next time someone writes a prompt in installer code, the only path
is `kei_prompt`. They CANNOT accidentally type `[ -t 0 ]` because
there is no `[ -t 0 ]` to copy-paste anymore (except inside the
cube itself).
- The v2 tty-interactivity-gate-guard.sh hook (added 2026-05-27)
becomes a regression net rather than the first line of defence.
- Two real install incidents this month (May 2026, 7 prompts each)
do not happen a third time.
VERIFIED:
- Syntax check passes on all 9 modified files + new cube.
- Primitive functions smoke-tested across 8 cases: headless,
KEI_NONINTERACTIVE override, default fallback, yn convenience,
re-source guard, /dev/tty available, /dev/tty open() fails.
- 2 remaining [ -t 0 ] in tree: BOTH inside kei_is_interactive
fallback in bootstrap.sh + install.sh (single-source contract,
not patches).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Thin skill over the kei-message jsonl mailbox: /msg reads inbox, /msg @name text sends (identity = cwd basename), /msg all broadcasts, /msg list|who. send now accepts leading @name. Mirror of keigit 7b453aac.
Mirror of keigit 3aff0029. lib-hooks.sh apostrophe-in-jq closed the bash single-quote and broke every install (fixed). cortex-ui removed from profiles+menu; forgejo/zoekt source lib-launchd; portable kei-message id (BSD date fallback); non-TTY default minimal; install stamps .kei-profile; README hook count 54; web-install warns before discarding local edits in the managed clone.
Any Claude Code session can message any other (not just Agent-Teams teammates),
no tmux. Append-only jsonl bus + UserPromptSubmit hook pulling unread per turn.
kei-message.sh (send/inbox/list, address by cwd-basename or "all"),
mailbox-inject.sh (cursor dedup, first-turn baseline, no self-echo), bin/kei
`message` dispatch, lib-scaffold copies all scripts/*.sh, snippet wires the hook.
Bypass KEI_MAILBOX_BYPASS=1. Verified by 2-session simulation.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root causes found by reproducing a clean install from keigit:
1. PROFILE_PRIMS resolved only inside check_prereqs → unbound for
--no-execute (plan showed 0 prims for every profile) and silently
empty for --skip-prereqs. Now resolved unconditionally in install.sh
before any reader (SSoT).
2. Every profile (even minimal, advertised "no Rust compile") fell back
to a 5-15 min `cargo build --workspace` because no prebuilt release
binaries exist. Auto-set KEI_SKIP_RUST for profiles with no rust
primitives → minimal installs in ~18s (assembler only). cargo stays a
hard prereq because the agent assembler always compiles.
3. The assembler aborted the WHOLE install on any single bad manifest
(set -e). generate_agents is now tolerant: bad manifests print FAIL
but hooks/skills/settings still land. Commit-time validate stays strict.
4. Data bugs that broke the assembler:
- duplicate [taxonomy] table in _roles/{auditor,merger}.toml
- fal-ai-runner handoff → keimd-expert (not shipped in kit)
- infra-implementer-cicd forbidden_domain literal `${{ secrets.NAME }}`
collided with assembler ${{ }} placeholder detection
5. Metadata: KeiSei84 (nonexistent GitHub org) → KeiSeiLab/KeiSeiKit-1.0
across plugin manifests, bootstrap, README, docs, Cargo/npm metadata.
.claude-plugin/{plugin,marketplace}.json 0.16.0 → 0.38.0. SECURITY.md
supported version 0.14.x → 0.38.x.
feat: ship KeiSei tamagotchi statusline into the kit
- scripts/keisei-pet{,-update}.sh (portable, state under ~/.claude/pet/)
- install copies them to ~/.claude/scripts/
- settings-snippet adds statusLine (set-if-absent, never clobbers an
existing one) + 4 pet-update hooks (prompt/rust_write/github_block/sleep)
Verified: clean minimal install RC=0, zero FAIL, 38 agents + 52 hooks +
68 skills, settings valid, statusLine wired, pet renders, idempotent re-run.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>