Skip to content

[SDK-776] One set of words, and a way to read them - #25

Merged
franco-zalamena-iterable merged 7 commits into
mainfrom
text/one-set-of-words
Oct 7, 2026
Merged

franco-zalamena-iterable merged 7 commits into
mainfrom
text/one-set-of-words

Conversation

@franco-zalamena-iterable

@franco-zalamena-iterable franco-zalamena-iterable commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Makes onboarding language a reviewable surface with one shared set of questions for the
terminal wizard and coding-agent conversation.

  • Shares question rendering and option behavior between both front ends.
  • Moves the opening screen's writer-facing copy into validated Markdown.
  • Adds offline commands for listing, rendering, and locating every shared question.
  • Gives Docs and engineering contributors an explicit copy-review workflow.
  • Separates installed-user documentation from contributor and architecture references.

Shared questions

q_render and ask_question in bin/questions.sh render the same question objects that
the coding-agent path receives. The wizard uses those objects for shared steps instead of
maintaining a second version of their wording.

Option labels and descriptions are presentation. Commands, consent records, option effects,
and state transitions remain behavior owned by the shell program.

Some terminal interactions still have their own presentation where the terminal and chat
have different data or capabilities. tests/agent-questions.sh counts those exceptions so
adding another requires an explicit decision.

Writer-facing Markdown

This PR introduces copy/screens/ and moves the opening screen into
copy/screens/opening.md.

bin/screen-copy.sh reads and validates the constrained Markdown format. Stable option IDs
connect labels, descriptions, and ordering in Markdown to commands and state changes in
bin/questions.sh; changing the words cannot silently attach an option to different
behavior.

Only the opening screen has moved so far. Unmigrated question copy remains in
bin/questions.sh and can move one screen at a time.

Reviewing the copy

From the repository root:

make screens-help
make screens
make screens KIND=opening
make screens KIND=pick_device
make screens KIND="iterable_step 3"

make screens-help lists every supported scenario and its source. make screens renders
the shared onboarding questions as a developer sees them, with sample Firebase projects and
devices and a source location above each question.

The preview requires Node.js, but no network access, credentials, Firebase or Iterable
project, or connected device. It renders live from the Markdown and shell sources and does
not store a second generated copy.

make screens covers shared questions and options, not every user-facing string. The source
map in CONTRIBUTING.md also identifies gate verdicts, summaries, Iterable dashboard
instructions, and terminal- or agent-specific text.

Documentation structure

  • README.md is now focused on installation, supported workflows, requirements, security
    boundaries, limitations, and updates for installed users.
  • CONTRIBUTING.md is the entry point for Docs and engineering contributors reviewing
    human-facing or model-facing content.
  • bin/README.md is an engineering reference for the onboarding program's invariants,
    components, protocol, consent, gates, workspace, and tests.
  • INTENDED-FLOW.md remains the authoritative contract for the onboarding sequence.

The security language now describes what this repository controls without making guarantees
about a coding-assistant provider or claiming that authenticated API requests never leave
the machine.

Validation

Coverage includes:

  • tests/agent-questions.sh for parity between chat and terminal questions.
  • Expect suites for interactive selection and decline behavior.
  • tests/text-surface.sh for scenario discovery, source locations, Markdown structure,
    stable option IDs, placeholders, and gate-name display limits.
  • tests/no-bare-commands.sh for commands that resolve from an installed user's project.
  • tests/plugin-manifests.sh for synchronized plugin delivery versions.

Local result:

22 suites ok (478 checks), 0 failed, 2 skipped, 1 network-backed check not run

GitHub's shell and validate checks pass.

Delivery

The Claude and Cursor manifests are synchronized at 26.10.0-beta. The plugin version
changes because installed clients skip an update when their installed version matches the
manifest, and this PR changes files delivered with the plugin.

The terminal wizard carried its own wording for every moment the chat path
already had a screen for. The sign-in step said "I never see your password —
gcloud opens your browser and handles it" in a terminal and "You run it, your
browser handles it" in a chat; neither was the other's source, and nothing
noticed, because the test suite pinned which screens exist and never which words
they use. So "look in bin/questions.sh to change what a developer reads" was
false for half the people reading it.

Two functions, in questions.sh where the screens are rather than in config.sh
which the gates also source: q_render prints a question's words, and
ask_question feeds its option labels to the menu and reports which came back.
Split in two so that "the terminal prints what the chat is handed" can be
asserted offline — tied to the menu it needs a pty, and a test that needs a pty
to check a sentence is a test that ends up skipped, which is how this drifted.

The wizard now renders the sign-in and remembered-target screens outright, and
the device step takes its words from the screen while drawing its own menu: a
chat picker is capped at four options with free text for the rest, and copying
that cap into a terminal would have made a fourth device unreachable.

q_sign_in's first option is relabelled "Sign in with gcloud". "Show me the
command to run" was true in a chat and wrong in the terminal that hosts the
command; what differs between the front ends moved into the option description,
which a chat shows and a menu does not.

Five moments still word themselves, each because the two paths reach them
differently — the project and app menus draw from a discovered.json the wizard
does not write, and bin/agent has no verb that deletes the local key, so a
shared "delete it?" screen would have nothing behind its yes. The count is
asserted, so a sixth has to be either a screen or a reason.

Found while testing: ask_question set its output variables after question_for,
so an unknown kind returned 2 with them unset and set -u killed the caller.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Where are the texts coming from?" had no answer you could act on. The words
are in bin/questions.sh, but they are JSON assembled by shell functions with
state in them, so seeing what a developer is actually shown meant running the
agent and answering your way to each screen.

`make screens` prints all seventeen of them, each headed by the file and line
its words live on. Read it, change the line it names, run it again.

Nothing is stored. A committed dump would be a second copy of the words to
keep true, and once behind it is worse than no dump at all: it shows you text
without telling you where to type. Same reason the list of screens is read out
of question_for's own dispatch rather than written down here again.

The fixtures are a stub toolchain, a sample discovery cache of five projects
(five because at four the pickers start saying "N more not shown", which is
one of the sentences worth reading), and a stub emulator, so the same command
prints the same text to two people reading it together.

tests/screens-resolve.sh guards the pointer rather than the prose — the
wording is already checked against the JSON in agent-questions.sh. What it
catches is the addresses going quiet: a screen the tool cannot place, a
function dropped because its definition was reformatted, a dispatch the list
can no longer read, and the fixtures breaking so it renders nothing at all.
All four were checked by breaking them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Answers the question this set of changes started from — "where are the texts
for the prompts coming from?" — in the file a maintainer already reads, rather
than in a new document. Four places hold nearly all of it, `make screens`
prints the questions with their addresses, and a rewording is a one-place edit
because both front ends now render the same objects.

Two limits get written down because the text itself cannot tell you about
them: a gate name is printed into a 34-column field, so a longer one shoves
that row's verdict out of line while every other row stays put; and nothing
printed may tell somebody to run a bare `bin/…` path, which does not resolve
from the project the tool actually runs in.

The first of those had nothing checking it, so the suite that checks the
addresses now checks it too — renamed text-surface.sh, since it is no longer
only about tools/screens. Both halves negative-tested: a name one character
over fails, and so does a ladder declared some other way, which would
otherwise pass by finding no names at all.

Explicitly not a second contract. INTENDED-FLOW.md says what the path is;
this says what the words currently are, and says so where a reader will see
it — two documents claiming the flow is how the sixteen-versus-eighteen-gates
disagreement got started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bin/wizard and bin/questions.sh both changed, and a host skips an update when
the version string matches what it already has. 26.9.12-beta is what is on
main, so without this the terminal front end would keep reading its old,
separate set of words on every machine that already has the plugin.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@franco-zalamena-iterable franco-zalamena-iterable changed the title One set of words, and a way to read them [SDK-776] One set of words, and a way to read them Oct 1, 2026
@franco-zalamena-iterable
franco-zalamena-iterable merged commit f479959 into main Oct 7, 2026
2 checks passed
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