feat(install): install Pi when missing, ask before replacing it - #18
Closed
lucy-wolfe wants to merge 14 commits into
Closed
feat(install): install Pi when missing, ask before replacing it#18lucy-wolfe wants to merge 14 commits into
lucy-wolfe wants to merge 14 commits into
Conversation
The word is a claim about whose fault the failure was, and the two invite opposite recoveries: refused invites a corrected call, failed invites a retry. Calling a crash a refusal is the worse direction, because it sends somebody to fix a call that was never wrong. The verb follows the classification rather than a list, so a refusal added next month gets the right word without anyone remembering. One predicate in one place: three renderers build a failure title, and two of them are bespoke titles that would otherwise have kept saying failed for a refusal -- the both-arms property again, found by sweeping for the word rather than trusting the default path to be the only one. One case was not what the classification said. A partial hire carries a status so the card can name the people already hired, which a retry needs so it does not double-hire them -- but the error it wraps may be a genuine crash. A status carried for CONTEXT is not a claim about fault. That path now asks the wrapped error's own type, and a producer in the same position marks itself rather than being enumerated in the renderer, because a list is where the next case is missed. Pinned by a discriminating pair: a classified refusal is refused, an unclassified failure is not, and a context-carried status with fault:true is not. Verified by mutation -- making the predicate return true fails both negative cases. Checked the collapsed card: the verb is one character longer and the title is not what gets truncated, so no card's summary window moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ed a default The field was REQUIRED under a description opening 'DEFAULT: the department YOU head'. An agent read that, reasoned correctly that it should omit the field, met a schema that would not allow it, and improvised the most salient name in context -- the company's. It obeyed the instrument over the claim, which is the right thing for it to do. The field is optional now and the default is resolved in execute using the helper that already existed: the department the caller heads, or failing that the one they sit in. That is word-for-word what the description promised, so the promise was always implementable and simply was not implemented. The worked example now shows the omitted form first. An example that keeps passing the field re-teaches the habit the description is trying to correct. The sweep asked the general question of every parameter in the file -- does the schema permit what the prose promises -- across DEFAULT, omit, omitted, optional and leave empty. Exactly one leaf field disagreed: this one. The only other hit says 'never omit this field' and is required, so its prose and schema agree. No mechanical guard was added: an instrument for a class of one is furniture. My first sweep reported sixteen mismatches. All but one were container objects matching on a nested field's prose -- the detector measured a property adjacent to the question. Refining it to leaf fields gave the real answer. Also caught by an existing guard: the longer tool description exceeded the 1024 characters a strict provider accepts. Trimmed to 993 rather than expanded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ng past a lecture What it is in two sentences, the animation, install, and the first company now lead the page. Depth moved into short skimmable sections or linked docs: the crate table went to docs/ARCHITECTURE.md, which already carries it, and the long GIF caption and quick-start asides were trimmed. New: an Everyday commands table, derived from the routed operator verbs in chief-cli's OPERATOR_VERBS, and a Contributing section naming the two open workstreams (finishing apps/web, and multi-machine hosting so one busy company stops pegging a single box's CPU) plus the issue tracker and CONTRIBUTING.md. Every command documented was checked against install.sh and the routed verb table. The Pi floor line keeps Pi and 0.80.10 on one line for pi-floor-single-definition.test.mjs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
The verb moved to the fault marker and the tag did not. The tag still measured only the ABSENCE of a status, so a partial batch carrying one for context while wrapping a real crash said "failed" -- correctly -- and then dropped the crash marker. Somebody debugging that would see a list of people already hired, no fault marker, and reasonably conclude they had passed bad input. One classification, two surfaces. The tag now reads the same marker, and a test asserts the two are complementary rather than merely each correct: nothing may be both a refusal and a system fault, which fails if either rule moves without the other. Verified by mutation -- putting the tag back on the old instrument fails the crash case and only that case. This was the scope note I flagged rather than fixed in the first pass. Review ruled it fix-here, and that was right: shipping the verb on the new instrument and the tag on the old one is a divergence nobody would find again except by hitting it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The installer already edits the shell profile and reports exactly which file it touched, so the extra line was a second copy of work the script does itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
The animation speaks for itself; the recording provenance note is not needed on the front page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
Three steps a stranger can paste in order: Pi, chief, first company. The Pi floor stays on one line with the name for the pi-floor guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
Step 3 says what the first run is (Founder, two questions, then the CEO boots) and step 4 says what every later run is (the same bare chief starts and attaches the company). The transition is the part a stranger cannot guess from the command alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
…s Pi (#1) The Pi step collapses into a single sentence: the installer installs a missing Pi and asks before upgrading an old one. The version number leaves the README entirely; the floor's single definition stays in pi_floor.rs, and CONTRIBUTING.md remains the document that quotes it. Depends on the installer change (PR tribes-protocol#18) riding in the same integration branch; without it this page describes behavior install.sh does not have. Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh> Co-authored-by: Lucy Wolfe <lucy@zbox.sh> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
lucy-wolfe
force-pushed
the
feat/installer-manages-pi
branch
from
August 28, 2026 17:08
efa79b2 to
75f46e3
Compare
This was referenced Aug 28, 2026
lucy-wolfe
force-pushed
the
feat/installer-manages-pi
branch
from
August 28, 2026 17:27
75f46e3 to
f73571c
Compare
A busy person now reads an ordinary message at the next step boundary inside the running turn instead of at the end of it. The operator typing mid-turn has always been submitted as a steering message and consumed within seconds; ordinary mail rode the follow-up queue, which Pi consumes only once the agent has no more tool calls or steering messages. So somebody an hour into a piece of work did not see a teammate's message until the hour was over, while the identical words typed by the operator arrived immediately. Interrupt mail already rode the steering lane, so this widens a production-proven path rather than building one. The digest is untouched: batching is still the answer to twenty messages in one turn, and only the moment of consumption moved. Verified before changing anything, because it would have been a real blocker: the delivery receipt hangs off message_start, not turn_start, so it is written wherever the message is consumed. Interrupts have been consumed mid-turn in production all along and receipted through that same handler, so a normal envelope takes an identical path. Three call sites were considered and two moved. The work-resume prompt keeps follow-up and says why: nobody is waiting on it and it asks the person to pick their own work back up. The input-requeue rescue and the printed-tool-call corrective keep theirs, with rationales already written down that remain true. An unreachable ternary went with it: normal urgency is routed away three lines above the interrupt delivery, so its false arm could never be taken even before this change. The change was unpinnable as written, so it was made pinnable. The delivery table was already covered, but the mode passed into it was two string literals at two call sites -- so the timing of every delivery in the product could change without one test noticing, which is exactly what happened when the first implementation went green. It is one named decision now, with a test that asserts the rule and fails when the mode is reverted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat(intercom): mail rides the same queue as the operator's own typing
The installer printed a command and hoped. It handles Pi now, and the asymmetry
is the decision: an ABSENT Pi is installed with no prompt, because chief cannot
run a single person without it and there is nothing to weigh; an EXISTING Pi
that is merely below the floor belongs to the user, and replacing a working
tool without asking is a different act, so that one prompts with a default of
yes. Declining exits nonzero -- a zero status would tell a calling script the
box is ready when the runtime every person needs is too old.
The floor is read from the release manifest, which the release process already
stamps from the single Rust definition. A version bump needs no edit here, and
the single-definition guard is satisfied rather than worked around.
Two shell facts, both learned by running the branches rather than reading them,
and both of which end the installer silently if got wrong:
A prompt in a script that is piped into sh must read /dev/tty, because stdin is
the script text and reading it would consume the rest of the installer.
And /dev/tty must be tested by OPENING it, inside a SUBSHELL. The node exists
in a container with no controlling terminal, so `[ -r /dev/tty ]` is true and
the redirect then fails; worse, `{ : < /dev/tty; }` uses a POSIX special
built-in, and a redirection error on one is fatal to a non-interactive shell --
it does not evaluate to false, it ENDS THE RUN with status 2 and no message.
Measured both: first as raw shell errors printed to the user, then as a trace
that stopped dead at the call.
npm missing refuses cleanly rather than half-installing, and a Pi that npm
reports as installed is checked against the floor before being called ready.
Verified by running every branch: absent Pi; at floor; above floor; below floor
answering y, bare Enter, and n (exit 1 with a clear message); below floor with
no terminal; below floor with no npm; and a manifest carrying no floor at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lucy-wolfe
force-pushed
the
feat/installer-manages-pi
branch
from
August 28, 2026 17:40
f73571c to
0a53ba2
Compare
Contributor
Author
|
Merged into the v0.5.7 integration branch and shipping in #16. The commit is on that branch verbatim; GitHub could not retarget this pull request because a cross-fork PR's base must live in the base repository, and the integration branch lives on the fork. The review that happened here stands. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The installer printed a command for Pi and hoped. It handles it now.
Upgrade Pi to >= <floor>? [Y/n], default yesThe asymmetry is the decision. An absent prerequisite is installed without asking, because chief cannot run a single person without it and there is nothing for the user to weigh. A Pi that is merely too old is their working tool, and replacing it is a different act — so that one asks. Declining exits nonzero with a clear message: a zero status would tell a calling script the box is ready when the runtime every person needs is too old.
The floor is read, never restated
It has one definition, in
pi_floor.rs, and the repository's guard bans copying that number into scripts — rightly, because a copy is a second definition wearing a copy's clothes.Verified before building on it: the release process already stamps it into the manifest as
piFloor, and that is pinned by tests. The installer reads it from the manifest it has just unpacked, so a version bump touches no shell script. A release whose manifest carries no floor simply skips the check rather than guessing.Two shell facts, both learned by running the branches
Both end the installer silently if got wrong, and neither is visible by reading.
A prompt in a piped script must read
/dev/tty. This file iscurl … | sh, so stdin is the script text — reading stdin would consume the rest of the installer.And
/dev/ttymust be tested by opening it, inside a subshell. The device node exists in a container with no controlling terminal, so[ -r /dev/tty ]is true and the redirect then fails. Worse, the obvious guard is fatal::is a POSIX special built-in, and a redirection error on one is fatal to a non-interactive shell. It does not evaluate to false — it ends the installer. Measured twice: first as raw shell errors printed above the question, then as a trace stopping dead at the call.Where there is no terminal, the default is taken and said, because a silent choice made on somebody's behalf is what surprises them later.
The other two failure modes
npmmissing refuses cleanly with the existingdie()style rather than half-installing.Nothing after chief itself is installed aborts the run, except the one deliberate decline.
Verified by running every branch
Absent Pi · at floor · above floor · below floor answering
y· below floor with bare Enter · below floor answeringn(exit 1, clear message) · below floor with no terminal · below floor with no npm · and a manifest carrying no floor at all.The interactive cases were driven through a real pty, not simulated.
Coordination
The README currently documents installing Pi as step one, because until now the installer only warned. When this lands, that step becomes optional and the quick start collapses to a single
curl.Checks
sh -n install.sh— this file is piped straight into a shell, so a syntax error is a broken install rather than a failed test — plus all 98 repository guards and CI.