Book 3: Ship
![]()
What Is SpecKit?
Section titled “What Is SpecKit?”You have a vault full of organised knowledge and a validated offer with paying early adopters. Now you need to build the thing. SpecKit is a specification-driven development workflow that turns product descriptions into working code through a repeatable four-stage cycle: Specify, Plan, Tasks, Implement.
Each stage produces a concrete artefact that feeds into the next, so nothing gets lost in translation between what you imagined and what gets built.
SpecKit is implemented as a set of skills installed in your LLM’s skills directory. Each skill auto-activates when you describe the relevant task.
The SpecKit Cycle
Section titled “The SpecKit Cycle”- Specify. Describe what you want built in plain language. The
speckit.specifyskill generates a structured specification with an overview, user stories, requirements, and acceptance criteria. - Plan. The
speckit.planskill reads your specification and produces a technical blueprint: which files need to change, the implementation order, and any risks. - Tasks. The
speckit.tasksskill breaks the plan into a flat, ordered list of discrete tasks. - Implement. The
speckit.implementskill works through the task list one task at a time, writing code, running tests, and moving on.
The four stages form a loop. After implementing a feature, you may discover that the spec needs updating, or that the plan should change for the next feature. This is expected. The spec is always the source of truth.
The Constraint of the Sold
Section titled “The Constraint of the Sold”In the Offer page, you found 10 early adopters. They paid. They are waiting. The offer PDF you shared with them is your build constraint now.
You can only build what the offer promised. Not more. Not less. Without this constraint, you would spend three weeks adding features nobody asked for. With the constraint, you build what people paid for, and you ship it to them.
Step 1: Install Gemini CLI
Section titled “Step 1: Install Gemini CLI”Gemini CLI is the AI coding tool you will use throughout this book. Like the tools in Books 1 and 2, it runs in your terminal and interacts directly with your project files.
Install Gemini CLI
Open Terminal and run: npm install -g @google/gemini-cli. Once the
installation finishes, run gemini to verify it launches. You will need
Node.js 18 or later installed first. If you do not have Node.js, download it
from nodejs.org. For the latest installation
instructions, visit geminicli.com.
Open PowerShell and run: npm install -g @google/gemini-cli. Once the
installation finishes, run gemini to verify it launches. You will need
Node.js 18 or later installed first. If you do not have Node.js, download it
from nodejs.org. For the latest installation
instructions, visit geminicli.com.
Gemini CLI requires a Google AI account with API access. Visit ai.google.dev, sign in, generate an API key, and store it somewhere safe. When you first run gemini, it will walk you through authentication.
For detailed setup instructions, see the Gemini CLI guide.
Step 2: Clone the Repository
Section titled “Step 2: Clone the Repository”Cloning the Water Tracker repository... git clone -b develop https://github.com/evalincius/odd-water-tracker-mob-app Cloning into 'odd-water-tracker-mob-app'... remote: Enumerating objects: 283, done. remote: Counting objects: 100% (283/283), done. remote: Compressing objects: 100% (208/208), done. Receiving objects: 100% (283/283), 1.41 MiB | 4.87 MiB/s, done. Resolving deltas: 100% (112/112), done. Repository cloned successfully. Here is the folder structure: odd-water-tracker-mob-app/ ├── android/ # Android platform files ├── ios/ # iOS platform files ├── lib/ │ ├── main.dart # App entry point │ ├── models/ │ │ └── water_entry.dart │ ├── screens/ │ │ ├── home_screen.dart │ │ ├── daily_screen.dart │ │ ├── weekly_screen.dart │ │ ├── monthly_screen.dart │ │ └── settings_screen.dart │ ├── widgets/ │ │ ├── progress_ring.dart │ │ ├── quick_add_buttons.dart │ │ └── history_chart.dart │ ├── providers/ │ │ ├── water_provider.dart │ │ └── settings_provider.dart │ └── database/ │ └── water_database.dart ├── test/ # Unit and widget tests ├── pubspec.yaml # Flutter dependencies └── README.md # Setup instructions The project uses Flutter with Riverpod for state management and SQLite for local storage. It tracks water intake in millilitres with a configurable daily goal.
LLM outputs are non-deterministic and may vary from this example.
Step 3: Follow the README Setup Instructions
Section titled “Step 3: Follow the README Setup Instructions”Open the README.md file in the repository and read through the setup instructions. If you get stuck on any step, ask your LLM for help.
I have read the README. Let me walk you through each setup step. 1. Flutter SDK Checking if Flutter is installed... found (version 3.27.4). Running: flutter doctor [✓] Flutter (Channel stable, 3.27.4) [✓] Android toolchain [✓] Xcode - develop for iOS and macOS [✓] Connected device (2 available) All checks passed. 2. Dependencies Running: flutter pub get Resolving dependencies... Got dependencies. 49 packages installed. Key packages: - flutter_riverpod 2.6.1 (state management) - sqflite 2.4.1 (local database) - intl 0.19.0 (date/time formatting) - fl_chart 0.70.2 (charts and graphs) - percent_indicator 4.2.3 (progress ring widget) 3. Android Emulator Checking for available emulators... Found: Pixel_7_API_34 Starting emulator... Emulator launched successfully. 4. Verify setup Running: flutter analyze Analyzing odd-water-tracker-mob-app... No issues found! 0 hints, 0 warnings, 0 errors. All dependencies are installed and your development environment is ready. Run "flutter run" to launch the app on the emulator.
LLM outputs are non-deterministic and may vary from this example.
Step 4: Get the App Running
Section titled “Step 4: Get the App Running”Running: flutter run Launching lib/main.dart on Pixel 7 API 34 in debug mode... ✓ Built build/app/outputs/flutter-apk/app-debug.apk. Installing and launching on Pixel 7 API 34... App launched successfully. Here is what you should see: Home Screen (default tab): - A large circular progress ring in the centre showing 0/2000ml - The ring is empty (grey) since no water has been logged - Below the ring: "0ml of 2000ml" - Quick-add buttons: +100ml, +250ml, +500ml - A "Custom" button for entering a specific amount - Current streak counter: "0 day streak" Tap a quick-add button (+250ml): - The progress ring animates, filling proportionally - The counter updates: "250ml of 2000ml" - A brief confirmation appears: "+250ml added" Bottom Navigation Bar (5 tabs): - Home (droplet icon): the current screen - Daily (list icon): today's individual entries with timestamps - Weekly (bar chart icon): 7-day bar chart of daily totals - Monthly (calendar icon): calendar heat map of current month - Settings (gear icon): daily goal, units, reminders Tap "Daily" in the bottom bar: - Shows a chronological list of today's water entries - Each entry shows: amount, timestamp, and running total - Empty state if no entries logged yet Tap "Weekly" in the bottom bar: - A 7-day bar chart (Mon to Sun) - Each bar shows the daily total in ml - A horizontal line marks the daily goal (2000ml) - Average for the week shown below the chart Tap "Monthly" in the bottom bar: - A calendar grid for the current month - Each day is colour-coded: green (goal met), amber (>50%), red (<50%), grey (no data) - Monthly total and daily average shown below Tap "Settings" in the bottom bar: - Daily goal: 2000ml (adjustable) - Unit preference: ml or oz - Reminder intervals (off by default) Verify these three things before moving on: 1. The app launches without errors ✓ 2. All five tabs are tappable and switch screens ✓ 3. A quick-add button updates the progress ring ✓
LLM outputs are non-deterministic and may vary from this example.
Before moving on, confirm these three things:
- The app launches without crash screens or error messages in your terminal.
- Navigation works by tapping each tab in the bottom bar (Home, Daily, Weekly, Monthly, Settings).
- The core interaction responds: tap a quick-add button and confirm the progress ring updates.
If any of these checks fail, copy the error message from your terminal and paste it into Gemini CLI.
Step 5: Build a New Feature: Edit Entry (Modify Time & Amount)
Section titled “Step 5: Build a New Feature: Edit Entry (Modify Time & Amount)”Now you will use the SpecKit workflow to add a real feature. Users will be able to tap an entry on the Daily screen to edit both the amount and the timestamp via a bottom sheet modal.
Describe the feature to your LLM. The speckit.specify skill will auto-activate and generate a structured specification:
The speckit.specify skill has activated. Generating specification... Specification saved to: specs/edit-entry/spec.md ═══════════════════════════════════════════════════ FEATURE SPECIFICATION: Edit Entry ═══════════════════════════════════════════════════ Overview Add an Edit Entry feature that allows users to modify existing water intake entries. Tapping an entry on the Daily screen opens a bottom sheet modal pre-filled with the current amount and timestamp. The user can update either field and save the changes, which updates the database and refreshes all related screens. User Stories 1. As a user, I want to tap an entry to edit it so I can correct mistakes without deleting and re-adding. 2. As a user, I want the edit form pre-filled with current values so I only need to change what is wrong. 3. As a user, I want totals and streaks to update automatically after an edit so my data stays accurate. 4. As a user, I want to cancel an edit without saving so I do not make accidental changes. Requirements Daily Screen Interaction: - Each entry row becomes tappable (add InkWell/GestureDetector) - Tapping an entry opens a bottom sheet modal - Visual hint: add a subtle edit icon or ripple effect on tap Bottom Sheet Modal: - Title: "Edit Entry" - Amount field: pre-filled with current value in ml - Validated between 1ml and 5000ml - Numeric keyboard input - Show validation error if out of range - Time field: pre-filled with current timestamp - Opens a time picker on tap - Cannot be set to a future time - Save button: disabled until the user changes at least one field - Cancel button: dismisses the modal with no changes Database Operation: - Perform an UPDATE on the existing entry (not delete + insert) - Update both amount and timestamp fields - Preserve the original entry ID and creation date State Refresh: - After a successful save, invalidate these Riverpod providers: - dailyEntriesProvider (refreshes the Daily screen list) - dailyTotalProvider (refreshes the Home screen progress ring) - weeklyTotalsProvider (refreshes the Weekly chart) - monthlyTotalsProvider (refreshes the Monthly calendar) - streakProvider (recalculates the streak counter) - The bottom sheet dismisses automatically after saving Acceptance Criteria - [ ] Tapping a Daily screen entry opens the edit bottom sheet - [ ] Amount field is pre-filled with the current value - [ ] Time field is pre-filled with the current timestamp - [ ] Amount validation rejects values below 1ml or above 5000ml - [ ] Time picker prevents selection of future times - [ ] Save button is disabled until a field is changed - [ ] Save performs an UPDATE on the existing database row - [ ] Home screen progress ring updates after edit - [ ] Weekly and Monthly views reflect the edited values - [ ] Streak counter recalculates after edit - [ ] Cancel dismisses the modal without changes - [ ] Existing tests still pass after implementation Out of Scope - Deleting entries (separate feature) - Editing entries from the Weekly or Monthly screens - Undo/redo functionality - Edit history or audit log - Bulk editing multiple entries ═══════════════════════════════════════════════════ Review the specification. If you are happy with it, say "generate the implementation plan" to activate speckit.plan, or edit the spec file directly to make changes first.
LLM outputs are non-deterministic and may vary from this example.
Once the specification is created and you are happy with it, ask your LLM to generate the implementation plan (the speckit.plan skill will auto-activate), then to break it into ordered tasks (speckit.tasks), and finally to implement them (speckit.implement). Review the output at each stage.
Delivering to Your Early Adopters
Section titled “Delivering to Your Early Adopters”The app is built. Now put it in the hands of the people who paid for it.
Your 10 early adopters from the Offer page are waiting. Share a development build (APK for Android, TestFlight for iOS). Send it to each early adopter with a short message: “Here is the water tracker you signed up for. I would love to hear what you think.”
Run lightweight UAT. Ask each person to do three things: log a glass of water, check the daily screen, and look at the weekly chart. If they can do all three without asking you a question, the core experience works.
Collect feedback simply. A shared note, a WhatsApp group, or a reply to your message. Close the loop: when you fix something based on their feedback, tell them.
What Comes Next
Section titled “What Comes Next”You have taken a starter project, set up a development environment, and built a real feature using the SpecKit workflow with Gemini CLI. The Water Tracker is yours to keep building.
Head to the Scale page to learn how to grow beyond your first 10 early adopters with outreach, content, and the Core Four framework.