Nano Banana Pro
Agent skill for nano-banana-pro
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Sign in to like and favorite skills
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is the bz-taew-py project - a Python implementation of the BlueZone parking ticket application, showcasing the "Ports and Adapters" architecture pattern. This project builds upon the bz-taew repository (included as a subtree under
common/) and uses the taew-py library for the Ports & Adapters framework.
This project uses UV for dependency management and a root-level Makefile for task automation.
make test-unit - Run unit tests using unittest discovery from ./test directorymake coverage - Run full test suite with coverage analysismake erase-coverage - Clean coverage datamake combine-coverage - Combine coverage data from parallel test runsmake report-coverage - Display coverage reportmake static - Run all static analysis tools (ruff, mypy, pyright)make ruff-check - Run ruff linting (excludes ./typings)make ruff-format - Run ruff formattingmake mypy - Run MyPy type checking on source and ./bin/bzmake pyright - Run Pyright type checking on source and ./bin/bzmake benchmark - Run performance benchmarks (currently: ticket storage)make sync - Sync dependencies using uv syncmake all - Execute complete pipeline: sync, static analysis, coverage, and benchmarksThis project uses custom slash commands for GitHub issue management:
/issue-new <label> "<title>" ["<body>"] - Create new issue and branch
enhancement, bug, documentation/issue-close - Close current issue (skip build, auto-version bump)
build (run make), --major (force major bump), --no-bump (skip version)Best Practice: After significant architectural changes, update CLAUDE.md to document:
This application implements the Ports & Adapters (Hexagonal Architecture) pattern using the taew-py framework (v2.13.0+). The architecture achieves pure separation between domain logic and infrastructure through well-defined interfaces (ports).
1. Pure Dependency Injection
bind() functionPortsMapping2. Convention Over Configuration
./, CLI package = adapters.cli)3. Stateless Dependency Resolution
bind() is a pure function with caching for performance4. Clean Separation of Concerns
For deep dive into taew framework architecture, see taew-py CLAUDE.md.
bz-taew-py/ ├── domain/ # BlueZone domain models │ ├── payment_card.py # Payment card value object │ ├── rate.py # Parking rate value object │ └── ticket.py # Parking ticket entity ├── ports/ # Port interfaces for external dependencies │ ├── for_car_drivers.py # Interface for car driver operations │ ├── for_making_payments.py # Payment processing interface │ ├── for_parking_inspectors.py # Parking inspector operations │ ├── for_storing_rates.py # Rate storage interface │ └── for_storing_tickets.py # Ticket storage interface ├── adapters/ # Adapter implementations │ ├── cli/ # CLI-specific adapters │ ├── dir/ # Directory-based storage adapters │ └── ram/ # In-memory storage adapters ├── workflows/ # Application workflows (use cases) ├── test/ # Unit and integration tests ├── benchmarks/ # Performance benchmarks │ ├── benchmark_tickets_storage.py # Storage adapter comparisons │ └── fake_tickets.py # Test data generation ├── bin/ # Executable scripts │ └── bz # Main CLI entry point ├── configuration.py # Port-to-adapter wiring configuration └── common/ # Shared specifications from bz-taew (subtree)
Performance Testing (
benchmarks/):
The benchmarks folder contains performance comparisons of different ticket storage configurations, evaluating them across three dimensions:
Current Configurations Tested:
Benchmark Results: The Pickle serializer emerges as the optimal choice for the current exploratory test setup:
The benchmark generates 10,000 fake tickets using the Faker library and measures write time, read time, and storage size for each configuration. While compressed formats (zlib) achieve better storage efficiency, they add configuration complexity and performance overhead that outweigh the benefits for this use case.
Running Benchmarks:
make benchmark # Runs all storage configuration benchmarks
Domain Models (
domain/):
payment_card.py - Payment card value object (card number, CVV, expiry)rate.py - Parking rate value object (zone, hourly rate)ticket.py - Parking ticket entity (registration, zone, payment details, timestamps)These are pure data structures (value objects and entities) with no behavior or business logic. They represent the core domain concepts that are manipulated by workflows through ports. All validation and business rules are encapsulated within these immutable data structures.
Port Interfaces (
ports/):
Defines the contracts that adapters must implement to provide infrastructure capabilities:
for_car_drivers.py - Operations for car drivers (buy parking tickets)for_making_payments.py - Payment processing capabilitiesfor_parking_inspectors.py - Ticket verification for inspectorsfor_storing_rates.py - Rate persistence interfacefor_storing_tickets.py - Ticket persistence interfaceAll ports use Python protocols for type safety and follow dependency inversion principles.
Business Process Logic (
workflows/):
Implements the application's use cases by orchestrating ports to manipulate domain objects:
for_car_drivers/ - Car driver workflows (purchase parking tickets)for_parking_inspectors/ - Inspector workflows (check parking status, verify tickets)Workflows receive ports as dependencies (via dependency injection) and coordinate them to implement business processes. For example, the "buy ticket" workflow orchestrates:
Workflows contain the business logic and rules, while domain objects remain pure data structures. Each workflow also provides a
Configure class for dependency injection setup.
Adapter Implementations (
adapters/):
adapters/cli/) - Thin wrappers that rename workflow classes to CLI commands (e.g., workflows.for_car_drivers.BuyTicket → buy_ticket method). The argparse infrastructure then automatically converts snake_case to kebab-case for CLI invocation (buy-ticket). This direct workflow-to-command mapping is a unique capability of taew, eliminating the manual command registration boilerplate found in traditional Python CLI frameworks like argparse or click.adapters/dir/) - File system-based persistenceadapters/ram/) - In-memory storage for testing/developmentAdapters are configured in
configuration.py using the taew-py framework's port binding system.
Entry Point (
bin/bz):
The main CLI executable is a minimal shim (~22 lines) that:
adapters configuration from configuration.pybind() function to resolve the Main interfacefrom taew.ports.for_starting_programs import Main from taew.adapters.launch_time.for_binding_interfaces import bind from configuration import adapters _main = bind(Main, adapters=adapters) _main(sys.argv)
The CLI automatically discovers commands from the workflow layer and provides a dynamic command-line interface. This shim is trivial enough to be auto-generated.
Port Wiring (
configuration.py):
Defines a single adapters variable that maps port interfaces to their adapter implementations. This configuration is purely application-specific - all framework infrastructure (CLI routing, argument parsing, pretty printing, etc.) is configured automatically by taew's configure() function.
from taew.utils.cli import configure adapters = configure( MakingPayments(), # Domain adapters CarDrivers(_min_euros=Decimal("0.50")), # with business rules ParkingInspectors(), CurrentDateTime(), Rates(...), # and domain data Tickets(...), variants={...}, # Type serialization variants )
The
configure() function:
Configure* prefix for brevity)./, CLI package = adapters.cli)PortsMapping for dependency injectionThis design achieves pure separation:
configuration.py describes what the application needs, while taew handles how to wire it together.
Hexagonal Architecture (Ports & Adapters)
Dependency Inversion Principle
Protocol-Based Contracts
Functional Dependency Injection
bind() function resolves dependencies at runtimeType Safety
Separation of Concerns:
configuration.py): Domain adapters, business rules, domain databin/bz): Minimal glue between configuration and frameworkNaming Conventions:
Configure classes without the Configure prefix for brevity
Configure as MakingPayments (not ConfigureMakingPayments)configure(MakingPayments(), CarDrivers(), ...)adapters (not ports or launch_ports) for the main configuration variablebind() function (not Bind() class) for dependency injectionConfiguration Pattern:
# Pure application configuration - no framework noise adapters = configure( DomainAdapter1(business_rule=value), DomainAdapter2(), ..., variants={CustomType: {...}}, # Optional type serialization )
Key Benefits:
bin/bz)When adding new adapters:
adapters/, workflows/)for_configuring_adapters.py with Configure classfrom path import Configure as ShortNameconfigure() call in configuration.pyWhen modifying configuration:
configuration.pybin/bz shim should rarely need modificationWhen upgrading taew:
configure() function signature compatibility