Nano Banana Pro
Agent skill for nano-banana-pro
This document contains important rules, conventions, and structural information for AI agents (like Claude) working on this codebase. These guidelines help ensure consistency, safety, and efficiency when making changes.
Sign in to like and favorite skills
This document contains important rules, conventions, and structural information for AI agents (like Claude) working on this codebase. These guidelines help ensure consistency, safety, and efficiency when making changes.
ONLY COMMIT FILES YOU ACTIVELY WORKED ON - This is critical
When committing changes, ONLY stage and commit the specific files you created or modified
NEVER use
git add -A or git add . without carefully reviewing what will be committed
NEVER commit files that were modified/added/deleted by other processes or users
Always use
git status to review changes before committing
Use selective staging:
git add <specific-file> for only the files you worked on
Example workflow:
# Review all changes first git status # Only stage the specific files you modified git add docker-compose.yml git add AGENTS.md # Verify what will be committed git status # Then commit git commit -m "Update docker-compose to use chart/files/grafana"
NEVER PUSH TO REMOTE - The user handles all git push operations
git commitgit push or git push origin <branch>git commit, not git pushALWAYS USE
WITH GIT COMMANDS - Prevents hanging on interactive prompts--no-pager
Git commands can open interactive pagers (like
less or more) which will hang waiting for user input
Always use
git --no-pager <command> to prevent this
Examples:
git --no-pager status git --no-pager log git --no-pager diff git --no-pager show
Exception: Simple commands like
git add, git commit don't need --no-pager
AMEND COMMITS WHEN FIXING ERRORS IN THE SAME CHAT - Keep history clean
If you're fixing an error or making adjustments to work done in the same conversation, use
git commit --amend
Only create new commits if the previous work has been pushed to remote
Check if commits have been pushed:
git --no-pager log origin/main..HEAD
Example:
# Make fix to previous work git add chart/files/grafana/dashboards/jupyterhub-demographics.json # Amend the previous commit instead of creating a new one git commit --amend --no-edit
Use
--amend -m "new message" if you need to update the commit message
UPDATE Chart.yaml VERSION AFTER CHANGES - Keep versions in sync
Any changes to files in the
chart/ directory require a version bump in chart/Chart.yaml
Version bump guidelines (follow Semantic Versioning):
Example changes:
# chart/Chart.yaml version: 1.3.0 # Bump this after changes
ONLY BUMP VERSION IF NOT PUSHED - Check before versioning
git --no-pager log origin/main..HEADgit --no-pager tag -l "v1.3.0"MAINTAIN values.schema.json - Keep schema up to date
chart/values.schema.json file must be kept in sync with chart/values.yamlvalues.yaml"type": ["string", "null"] or "type": ["object", "null"]Chart.yaml with schema changes in the artifacthub.io/changes annotationchart/values.schema.jsonUPDATE ARTIFACTHUB.IO CHANGES - Document changes in Chart.yaml
Helm charts can include an
artifacthub.io/changes annotation in Chart.yaml
Document ALL changes made in the version, even small ones
Format:
annotations: artifacthub.io/changes: | - kind: added description: Added Users by College and Users by Application tables to demographics dashboard - kind: changed description: Updated all demographics tables to show GPU/CPU hours - kind: fixed description: Fixed incorrect column widths in dashboard tables
Valid kinds:
added, changed, deprecated, removed, fixed, security
MAINTAIN CHANGELOG.md - Document all releases
Keep a
CHANGELOG.md file in the chart/ directory
The version in the changelog MUST match the version in
Chart.yaml
Follow Keep a Changelog format
Include sections: Added, Changed, Deprecated, Removed, Fixed, Security
Example:
## [1.3.0] - 2025-11-03 ### Added - Users by College table in demographics dashboard - Users by Application table in demographics dashboard ### Changed - Updated all demographics tables to display GPU Hours, CPU Hours, and Total Hours - Reorganized demographics dashboard into 2x2 grid layout
Location:
chart/CHANGELOG.md
NEVER DROP TABLES - Especially when upgrading or modifying schemas
ALTER TABLE to modify existing tablesIF NOT EXISTS when creating new tables or columnsALTER TABLE users ADD COLUMN IF NOT EXISTS department TEXT; instead of dropping and recreatingNEVER DELETE DATA - Unless explicitly requested by the user
init-db.sql or add-policies.sqlAlways Use Transactions for Data Modifications
jupyterhub-metrics/ āāā .env # Database credentials and configuration (DO NOT COMMIT) āāā .env.example # Template for environment variables āāā add-policies.sql # TimescaleDB policies (compression, aggregates) āāā migrations/ # Database migration and fix scripts ā āāā migrate_*.sql # Database migration scripts (dated/versioned) ā āāā fix_*.sql # One-off data fix scripts āāā AGENTS.md # This file - guidelines for AI agents āāā README.md # Project documentation
IMPORTANT: The main database schema (
init-db.sql) and Grafana dashboards are maintained in chart/files/ - see Helm Chart section below.
āāā export_user_details.py # Fetch user details from MS Graph (device auth) āāā export_user_details_with_token.py # Fetch user details from MS Graph (token auth) āāā export_user_usage_stats.py # Export user usage statistics to CSV āāā test_*.py # Test scripts (don't modify production data)
collector/ āāā collector.sh # Main data collection script (runs every 5 minutes) āāā Dockerfile # Container for running collector
chart/ āāā Chart.yaml # Helm chart metadata āāā values.yaml # Default configuration values āāā cori-dev.yaml # Environment-specific overrides (not tracked) āāā templates/ # Kubernetes manifests ā āāā deployment.yaml # TimescaleDB deployment ā āāā service.yaml # Database service ā āāā cronjob.yaml # Collector cronjob ā āāā configmap.yaml # Configuration āāā files/ # **PRIMARY SOURCE** for all config files āāā init-db.sql # Main database schema (edit this, not root) āāā grafana/ āāā provisioning/ # Grafana provisioning configs āāā dashboards/ # Grafana dashboard JSON files āāā jupyterhub-demographics.json
CRITICAL: The
chart/files/ directory is the single source of truth for:
init-db.sql)Edit files in
chart/files/ directly. Do NOT create duplicates in the root directory.
history/ āāā venv/ # Python virtual environment for scripts
users - User Informationemailuser_id, full_name, department, job_title, first_seen, last_seenexport_user_details*.py scriptscontainer_observations - Raw Time Series Data(user_email, pod_name, timestamp)timestamp, user_email, node_name, container_image, container_base, container_version, age_seconds, pod_namecollector/collector.shuser_sessions - Materialized Viewuser_email, pod_name, node_name, session_id, session_start, session_end, runtime_hours, container_base, container_versionREFRESH MATERIALIZED VIEW CONCURRENTLY user_sessions;user_session_stats - Regular Viewuser_email, total_hours, gpu_hours, cpu_hours, total_sessions, applications_used, first_session, last_sessionhourly_node_stats - Hourly statistics per Kubernetes nodehourly_image_stats - Hourly statistics per container imageAlways Use the Existing Virtual Environment
history/venv/source history/venv/bin/activateEnvironment Configuration
.env file using the load_env_file() pattern (see existing scripts)DB_* environment variables for database connectionDB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORDScript Naming Conventions
export_*.py - Scripts that export data to CSVtest_*.py - Scripts that test functionality without modifying production datamigrations/migrate_*.sql - Database migration scripts (include date if possible)migrations/fix_*.sql - One-off data correction scriptsCSV Export Conventions
user_usage_stats.csvuser_details_20251024_123456.csvIdempotent Operations
Always use
IF EXISTS / IF NOT EXISTS where applicable
Scripts should be safe to run multiple times
Example:
ALTER TABLE users ADD COLUMN IF NOT EXISTS department TEXT;
Comments and Documentation
Migration Scripts
migrations/ for migrations (don't modify chart/files/init-db.sql for one-off changes)migrations/migrate_add_user_fields.sqlComment Spacing - CRITICAL
# character)key: "value" # comment (2 spaces)key: "value" # comment (1 space - will fail yamllint)chart/values.yamlWhy This Matters
Special Cases to Remember
"JOB_TITLE, Actual Department""GRAD TEACHING ASST, Siebel School Comp & Data Sci" ā job_title="GRAD TEACHING ASST", department="Siebel School Comp & Data Sci"GPU vs CPU Detection
node_name NOT ILIKE '%cpu%' for GPU hoursIncremental Update (default - only new users):
export ACCESS_TOKEN="your_token_here" python export_user_details_with_token.py
Full Refresh (all users):
export ACCESS_TOKEN="your_token_here" python export_user_details_with_token.py --refresh
python export_user_usage_stats.py # Outputs: user_usage_stats.csv # Fields: fullname, email, department, jobtitle, gpu_hours, cpu_hours, total_hours, total_sessions, last_seen, favorite_container
Create a new migration file in the migrations folder:
migrations/migrate_description_YYYYMMDD.sql
Use idempotent operations (IF EXISTS, IF NOT EXISTS)
Test the migration:
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f migrations/migrate_description.sql
Update
chart/files/init-db.sql if the changes should apply to new deployments
All configuration files are maintained in
:chart/files/
chart/files/init-db.sql directlychart/files/grafana/dashboards/*.json directlychart/files/grafana/provisioning/* directlyBoth
docker-compose.yml and Kubernetes deployments reference these files.
Do NOT create duplicate copies in the root directory.
Every 5 minutes:
collector/collector.sh runs
container_observations tableuser_sessions materialized viewusers table with latest last_seen timestampHourly: TimescaleDB continuous aggregate policies update
hourly_node_stats - node usage by hourhourly_image_stats - container image usage by hourOn-demand: User detail synchronization
export_user_details_with_token.py to fetch latest user info from Microsoft Graphfull_name, department, job_title in users tablesource history/venv/bin/activate.env file exists and has correct credentialspsql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "SELECT version();"SELECT * FROM pg_extension WHERE extname = 'timescaledb';SELECT * FROM timescaledb_information.jobs;SELECT schemaname, matviewname, last_refresh FROM pg_matviews;user_sessions materialized view being refreshedexport_user_details_with_token.py --refreshBefore making significant changes:
init-db.sql)IF EXISTS / IF NOT EXISTS for idempotent operationsinit-db.sql and chart/files/init-db.sql if neededDear Future AI Agent:
If you discover new important patterns, conventions, or safety rules while working on this codebase, please update this document in the relevant section. This helps maintain institutional knowledge across conversations.
When adding new rules:
Remember: This codebase tracks valuable long-term research data. Preservation and accuracy are more important than convenience.
Last Updated: 2025-11-03
Version: 1.1
Maintained By: AI Agents working with the JupyterHub Metrics project team