Skip to content

mattstack.app installer: spec, contract, lane plans (docs only) - #6

Merged
m4ttheweric merged 12 commits into
mainfrom
docs/mattstack-app-installer-spec
Aug 21, 2026
Merged

m4ttheweric merged 12 commits into
mainfrom
docs/mattstack-app-installer-spec

Conversation

@m4ttheweric

@m4ttheweric m4ttheweric commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator

Design + plans for mattstack.app as suite installer/onboarding/permissions/updater (MAT-383 phase 2). Docs only — no code.

  • docs/superpowers/specs/2026-08-20-mattstack-app-installer-design.md — ratified 2026-08-20 (16 rulings + V1–V5), validated against Linear + full setup survey, reconciled with the home-repo/settings program.
  • docs/superpowers/specs/2026-08-21-rt-setup-contract.md — rt ↔ app JSON contract v1.
  • docs/superpowers/plans/2026-08-21-{rt-setup-verbs,mattstack-app-shell,release-pipeline,clean-room-vm}.md + cross-plan-review.md (ownership matrix, execution order, amendments applied).
  • docs/superpowers/specs/research/2026-08-20-mattstack-app/ — research records.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Documented the native macOS installer experience, including onboarding, permissions, updates, services, team setup, restore, and uninstall flows.
    • Defined the rt setup contract for planning, applying, verifying, and managing installations.
    • Added guidance for dependency bundling, secrets, invitations, artifacts, and development mode.
  • Documentation

    • Added research on installer architecture, macOS permissions, launch services, distribution, dependencies, and onboarding UX.
    • Added a cross-plan review identifying interface mismatches, ownership overlaps, dependencies, and required decisions.

m4ttheweric and others added 12 commits August 20, 2026 23:08
…6-08-20) + research records

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sions, onboarding gaps folded in

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… V5 home repo; L2/L5 shrink)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…onc, linear team deleted, clone-activated tracking, in-process reads)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… relay URL

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… swept

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fixed, R1–R5 decided, execution order

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@m4ttheweric
m4ttheweric merged commit 37a4e29 into main Aug 21, 2026
1 of 2 checks passed
@coderabbitai

coderabbitai Bot commented Aug 21, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ccf7e89-aa33-4fd1-8e62-c6504a9c35cd

📥 Commits

Reviewing files that changed from the base of the PR and between 3a1766b and 86a951e.

📒 Files selected for processing (12)
  • docs/superpowers/plans/2026-08-21-clean-room-vm.md
  • docs/superpowers/plans/2026-08-21-cross-plan-review.md
  • docs/superpowers/plans/2026-08-21-mattstack-app-shell.md
  • docs/superpowers/plans/2026-08-21-release-pipeline.md
  • docs/superpowers/plans/2026-08-21-rt-setup-verbs.md
  • docs/superpowers/specs/2026-08-20-mattstack-app-installer-design.md
  • docs/superpowers/specs/2026-08-21-rt-setup-contract.md
  • docs/superpowers/specs/research/2026-08-20-mattstack-app/research-dependency-inventory.md
  • docs/superpowers/specs/research/2026-08-20-mattstack-app/research-linear-rulings.md
  • docs/superpowers/specs/research/2026-08-20-mattstack-app/research-local-inventory.md
  • docs/superpowers/specs/research/2026-08-20-mattstack-app/research-onboarding-permissions-ux.md
  • docs/superpowers/specs/research/2026-08-20-mattstack-app/research-sparkle-install-launchd.md

📝 Walkthrough

Walkthrough

The PR adds a ratified macOS installer design, a v1 rt setup contract, supporting dependency and platform research, and a cross-plan review that aligns implementation lanes, interfaces, release behavior, and unresolved decisions.

Changes

Installer design and execution plan

Layer / File(s) Summary
Product scope and environment research
docs/superpowers/specs/2026-08-20-mattstack-app/*, docs/superpowers/specs/research/2026-08-20-mattstack-app/research-dependency-inventory.md, research-linear-rulings.md, research-local-inventory.md
Defines the signed app front door, repository model, dependencies, existing architecture, platform requirements, and clean-Mac conditions.
Onboarding, permissions, and shared state
docs/superpowers/specs/2026-08-20-mattstack-app-installer-design.md, docs/superpowers/specs/research/2026-08-20-mattstack-app/research-onboarding-permissions-ux.md
Defines onboarding screens, readiness checks, team and invite flows, macOS permission handling, repository setup, and encrypted secret storage.
rt setup and integration contract
docs/superpowers/specs/2026-08-21-rt-setup-contract.md, docs/superpowers/specs/2026-08-20-mattstack-app-installer-design.md
Defines rt invocation, JSON and NDJSON shapes, setup actions, tray routes, team operations, restore handling, uninstall behavior, and debug scenarios.
Dependencies, services, release, and uninstall
docs/superpowers/specs/2026-08-20-mattstack-app-installer-design.md, docs/superpowers/specs/research/2026-08-20-mattstack-app/research-sparkle-install-launchd.md
Defines dependency bundling, PATH links, launchd and SMAppService registration, Sparkle artifacts, signing, update behavior, test gates, and cleanup.
Cross-plan alignment and implementation governance
docs/superpowers/plans/2026-08-21-cross-plan-review.md, docs/superpowers/specs/2026-08-20-mattstack-app-installer-design.md
Records interface drift, lane ownership, task amendments, merge order, dependencies, and five decisions requiring resolution.

Estimated code review effort: 3 (Moderate) | ~25 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/mattstack-app-installer-spec

Comment @coderabbitai help to get the list of available commands.

m4ttheweric added a commit that referenced this pull request Aug 22, 2026
…DME drift, escaping, log collision)

#1: walkthrough.sh's cleanup() defaulted a missing phases.jsonl to success
via ${f:-0}, so dying before the first vm_phase_end (e.g. no tart on a
fresh machine) exited 0 with an empty report. Dropped the default so a
missing ledger fails the `[ -eq 0 ]` test and falls through to exit 1,
matching xcuitest.sh's existing fail-closed form. Pre-existing on main;
reproduced the before/after with the review's no-tart repro.

#2/#9: README described ax.sh/drive-setup.sh/trigger-update.sh as not yet
in the tree and misattributed the screens-phase failure to an unstaged
guest script; all three are staged into $GUEST_BIN by walkthrough.sh today.
Corrected the Status/Layout prose to state what's actually gating
`--scenario create/join` (L3's setup screens) and the update phase (L3's
MATTSTACK_APPCAST_URL hook). Also corrected the disk-footprint line: the
~60 GB figure is cleanroom-only, and an --xcode golden needs substantially
more (full Xcode install on top of the base OS).

#3: check-vm-scripts.sh's ax.sh syntax-error net only matched "script
error"/"Expected " literally, missing other osascript compile-failure
shapes (e.g. "syntax error: A property can't go after..."). Widened to a
bare "syntax error" alternative, which osascript writes for every compile
failure and never for a runtime error.

#4: ax_click_button_named defaulted its process arg to the already-escaped
$AX_APP, then ran ax_esc on it again, double-escaping any AX_APP containing
a quote or backslash. Now only escapes when an explicit (raw) $2 is given.

#6: build-golden.sh's tart boot log was named golden-$VER-tart.log for both
flavours, so an --xcode build silently overwrote the cleanroom golden's
boot log. Named it after $GOLDEN instead, which already carries the -xcode
suffix.

Findings #5 (VM_APPCAST_PORT default duplication), #7 (--ver not
version-validated), #8 (xcuitest.sh's guest-staging convention), and #10
(PAT/password on guest ssh argv) are parked per the reviewer's ruling —
not touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 22, 2026
R-T7-a (#1): tool.daemon's launchd/worktrees sub-facts are real negative
signals now, not folded into a "ready" detail — either failing flips the
row to "invalid" with the specific fact named.

R-T7-b (#4): the legacy split-state branch (required, invalid) carries a
{type:"steps"} merge-by-hand remedy instead of action:null; the detail also
gets verify's plural handling back.

R-T7-c (#6): fixes the bundle-memo hazard at its source. appBundleRoot()
(lib/bundle-layout.ts) now memoizes only the true default
(exists === existsSync); an injected exists (every Probes-driven caller)
never reads or writes it. Validator tests drop the reset ceremony this made
unnecessary.

R-T7-d (#12): tool.rt-link's needs-you branch carries a {type:"run"} action
to fix the link in one step.

#2/#3: tool.fzf and tool.rt now distinguish "genuinely absent" (127) from
"resolved but won't run" (any other exit) — the latter is "error", never
"ready"/"missing".

#5: tool.daemon and tool.app get recheck:"on-activate" (Task 6's convention
for out-of-band, leave-the-app-and-come-back rows).

#7: the five optional rows carry real optionalNotes.

#8: tool.app's legacy note names the exact hit path(s), matching verify's
phrasing.

#9: interceptsRow wraps shimReport()/staleIntercepts() so a throw degrades
to an "error" row instead of rejecting the whole plan.

#10: tool.daemon's Login Items action is imported from permissions.ts
(now exported as LOGIN_ITEMS_SETTINGS_ACTION) instead of a duplicate
literal.

#11: lib/shell-integration.ts gains detectShellFrom()/shellRcPathFor(),
pure functions the real detectShell()/shellRcPath() now delegate to and
tool.shell reuses over Probes; an unrecognized shell gets an honest
"can't write automatically" detail instead of "Install writes it".

#13: the tool.daemon describe saves/restores DAEMON_CONFIG_PATH's
pre-existing content around the whole block instead of only deleting it,
so status-fallback.test.ts's absence assumption can't be poisoned.

#14/#15: header comment no longer cites the brief's table, the rt-link
"no app" test asserts its reason string, and commands/verify.ts's docblock
is trimmed to the one load-bearing line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
mattstack.app installer: spec, contract, lane plans (docs only)
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
…DME drift, escaping, log collision)

#1: walkthrough.sh's cleanup() defaulted a missing phases.jsonl to success
via ${f:-0}, so dying before the first vm_phase_end (e.g. no tart on a
fresh machine) exited 0 with an empty report. Dropped the default so a
missing ledger fails the `[ -eq 0 ]` test and falls through to exit 1,
matching xcuitest.sh's existing fail-closed form. Pre-existing on main;
reproduced the before/after with the review's no-tart repro.

#2/#9: README described ax.sh/drive-setup.sh/trigger-update.sh as not yet
in the tree and misattributed the screens-phase failure to an unstaged
guest script; all three are staged into $GUEST_BIN by walkthrough.sh today.
Corrected the Status/Layout prose to state what's actually gating
`--scenario create/join` (L3's setup screens) and the update phase (L3's
MATTSTACK_APPCAST_URL hook). Also corrected the disk-footprint line: the
~60 GB figure is cleanroom-only, and an --xcode golden needs substantially
more (full Xcode install on top of the base OS).

#3: check-vm-scripts.sh's ax.sh syntax-error net only matched "script
error"/"Expected " literally, missing other osascript compile-failure
shapes (e.g. "syntax error: A property can't go after..."). Widened to a
bare "syntax error" alternative, which osascript writes for every compile
failure and never for a runtime error.

#4: ax_click_button_named defaulted its process arg to the already-escaped
$AX_APP, then ran ax_esc on it again, double-escaping any AX_APP containing
a quote or backslash. Now only escapes when an explicit (raw) $2 is given.

#6: build-golden.sh's tart boot log was named golden-$VER-tart.log for both
flavours, so an --xcode build silently overwrote the cleanroom golden's
boot log. Named it after $GOLDEN instead, which already carries the -xcode
suffix.

Findings #5 (VM_APPCAST_PORT default duplication), #7 (--ver not
version-validated), #8 (xcuitest.sh's guest-staging convention), and #10
(PAT/password on guest ssh argv) are parked per the reviewer's ruling —
not touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
R-T7-a (#1): tool.daemon's launchd/worktrees sub-facts are real negative
signals now, not folded into a "ready" detail — either failing flips the
row to "invalid" with the specific fact named.

R-T7-b (#4): the legacy split-state branch (required, invalid) carries a
{type:"steps"} merge-by-hand remedy instead of action:null; the detail also
gets verify's plural handling back.

R-T7-c (#6): fixes the bundle-memo hazard at its source. appBundleRoot()
(lib/bundle-layout.ts) now memoizes only the true default
(exists === existsSync); an injected exists (every Probes-driven caller)
never reads or writes it. Validator tests drop the reset ceremony this made
unnecessary.

R-T7-d (#12): tool.rt-link's needs-you branch carries a {type:"run"} action
to fix the link in one step.

#2/#3: tool.fzf and tool.rt now distinguish "genuinely absent" (127) from
"resolved but won't run" (any other exit) — the latter is "error", never
"ready"/"missing".

#5: tool.daemon and tool.app get recheck:"on-activate" (Task 6's convention
for out-of-band, leave-the-app-and-come-back rows).

#7: the five optional rows carry real optionalNotes.

#8: tool.app's legacy note names the exact hit path(s), matching verify's
phrasing.

#9: interceptsRow wraps shimReport()/staleIntercepts() so a throw degrades
to an "error" row instead of rejecting the whole plan.

#10: tool.daemon's Login Items action is imported from permissions.ts
(now exported as LOGIN_ITEMS_SETTINGS_ACTION) instead of a duplicate
literal.

#11: lib/shell-integration.ts gains detectShellFrom()/shellRcPathFor(),
pure functions the real detectShell()/shellRcPath() now delegate to and
tool.shell reuses over Probes; an unrecognized shell gets an honest
"can't write automatically" detail instead of "Install writes it".

#13: the tool.daemon describe saves/restores DAEMON_CONFIG_PATH's
pre-existing content around the whole block instead of only deleting it,
so status-fallback.test.ts's absence assumption can't be poisoned.

#14/#15: header comment no longer cites the brief's table, the rt-link
"no app" test asserts its reason string, and commands/verify.ts's docblock
is trimmed to the one load-bearing line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Sep 17, 2026
mattstack.app installer: spec, contract, lane plans (docs only)
m4ttheweric added a commit that referenced this pull request Sep 17, 2026
…DME drift, escaping, log collision)

#1: walkthrough.sh's cleanup() defaulted a missing phases.jsonl to success
via ${f:-0}, so dying before the first vm_phase_end (e.g. no tart on a
fresh machine) exited 0 with an empty report. Dropped the default so a
missing ledger fails the `[ -eq 0 ]` test and falls through to exit 1,
matching xcuitest.sh's existing fail-closed form. Pre-existing on main;
reproduced the before/after with the review's no-tart repro.

#2/#9: README described ax.sh/drive-setup.sh/trigger-update.sh as not yet
in the tree and misattributed the screens-phase failure to an unstaged
guest script; all three are staged into $GUEST_BIN by walkthrough.sh today.
Corrected the Status/Layout prose to state what's actually gating
`--scenario create/join` (L3's setup screens) and the update phase (L3's
MATTSTACK_APPCAST_URL hook). Also corrected the disk-footprint line: the
~60 GB figure is cleanroom-only, and an --xcode golden needs substantially
more (full Xcode install on top of the base OS).

#3: check-vm-scripts.sh's ax.sh syntax-error net only matched "script
error"/"Expected " literally, missing other osascript compile-failure
shapes (e.g. "syntax error: A property can't go after..."). Widened to a
bare "syntax error" alternative, which osascript writes for every compile
failure and never for a runtime error.

#4: ax_click_button_named defaulted its process arg to the already-escaped
$AX_APP, then ran ax_esc on it again, double-escaping any AX_APP containing
a quote or backslash. Now only escapes when an explicit (raw) $2 is given.

#6: build-golden.sh's tart boot log was named golden-$VER-tart.log for both
flavours, so an --xcode build silently overwrote the cleanroom golden's
boot log. Named it after $GOLDEN instead, which already carries the -xcode
suffix.

Findings #5 (VM_APPCAST_PORT default duplication), #7 (--ver not
version-validated), #8 (xcuitest.sh's guest-staging convention), and #10
(PAT/password on guest ssh argv) are parked per the reviewer's ruling —
not touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Sep 17, 2026
R-T7-a (#1): tool.daemon's launchd/worktrees sub-facts are real negative
signals now, not folded into a "ready" detail — either failing flips the
row to "invalid" with the specific fact named.

R-T7-b (#4): the legacy split-state branch (required, invalid) carries a
{type:"steps"} merge-by-hand remedy instead of action:null; the detail also
gets verify's plural handling back.

R-T7-c (#6): fixes the bundle-memo hazard at its source. appBundleRoot()
(lib/bundle-layout.ts) now memoizes only the true default
(exists === existsSync); an injected exists (every Probes-driven caller)
never reads or writes it. Validator tests drop the reset ceremony this made
unnecessary.

R-T7-d (#12): tool.rt-link's needs-you branch carries a {type:"run"} action
to fix the link in one step.

#2/#3: tool.fzf and tool.rt now distinguish "genuinely absent" (127) from
"resolved but won't run" (any other exit) — the latter is "error", never
"ready"/"missing".

#5: tool.daemon and tool.app get recheck:"on-activate" (Task 6's convention
for out-of-band, leave-the-app-and-come-back rows).

#7: the five optional rows carry real optionalNotes.

#8: tool.app's legacy note names the exact hit path(s), matching verify's
phrasing.

#9: interceptsRow wraps shimReport()/staleIntercepts() so a throw degrades
to an "error" row instead of rejecting the whole plan.

#10: tool.daemon's Login Items action is imported from permissions.ts
(now exported as LOGIN_ITEMS_SETTINGS_ACTION) instead of a duplicate
literal.

#11: lib/shell-integration.ts gains detectShellFrom()/shellRcPathFor(),
pure functions the real detectShell()/shellRcPath() now delegate to and
tool.shell reuses over Probes; an unrecognized shell gets an honest
"can't write automatically" detail instead of "Install writes it".

#13: the tool.daemon describe saves/restores DAEMON_CONFIG_PATH's
pre-existing content around the whole block instead of only deleting it,
so status-fallback.test.ts's absence assumption can't be poisoned.

#14/#15: header comment no longer cites the brief's table, the rt-link
"no app" test asserts its reason string, and commands/verify.ts's docblock
is trimmed to the one load-bearing line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Sep 17, 2026
Ruling #6. After the fuzzy Rank, GroupContiguous stable-partitions the
matched rows into one contiguous block per group so a group renders under
one header instead of score interleaving repeating it down the list. Block
order follows the caller's group order (first appearance in the unranked
rows), so run's queue group stays pinned above packages; within a block the
Rank score order is preserved.

With contiguity restoring one header per group, revert the grouped height
reservation from chrome + 2*rowCap back to chrome + rowCap +
distinctGroupCount (any window now shows at most distinctGroupCount
headers). Leaves the F2 interior filler, pinFrameHeight, and the quit-erase
alone. Also refresh the openRegistryMenu doc to point at deriveMenu as the
authority on which actions stay keybar-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Sep 26, 2026
* deps: rt-client ^0.14.0, declare glance ^0.24.0 peer

Supersedes renovate #6 (which only proposed rt-client ^0.13.0). Follows
the console pattern: go to rt-client ^0.14.0 (latest) and declare the
glance ^0.24.0 peer explicitly so it's visible and renovate-trackable,
since renovate only bumps what's declared.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* format: prettier scripts/sync-probe-refs.ts (unblock format:check CI)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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