chore: add launch plan
This commit is contained in:
284
context/plan.md
Normal file
284
context/plan.md
Normal file
@ -0,0 +1,284 @@
|
||||
# improvise — launch preparation plan
|
||||
|
||||
You are working in the `improvise` repository, a Rust terminal application that implements a Lotus Improv-style pivot-table modeling tool. Cells are keyed by sets of `(category, item)` coordinates rather than 2D grid addresses; views assign categories to row/column/page axes; formulas reference dimension names rather than cell addresses. The application is built with `ratatui` + `crossterm`, persists models in a markdown-based `.improv` format (with optional gzip), and supports both an interactive TUI and a headless command/script mode through a unified registry.
|
||||
|
||||
Your job is to prepare this repository for a public Show HN launch. The bar is "ready for strangers to install and try in 60 seconds," not "feature-complete." Do tasks in the order given. Do not start a later phase before earlier phases are complete. Do not add features, refactor warts, or restructure modules — those are explicitly out of scope and listed at the end.
|
||||
|
||||
The target audience is developers who use vim, who have opinions about data modeling, and who would understand a Lotus Improv reference. The pitch positions improvise as a pivot-table modeling tool, not "a spreadsheet in a terminal" — that framing competes with sc-im and VisiData and loses.
|
||||
|
||||
The development environment is Nix-based (the repo has a `flake.nix`). The user does not have Homebrew installed and will not install it. All tooling must be available through Nix, and any process that needs new tools must be codified as additions to `flake.nix` so the user can reach them via `nix develop` or `nix run`. Do not suggest `brew install` anywhere.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Repository hygiene
|
||||
|
||||
Goal: raise the quality floor of what a stranger sees when they land on the repo. Roughly 90 minutes of work.
|
||||
|
||||
### 1.1 Audit and remove or update `context/SPEC.md`
|
||||
|
||||
Read `context/SPEC.md` and compare it against the actual code. The spec is likely stale: it may describe a JSON import wizard when the real wizard handles CSV, and it may describe JSON persistence when the real format is markdown (look at `src/persistence/mod.rs` to confirm). It may also list commands that no longer exist in the registry.
|
||||
|
||||
If the spec contradicts the code in significant ways, delete it. If you want to preserve design intent, move salvageable conceptual content to `docs/design-notes.md` with a header that reads:
|
||||
|
||||
> **Note:** This document captures design intent and may not reflect the current implementation. The README and source code are authoritative.
|
||||
|
||||
Do not try to bring the spec back into sync with the code — that is not worth the effort for a personal project, and a stale spec is worse than no spec.
|
||||
|
||||
### 1.2 Fix `Cargo.toml` metadata
|
||||
|
||||
The current `[package]` section is missing fields that crates.io and `cargo dist` need. Update it to include:
|
||||
|
||||
- `description` — replace any generic placeholder with: `"Terminal pivot-table modeling in the spirit of Lotus Improv"`
|
||||
- `repository` — ask the user for the GitHub URL if you don't already know it; otherwise leave a `TODO` comment and flag it
|
||||
- `homepage` — same URL as `repository`
|
||||
- `documentation` — same URL as `repository` for now
|
||||
- `readme = "README.md"`
|
||||
- `keywords = ["tui", "pivot", "spreadsheet", "data", "improv"]` (max 5 keywords, each ≤20 chars)
|
||||
- `categories = ["command-line-utilities", "visualization"]`
|
||||
- `license` — confirm this is set; if not, ask the user
|
||||
|
||||
Preserve all existing fields and dependency entries.
|
||||
|
||||
### 1.3 Verify publish-readiness
|
||||
|
||||
Run `cargo publish --dry-run` from inside `nix develop`. Fix any errors or warnings. Common issues: missing license file, files too large to publish, dependencies with incompatible versions. Do not actually publish — that happens in Phase 3.
|
||||
|
||||
### 1.4 Audit CSV quote handling
|
||||
|
||||
Look at `src/import/csv_parser.rs` (or wherever CSV parsing lives). Verify that it correctly handles RFC 4180 quoted fields: fields enclosed in double quotes, embedded commas inside quoted fields, and escaped quotes (`""` inside a quoted field).
|
||||
|
||||
If the parser is using the `csv` crate from `Cargo.toml`, this should be handled correctly by default — verify that the code is actually using it and not doing manual `split(',')` anywhere. If there are any places that do manual splitting or fragile quote handling, fix them by routing through the `csv` crate. Add a unit test that round-trips a CSV row with `"O'Reilly, Inc."` (embedded comma) and `"She said ""hi"""` (embedded escaped quotes).
|
||||
|
||||
If the parser is fundamentally broken in ways that can't be fixed quickly, do not block on this. Add a one-line note to the README under a "Known limitations" section: "CSV files with unusual quoting may not parse correctly; PRs welcome."
|
||||
|
||||
### 1.5 Create `examples/demo.improv` and `examples/demo.csv`
|
||||
|
||||
Create two synthetic example files with obviously-fake data. These exist so a new user can run `improvise examples/demo.improv` and immediately see a working pivot, or `improvise --import examples/demo.csv` and walk through the wizard.
|
||||
|
||||
**`examples/demo.csv`** should contain ~30-50 rows with columns like:
|
||||
- `Date` (mix of dates across at least 2 quarters of one year)
|
||||
- `Region` (3-4 values: North, South, East, West)
|
||||
- `Product` (3-4 values: Widget, Gadget, Sprocket, Doohickey)
|
||||
- `Customer` (5-8 fake company names: Acme Corp, Globex, Initech, Umbrella, Soylent, etc.)
|
||||
- `Revenue` (round numbers, 100-10000)
|
||||
- `Cost` (round numbers, less than Revenue)
|
||||
|
||||
**`examples/demo.improv`** should be the result of importing `demo.csv` through the tool, then manually saving. To create it: build the tool, run the import on `demo.csv`, optionally pivot it into an interesting default view (e.g., Region on rows, Date_Quarter on columns, Product on page axis), add a sample formula like `Profit = Revenue - Cost` if the formula system supports it, save as `examples/demo.improv`, and commit both files.
|
||||
|
||||
If you cannot determine the exact format syntax, look at existing test fixtures or run the tool's save path on a small in-memory model to generate one.
|
||||
|
||||
The data must be obviously synthetic. Do not copy data from any other file in the repo. Do not use any real-looking names, real amounts, or anything that looks like it might be from a real bank export.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — README and demo artifacts
|
||||
|
||||
This is the main weekend's work. The README is 80% of the launch. The demo artifacts are the other 20%. Nothing in Phase 3 or 4 matters if Phase 2 is weak.
|
||||
|
||||
### 2.1 Add Nix tooling for asciinema and VHS
|
||||
|
||||
The user does not have Homebrew. Both asciinema (terminal session recording) and VHS (Charmbracelet's terminal-to-GIF tool, package name `vhs` in nixpkgs) need to be available through Nix.
|
||||
|
||||
Modify `flake.nix` to add `pkgs.asciinema` and `pkgs.vhs` to the dev shell's `nativeBuildInputs`. Both packages exist in nixpkgs unstable; verify before adding. If `vhs` requires additional runtime dependencies (it uses `ttyd` and `ffmpeg` internally), add those too — check the nixpkgs `vhs` derivation to see what's already bundled.
|
||||
|
||||
After modifying the flake, verify that `nix develop --command asciinema --version` and `nix develop --command vhs --version` both work.
|
||||
|
||||
While you're in the flake, also add:
|
||||
- `pkgs.cargo-dist` for the release tooling in Phase 3 (if it's packaged in nixpkgs; if not, fall back to running it via `cargo install` inside the dev shell and note this in a comment)
|
||||
- A `nix run` app or shell alias for the demo recording workflow (see 2.4)
|
||||
|
||||
### 2.2 Write the README
|
||||
|
||||
Replace any existing `README.md` with a new one structured as follows. Aim for under 250 lines total.
|
||||
|
||||
**Section order (do not deviate):**
|
||||
|
||||
1. **Title** — `# improvise`
|
||||
|
||||
2. **One-sentence pitch** — italicized, immediately under the title:
|
||||
> *Terminal pivot-table modeling in the spirit of Lotus Improv — multidimensional cells, formulas over dimensions instead of cell addresses, and vim-style keybindings for reassigning axes on the fly.*
|
||||
|
||||
3. **Inline animated demo** — `` (the GIF generated in step 2.5). This must be near the top so it shows in HN previews and the GitHub repo card.
|
||||
|
||||
4. **Why this exists** — exactly one paragraph. Explain the Improv data/view separation and why no terminal tool currently does it. Reference Lotus Improv (NeXT, 1991) by name. Briefly note that Excel pivot tables took the visual idea but not the formula model. Do not bash other tools — name sc-im and VisiData neutrally as adjacent-but-different.
|
||||
|
||||
5. **Quick start** — three code blocks:
|
||||
```
|
||||
nix develop
|
||||
cargo build --release
|
||||
./target/release/improvise examples/demo.improv
|
||||
```
|
||||
Followed by a one-line "or import your own CSV":
|
||||
```
|
||||
./target/release/improvise --import path/to/data.csv
|
||||
```
|
||||
|
||||
6. **Key bindings to try first** — short list, not a complete reference. `T` for tile mode (reassign axes), `[` `]` for page axis cycling, `>` to drill into a cell, `<` to return, `F` for formula panel, `:w` to save, `:q` to quit, `?` or `F1` for full help.
|
||||
|
||||
7. **Installation** — three subsections:
|
||||
- **From source with Nix** (preferred): `nix develop` then `cargo build --release`, then optionally `cargo install --path .`
|
||||
- **From crates.io**: `cargo install improvise` (will be valid after Phase 3)
|
||||
- **Prebuilt binaries**: link to GitHub releases page (will be populated after Phase 3)
|
||||
|
||||
Do not mention Homebrew. Do not mention `apt`, `dnf`, or other distro package managers.
|
||||
|
||||
8. **What's interesting about the codebase** — 10-15 lines, prose, no bullets. Cover: the multidimensional data model with categories instead of grid coordinates; the view layer as a pure function from `(Model, View)` to `GridLayout`; records mode as just another axis assignment; the command/effect architecture that lets the same registry serve both interactive dispatch and headless scripts; the markdown `.improv` persistence format that's human-readable and git-diffable.
|
||||
|
||||
9. **Expectations** — mandatory disclaimer paragraph, exact wording:
|
||||
> improvise is a personal project I built for my own use. I'm sharing it because other people might find it useful, but I can't promise active maintenance or feature development. Issues and PRs are welcome but may not get a fast response. If you want to build on it, fork away.
|
||||
|
||||
10. **License** — one line.
|
||||
|
||||
Do not add: a table of contents, badges (build status, version, license badges, etc.), a contributing guide, a code of conduct, an "inspired by" gratitude section. These are noise for a personal project launch.
|
||||
|
||||
### 2.3 Create `docs/demo.tape` and generate `docs/demo.gif`
|
||||
|
||||
VHS is scripted: you write a `.tape` file describing keystrokes and timing, and VHS produces a GIF. This GIF goes inline in the README and is the single highest-leverage artifact in the launch — it's what shows up in HN preview cards and Google search results.
|
||||
|
||||
Create `docs/demo.tape` that scripts a ~20-second flow showing the pivot reassignment killer demo. Rough script structure (consult VHS docs for exact syntax):
|
||||
|
||||
```
|
||||
Output docs/demo.gif
|
||||
Set FontSize 14
|
||||
Set Width 1000
|
||||
Set Height 600
|
||||
Set Theme "Dracula"
|
||||
|
||||
Type "improvise examples/demo.improv"
|
||||
Enter
|
||||
Sleep 1500ms
|
||||
|
||||
# Show initial pivot
|
||||
Sleep 1s
|
||||
|
||||
# Enter tile mode and reassign an axis
|
||||
Type "T"
|
||||
Sleep 800ms
|
||||
# (whatever keystrokes reassign Region from rows to columns)
|
||||
Sleep 1500ms
|
||||
|
||||
# Show the new pivot
|
||||
Sleep 1s
|
||||
|
||||
# Reassign again to demonstrate the speed
|
||||
# (more keystrokes)
|
||||
Sleep 1500ms
|
||||
|
||||
# Exit
|
||||
Type ":q"
|
||||
Enter
|
||||
```
|
||||
|
||||
Generate the GIF by running `nix develop --command vhs docs/demo.tape`. Iterate on the script until the GIF is under 5MB, the timing is readable (not too fast, not too slow), and the key beats are clear: start in pivot view → press T → axis reassigns → press T again → axis reassigns again. The viewer should be able to understand "this tool re-pivots data with one keystroke" without any narration.
|
||||
|
||||
### 2.4 Record asciinema casts
|
||||
|
||||
Asciinema produces `.cast` files that the asciinema-player JS widget can replay in a browser, with selectable text and pixel-perfect terminal rendering. These will be embedded in the GitHub Pages landing page in Phase 4.
|
||||
|
||||
Before recording, set the terminal to exactly 100 columns by 30 rows: `stty cols 100 rows 30` (or resize the terminal window manually if `stty` doesn't take). This matters because the asciinema player renders at the recorded dimensions and a wrong size will look broken on the landing page.
|
||||
|
||||
Record four casts under `docs/casts/`:
|
||||
|
||||
- **`docs/casts/import.cast`** — start with `improvise` (no args, empty model), trigger CSV import for `examples/demo.csv`, walk through the wizard accepting defaults, end in pivot view.
|
||||
- **`docs/casts/pivot.cast`** — start from `improvise examples/demo.improv`, demonstrate axis reassignment with `T`. This is the same flow as the README GIF but longer and more complete. Show 2-3 different pivots.
|
||||
- **`docs/casts/drill.cast`** — from a pivot view, press `>` to drill into an aggregated cell, show the records view, demonstrate that you can edit a record, press `<` to return.
|
||||
- **`docs/casts/formulas.cast`** — from a pivot view, open the formula panel with `F`, add `Profit = Revenue - Cost`, show it appearing across the pivot.
|
||||
|
||||
Record each with `nix develop --command asciinema rec -i 2 docs/casts/<name>.cast`. The `-i 2` flag caps idle gaps at 2 seconds, which prevents long pauses from making the playback feel dead. Each cast should be under 60 seconds.
|
||||
|
||||
If a take has flubs, delete it and re-record. Do not try to edit the JSON cast files manually.
|
||||
|
||||
Add a `nix run` app to the flake or a shell script in `scripts/record-demo.sh` that wraps the recording workflow with the right `stty` setup, so the user can re-record consistently in the future without remembering the exact incantation.
|
||||
|
||||
### 2.5 Verify all artifacts exist and are committed
|
||||
|
||||
Before moving to Phase 3, confirm:
|
||||
- `README.md` exists with all 10 sections
|
||||
- `docs/demo.gif` exists, is referenced from the README, and is under 5MB
|
||||
- `docs/demo.tape` exists and regenerates the GIF when run through VHS
|
||||
- `docs/casts/import.cast`, `pivot.cast`, `drill.cast`, `formulas.cast` all exist
|
||||
- `examples/demo.csv` and `examples/demo.improv` exist and contain only synthetic data
|
||||
- `flake.nix` includes `asciinema`, `vhs`, and `cargo-dist` (or a fallback for `cargo-dist`)
|
||||
- `nix develop` succeeds and all the tools above are on PATH
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Distribution
|
||||
|
||||
### 3.1 Configure `cargo dist`
|
||||
|
||||
`cargo dist` generates a GitHub Actions workflow that produces release tarballs and installer scripts when you push a version tag. Run `nix develop --command cargo dist init` and configure for these targets:
|
||||
|
||||
- `x86_64-unknown-linux-gnu`
|
||||
- `aarch64-apple-darwin`
|
||||
- `x86_64-apple-darwin`
|
||||
|
||||
Skip Windows. Skip musl unless `cargo dist init` strongly recommends it — the existing flake doesn't build for musl and adding that complication is out of scope.
|
||||
|
||||
Commit the generated `.github/workflows/release.yml` and the additions to `Cargo.toml`. Test the workflow by tagging `v0.1.0-rc1` and pushing the tag to a branch — verify the release builds successfully on GitHub Actions before doing a real release. Delete the rc tag afterward.
|
||||
|
||||
### 3.2 Publish to crates.io
|
||||
|
||||
After `cargo publish --dry-run` is clean (from step 1.3) and the user confirms they're ready, run `nix develop --command cargo publish`. Verify the crate appears at `https://crates.io/crates/improvise` and that `cargo install improvise` works on a clean machine (or in a fresh `nix shell --packages cargo`).
|
||||
|
||||
### 3.3 Tag the v0.1.0 release
|
||||
|
||||
Create a git tag `v0.1.0`, push it, and verify the `cargo dist` workflow produces release artifacts. Update the README's "Prebuilt binaries" link to point at the actual release.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Landing page (optional but recommended)
|
||||
|
||||
### 4.1 Create `docs/index.html`
|
||||
|
||||
Vanilla HTML, single file, under 200 lines. No framework, no build step. Dark background, monospace headings to match the terminal aesthetic. Embed the asciinema-player from jsdelivr CDN (`https://cdn.jsdelivr.net/npm/asciinema-player@3/dist/bundle/`) and reference the four `.cast` files from `docs/casts/`.
|
||||
|
||||
Section structure: title and one-line tagline → "Reassign axes on the fly" with the pivot cast → "Drill into aggregated cells" with the drill cast → "Formulas over dimensions" with the formulas cast → "Import a CSV" with the import cast → "Get it" with the install commands and a GitHub link.
|
||||
|
||||
Each cast should be embedded with `AsciinemaPlayer.create()` configured with `rows: 30, cols: 100, theme: 'monokai', autoPlay: false, loop: true`.
|
||||
|
||||
### 4.2 Enable GitHub Pages
|
||||
|
||||
In the GitHub repo settings, enable Pages with source set to the `main` branch and folder set to `/docs`. Verify the site is live at `https://<user>.github.io/improvise/` within a few minutes of pushing.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Buffer
|
||||
|
||||
The second weekend (or the second half of the first weekend) is reserved for whatever was missed in Phases 1-4. Do not use it to add features. Do not use it to fix the issues listed in "Out of scope" below. If everything is done early, stop.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope — do not do these before launch
|
||||
|
||||
The following are real issues that have been identified but are explicitly not launch-blocking. Do not start any of them as part of this plan. They can be addressed after launch based on what real users actually trip over.
|
||||
|
||||
- **Do not** raise or restructure the `MAX_CATEGORIES = 12` limit, even though it's tight for some real use cases.
|
||||
- **Do not** refactor the `ExecuteCommand` vim command match ladder, even though it duplicates registry logic.
|
||||
- **Do not** fix the hardcoded `"Measure"` category name in `evaluate_aggregated`, even though it's the one place in the code that assumes a specific user-facing name.
|
||||
- **Do not** change `Model::evaluate` from a linear formula walk to a HashMap lookup, even though it's O(N·M·F) in the render hot path.
|
||||
- **Do not** add render-pass memoization to `matching_values` calls.
|
||||
- **Do not** fix the `ApplyAndClearDrill` HashMap iteration ordering issue around coordinate rename + value edit interactions.
|
||||
- **Do not** add new features: no YoY references, no parameterized formulas, no Datalog backend, no undo/redo, no charts, no plugin system.
|
||||
- **Do not** write a documentation site beyond the single GitHub Pages landing page in Phase 4.
|
||||
- **Do not** add Windows support.
|
||||
- **Do not** rename types, restructure modules, or do any "while I'm in here" cleanups.
|
||||
|
||||
Each of these is worth doing eventually. None of them is worth doing before the launch post is up. The goal of this plan is to get the existing tool in front of strangers in a form they can install and try, not to make the tool perfect first.
|
||||
|
||||
---
|
||||
|
||||
## Definition of done
|
||||
|
||||
The plan is complete when, on a clean machine with only Nix installed:
|
||||
|
||||
1. `git clone <repo> && cd improvise && nix develop` succeeds.
|
||||
2. `cargo build --release` succeeds.
|
||||
3. `./target/release/improvise examples/demo.improv` opens an interesting pivot immediately.
|
||||
4. The README renders correctly on GitHub with the inline GIF playing.
|
||||
5. `cargo install improvise` from a fresh shell works and produces a runnable binary.
|
||||
6. The GitHub releases page has prebuilt binaries for Linux x86_64 and macOS (Intel + Apple Silicon).
|
||||
7. The GitHub Pages site at `https://<user>.github.io/improvise/` loads and the asciinema casts play.
|
||||
8. Nothing in the "Out of scope" list has been touched.
|
||||
|
||||
When all eight conditions hold, stop. Report back to the user with a summary of what was done and any blockers encountered. Do not post to Hacker News yourself — that's the user's call and their timing.
|
||||
Reference in New Issue
Block a user