Skip to content

fix(tui): welcome preflight passes in installed mode#14

Closed
21tmccauley wants to merge 15 commits into
paramify:mainfrom
21tmccauley:fix/tui-welcome-installed-preflight
Closed

fix(tui): welcome preflight passes in installed mode#14
21tmccauley wants to merge 15 commits into
paramify:mainfrom
21tmccauley:fix/tui-welcome-installed-preflight

Conversation

@21tmccauley

Copy link
Copy Markdown
Collaborator

Problem

On a brew/pipx install, paramify tui now launches — but the welcome screen's animated startup checks fail:

verifying your workspace
  repo root ............ ✗ not found     ← red, on every healthy install
  fetcher catalog ...... —
  run manifests ........ none yet
  evidence uploader .... —

The readout was written when a checkout was the only way to have content. Under the overlay model that's wrong on both ends: no checkout is the normal installed state, and the catalog/uploader work fine without one (api.catalog(None) reads the bundled snapshot + user dir; the uploader ships in the wheel).

Fix

  • "repo root" → "content roots": shows the checkout name in dev mode, ✓ installed bundle (or ✓ installed · N roots once a user dir exists) installed, and only goes red when discovery found no roots at all.
  • The catalog check answers from app.catalog_data regardless of a checkout; the uploader check falls back to importlib.util.find_spec("uploaders.paramify_evidence").
  • New manifest from the welcome screen no longer demands a repo root — api.new_manifest_path(None, ...) already falls back to ./manifests/ (covered by tests/test_roots.py).

Installed mode now settles to the green one-liner: ✓ workspace ok · 109 fetchers · no manifests yet · uploader ready.

Tests

New tests/test_tui_welcome.py drives _resolve_checks through installed / installed+user-dir / dev-checkout / no-content-anywhere (the last still fails red, as it should). Skips cleanly when textual isn't installed.

pytest 238 passed · ruff check framework/ clean · mypy framework/ clean.

🤖 Generated with Claude Code

Tate McCauley and others added 15 commits July 13, 2026 12:16
…content

Plan for shipping the CLI via pipx/Homebrew with user-owned, self-updating content: multi-root fetcher discovery, a hashed workspace manifest, a paramify sync reconcile with .new conflict handling, schema-version migrations, release integration, platform nuances (Mac/Windows/Linux), and a phased prototype plan with an acceptance test.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…y model

The expected customization is creating fetchers for unsupported platforms,
not editing built-ins — so ship read-only bundled content + a writable user
overlay instead of a materialized workspace reconciled by a sync engine.
The no-clobber guarantee becomes structural: upgrades never write where
users do.

The reviewed workspace-sync design moves to docs/deferred/ with its revival
trigger (evidence of customers editing many built-ins in place). Decision
#243 supersedes #223; #224 (content bundled per release) stands.

Co-Authored-By: Claude Fable 5 <[email protected]>
- framework/roots.py: ordered content roots — $PARAMIFY_FETCHERS_PATH →
  dev checkout → $PARAMIFY_HOME/fetchers (platformdirs) → the installed
  bundle (framework/_bundled, shipped by a later commit).
- Discovery walks all roots: the first root wins a name collision, reported
  as a shadow (never silent); within-root duplicates stay a hard error; a
  broken fetcher.yaml is skipped and reported instead of aborting discovery
  (refuse, don't crash). Category files union per-file across roots, so a
  user dir can define entirely new platforms.
- Schemas and ksis.yaml resolve package-relative; every CLI command
  tolerates a missing checkout (api.locate_root); run manifests fall back
  to the cwd. The dev clone outranks the user dir so in-tree edits win.
- paramify create <category>/<name> scaffolds a user fetcher from the
  shipped template; paramify customize <fetcher> is the copy-on-write
  override, with a .customized.json sidecar (source, tool version,
  per-file hashes); doctor gains a distribution section reporting roots,
  shadows, stale/orphaned overrides, and invalid fetchers.

Co-Authored-By: Claude Fable 5 <[email protected]>
setup.py's build_py hook assembles framework/_bundled/ (fetchers + examples;
logos excluded — README furniture) straight into build_lib, so every build
path produces the bundle and the source tree never grows a stale copy.
Package data covers the schemas, the KSI reference, and the TUI stylesheet;
uploaders/ becomes a proper package so paramify upload works installed
(api falls back to the packaged module outside a checkout). MANIFEST.in
keeps sdists — including the GitHub source tarball — complete.

tests/test_installed.py builds the wheel, installs it into an isolated
target, and drives catalog + a real demo_hello run from an empty cwd with
no checkout on disk — the 'green in dev, broken installed' gap, now gated —
plus the user-dir-shadows-bundle override path.

Co-Authored-By: Claude Fable 5 <[email protected]>
Console scripts installed next to the running interpreter — a pipx venv, an
unactivated .venv — were invisible to fetchers: pipx inject checkov lands
the CLI in a bin/ that pipx never puts on PATH, and _build_env passed
children only the inherited PATH. Prepend Path(sys.executable).parent
(deduped) so venv-installed CLIs resolve under pipx and dev venvs alike.

Co-Authored-By: Claude Fable 5 <[email protected]>
packaging/brew/ holds the tap formula template (virtualenv-based; the
external CLIs the catalog shells out to as deps — the one thing brew can
declare that pipx can't; setuptools/wheel as resources because brew builds
offline and the bundle-assembling build hook needs them) plus the
per-release stamp procedure (shasum + brew update-python-resources).

releasing.md gains build-and-attach-the-wheel and tap-bump steps, and the
Artifacts section drops the wheel/PyPI blocker removed by the overlay
distribution work — PyPI is now a channel decision, not a technical one.

Co-Authored-By: Claude Fable 5 <[email protected]>
…tra hint

The TUI gated the manifest picker, welcome-screen manifest table, and the
run action on root_path — a checkout-era assumption. The api facade now
handles root=None (manifests resolve from the cwd, content from the overlay
roots), so the gates just made those features silently dead under a pipx
install. Removed them.

The missing-textual hint named the wrong package ('paramify') and only the
pip flow; it now gives the pipx and pip commands for paramify-fetchers.

Co-Authored-By: Claude Fable 5 <[email protected]>
Found in dist testing: brew's pipx 1.15 (uv venv backend) exits 1 on
pipx install --force into an existing venv and silently leaves the old
version installed. UV_VENV_CLEAR=1 or uninstall-first works; the upgrade
instructions now say so.

Co-Authored-By: Claude Fable 5 <[email protected]>
Distributable install: the overlay model (multi-root discovery, bundled wheel, create/customize, pipx)
rust is a build dep (rpds-py via jsonschema builds from sdist under brew's
--no-binary policy), and update-python-resources can't resolve a package
that isn't on PyPI — the README now documents the freeze + PyPI-JSON
fallback used to stamp the 21tmccauley test tap.

Co-Authored-By: Claude Fable 5 <[email protected]>
Found in tap testing: a brew install shipped only the base closure, so
paramify tui failed out of the box — wrong for the batteries-included
path. The template now carries a textual resource and a test asserting
the import; pipx users keep opting in via the [tui] extra.

Co-Authored-By: Claude Fable 5 <[email protected]>
docs(brew): formula learnings from tap testing (TUI bundling, resource generation)
Co-Authored-By: Claude Fable 5 <[email protected]>
The welcome screen's startup readout treated a missing checkout as a
failure: "repo root ✗ not found" in red, with the catalog and uploader
checks dashed out — on every pipx/brew install, where everything
actually works. A checkout is one way to have content, not a
requirement.

- Check 0 is now "content roots": the checkout name in dev mode,
  "installed bundle" (or a root count) installed, red only when
  discovery found no roots at all.
- The catalog check answers from app.catalog_data regardless of a
  checkout; the uploader check falls back to the packaged
  uploaders.paramify_evidence module.
- "New manifest" no longer requires a repo root —
  api.new_manifest_path(None, ...) already lands it in ./manifests/.

Regression tests cover installed / installed+user-dir / dev / empty.

Co-Authored-By: Claude Fable 5 <[email protected]>
@21tmccauley

Copy link
Copy Markdown
Collaborator Author

Opened against upstream by mistake — this work is staged on the 21tmccauley/paramify-fetchers-distribute fork for now. Recreating there.

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