ho-04.6 — Plain-prompt init
fell · ho-04.4 — The ingest dashboard
sharibako init shows every secret it finds on one screen and lets the practitioner route all of them from that single view — set each key's fate, bulk-apply to a marked set or the whole list, then commit once. This replaces the per-key arrow walk from ho-04.2, which read fine at three keys and fell apart at twelve.
replaced · ho-04.6 — Plain-prompt init
A plain readLine-based prompt, PlainIngestPrompt, as a new IngestDecisionSource. No raw mode, no alternate screen, no arrow keys — nothing to get stuck in.
sharibako init collects its ingest decisions through a plain line-based prompt instead of a full-screen dashboard. This ho-04.4, whose -rolled scrolling TUI was over-built for a once-per-project command and, on the first real , trapped the practitioner on the first keystroke (see ho-04.4 ). The library seam is unchanged; only the surface changes.
Problem
ho-04.4 built a full-screen, raw-mode, scrolling dashboard as init's ingest surface. It works in tests (405 green) and fails in use: no viewport on short terminals, cycling into a modal that traps the user, an Esc that hangs. The deeper problem is that a hand-rolled TUI is the wrong amount of machine for init — ~600 lines of termios to imitate a spatial table the GUI gets for free. The CLI should be an idiomatic CLI prompt.
Solution
A plain readLine-based prompt, PlainIngestPrompt, as a new IngestDecisionSource. No raw mode, no alternate screen, no arrow keys — nothing to get stuck in.
Flow:
- Print the detected keys as a compact numbered list, with the scope ID and count.
- Ask "Import all N as scope-local? [Y/n]".
Y/Enter imports every key — one keystroke for the dominant case. - On
n, ask "Which to handle differently? numbers (e.g.3,7), blank to import the rest:". For each named key, a one-line choice prompt —[i]mport / [l]ink / [m]ove / [leave] / [s]kip— with the follow-up line for link (pick a shared entry by number) and move (type a slug). Every key not named is imported. - Return
[KeyDecision]in proposal order to the unchangedacceptIngest.
Name-matched keys are noted in the list ("OPENAI_API_KEY → matches shared openai-personal") so the practitioner can choose to link them among the exceptions. Non-TTY still refuses via notInteractiveTerminal (checked through the injected line-reader's context, as the other prompt verbs do). suggestedKeysNeedingValues and parseWarnings print as plain context lines before the prompt.
Approach — rough first, then harden. Applying ho-04.4's lesson: build the prompt minimally and dogfood it on a real terminal before writing the full test suite. Only once the feel is confirmed does the hardening pass add coverage and delete the dashboard. This is deliberately two steps, not one.
Changes
- Create:
Sources/SharibakoCLI/Support/PlainIngestPrompt.swift— theIngestDecisionSource, line-based, with an injected line-reader (mirrorCleanCommand/ValueInput). - Modify:
Sources/SharibakoCLI/Commands/InitCommand.swift—_rundefaultdecisionSourcefromDashboardIngestPrompt()toPlainIngestPrompt(). Nothing else in_runchanges; the seam is stable. - Delete:
Sources/SharibakoCLI/Support/IngestDashboard.swift,Sources/SharibakoCLI/Support/DashboardIngestPrompt.swift, and their tests (Tests/SharibakoCLITests/IngestDashboardTests.swift,DashboardIngestPromptTests.swift) — in the hardening step, after the dogfood confirms the plain prompt. - Create:
Tests/SharibakoCLITests/PlainIngestPromptTests.swift— every branch through the injected line-reader (import-all, exceptions parsing, each of the five choices, link pick, move slug, non-TTY refusal).
Unchanged: IngestDecisionSource, ScriptedIngestDecisionSource, KeyDecision, ProposedScope, acceptIngest, InteractiveSelect, SharibakoCore.
Decomposition: likely one small for the hardening pass (Ho-04.6-AT-01 — tests + dashboard deletion), authored after the rough prompt is dogfooded. The rough prompt itself is small enough to build directly.
Results
Built rough, dogfooded, hardened, closed — in that order.
The dogfood confirmed the feel. The rough prompt ran on a real terminal against the same twelve-key .env that broke the dashboard. It imported all twelve in one keystroke; the exception path (n → 3,7 → per-key choice) routed correctly, and a move slug came back clean — the ho-04.2 corruption that started this whole is gone by construction, since there is no raw mode to leak escape bytes. The practitioner's verdict: "boring but good. I could figure it out." That is the target outcome for a once-per-project command — nothing to learn, nothing to get stuck in.
The hardening pass (2418a98) added 13 PlainIngestPrompt tests through the injected line-reader — import-all, exception-index parsing (dedup, out-of-range), all five choices, link pick, move-slug sanitize, non-TTY refusal, and context lines — then deleted the dashboard (IngestDashboard, DashboardIngestPrompt, and their ~59 tests). The IngestDecisionSource seam made the surface swap a one-line change in InitCommand._run; acceptIngest, KeyDecision, ScriptedIngestDecisionSource, and SharibakoCore never moved. 349 tests, both linters clean.
What held. The seam is the reason a whole surface could be replaced twice (per-key walk → dashboard → plain prompt) with acceptIngest and the library untouched each time. The parts that were right in ho-04.2 — Touch-ID-free ingest, source-.env untouched, scope collision reuse, re-init reconcile, first-run key generation — carried through all three surfaces unchanged, because they live in InitCommand and the library, not in the prompt.
The lesson, kept. The plain prompt was built rough and put in the practitioner's hands before a single test was written. That is the inversion ho-04.4's named — validate rough, then harden — applied directly. init now ships the boring thing that works.
Authored: 2026-07-02.
Executed and closed: 2026-07-03 — rough prompt dogfooded, hardened (2418a98), dashboard removed.
Rendered from the corpus, verbatim · source on GitHub →