Introduction
I participated in the Kiro University Challenge and built a TUI app called AWS Public IP Ranges Navigator, which allows users to filter and view AWS's published list of IP ranges directly in the terminal.
This challenge was a program where lessons were published daily from September 21 to September 25, 2026. Participants were expected to integrate what they learned into a single project and submit it as a take-home final exam by October 5.
Grading is determined by "how well the project demonstrates the concepts learned across the 7 lessons."
In this article, I will reflect on what I built and how I used Kiro to build it.
What I Built
AWS publishes its public IP ranges as JSON at ip-ranges.amazonaws.com/ip-ranges.json.
This application allows users to filter and browse this list by region and service using keyboard navigation alone.
For the TUI framework, I chose Textual.
https://github.com/yuj1osm/aws-public-ip-ranges-navigator
Key Features
- Fetches the latest IP range document via HTTPS on startup (15-second timeout)
- 3-pane layout: Region list and Service list on the left, results table on the right, and keybindings bar at the bottom
- Filter by Region, Service, or both.
ALLat the top of each list means "no filter" - Results table displays index numbers, CIDR, Region, and Service, with a live count of matching entries in the header
- Re-fetches data without exiting the app (
rkey). Fetching and parsing run off the main UI thread, ensuring the screen never freezes - If fetching or parsing fails, existing data is preserved, and a non-blocking message is displayed while the app continues running
- Supports mouse interactions (click to select, wheel to scroll)
Keyboard Shortcuts
| Key | Action |
|---|---|
↑ / ↓
|
Move selection within the active list |
Tab |
Switch focus between Region list and Service list |
x |
Clear filters (resets both lists to ALL) |
r |
Re-fetch the IP range document |
q |
Quit |
How I Used Kiro
The main focus during this project was properly executing Kiro's Spec-driven development workflow.
Rather than jumping straight into coding, I solidified the 3 steps (requirements → design → tasks) in order before starting implementation.
The artifacts are stored under the .kiro/specs/ directory.
1. Requirements
First, using Kiro's Spec mode, I wrote out acceptance criteria using a format similar to EARS notation.
For example, conditions such as "fetch data via HTTPS on startup" or "if the document is not received within 15 seconds, cancel fetching, display an error, and keep the app running" were enumerated one by one to eliminate ambiguity.
This eventually culminated in 12 Requirements, each with its own set of Acceptance Criteria.
Terminology was also defined upfront in a Glossary.
Establishing clear names like Data_Fetcher, Data_Store, IP_Prefix, and Active_Panel kept vocabulary consistent throughout design and implementation.
2. Design
In the design phase, logic prone to bugs was separated into pure functions.
The architecture was split into the following layers:
-
Network Layer (
fetcher): I/O responsible solely for HTTPS fetching and timeout handling -
Parser Layer (
parser): Converts JSON intoIP_Prefixobjects. Separately handles corrupted documents, missing prefixes, and invalid individual entries -
Domain Layer (
store/filtering/navigation/models): Manages state and filter computations. Entirely composed of side-effect-free pure functions -
Presentation Layer (
app): UI rendering and input routing handled by Textual
Thanks to this separation, the most delicate logic—parsing and filtering—could be completely isolated from the UI and thoroughly unit tested.
The design document explicitly captured reasons for choosing Textual (its components like DataTable, ListView, and Footer mapped directly to requirements) as well as reasons for rejecting curses, making the rationale easy to trace later.
Furthermore, 17 "Correctness Properties" were defined in the design document.
These are invariants that must hold true across all possible inputs, such as "converting valid entries to text and re-parsing yields equivalent data (round-trip)" or "filtered result counts must always match the count displayed in the header."
These directly served as specifications for property-based testing later on.
3. Tasks
Implementation tasks were organized to progress in sequence: "pure core → I/O → presentation → entry point → packaging."
Each task explicitly cited its corresponding Requirement and Property to ensure traceability, with dependencies structured into waves. Sub-tasks for writing tests were marked as optional with *, allowing for an MVP-first build strategy.
Fixing Coding Standards via Steering
I placed project-wide Python guidelines in .kiro/steering/python-guidelines.md to ensure code generated by Kiro strictly adhered to these rules.
Key rules included:
- PEP 8 compliance, 4-space indentation, 88–99 characters per line
- Use
@dataclassfor structured data, addingfrozen=Truewhen immutability is desired - Avoid catching raw
except Exception:; instead, catch specific custom exception classes and branch by type - Guarantee proper cleanup using
withstatements ortry-finallyblocks
In practice, IP_Prefix became a frozen=True dataclass, and exceptions were structured under a hierarchy rooted at NavigatorError (e.g., FetchError, FetchTimeoutError, ParseError).
Leveraging Steering maintained these principles consistently across all modules.
Ensuring Quality with Property-Based Testing
For logic extracted into pure functions, I applied property-based testing using Hypothesis.
Instead of writing edge cases one by one, massive amounts of auto-generated test cases verified that "this property holds true for any input."
The 17 properties defined during design directly guided the test suite:
- Round-trip parsing and skipping invalid entries
- Correctness of filtering under all combinations of
ALLand specific filter values - Matching row counts with header indicators and no gaps in index numbering
- Selection index clamping and immutability of selection during scrolling
For the UI (app), integration tests using Textual's run_test verified app startup, focus changes, reloading, quitting, and mouse interactions.
Looking Back
The best part of following a Spec-driven approach was that I spent virtually zero time wondering "what should I build next?"
Locking down requirements and design upfront made the implementation phase simply a matter of giving form to what was decided, making Kiro's responsibilities crystal clear.
Recording technical choices in design documents means the context behind past decisions is immediately accessible whenever I review it.
Even with Textual—a framework I don't use often—the upfront mapping to requirements minimized roadblocks during development.
It was also rewarding to try a different development workflow, aligning with the challenge's encouragement to "experiment with Kiro features you haven't used yet."
Additionally, I created custom Powers and Custom Agents.
When it came to preparing a demo video for submission, asking Kiro enabled me to generate an animated GIF effortlessly.
Conclusion
Although AWS Public IP Ranges Navigator is a practical, lightweight tool, it served as a great subject to practice a full Kiro-driven workflow: Spec-driven development, standard enforcement via Steering, and property-based testing.
I hope this provides a helpful reference for anyone tackling the same challenge.
How to Use (Bonus)
bash
python -m venv .venv
source .venv/bin/activate
pip install -e .
python -m aws_ip_navigator






Top comments (0)