development - nself-org/cli GitHub Wiki
Thank you for your interest in contributing to nself! This document provides guidelines and standards for contributing to the project.
- Code of Conduct
- Getting Started
- Development Setup
- Architecture Overview
- Coding Standards
- Testing Guidelines
- Submitting Changes
- Documentation
Be respectful, inclusive, and professional. We're building infrastructure tools that people depend on.
-
Fork the repository
git clone https://github.com/nself-org/cli.git cd nself -
Create a test project
mkdir ~/test-nself && cd ~/test-nself nself init
-
Never run nself commands in the nself repository itself
- The repository contains source code, not a project
- Always test in a separate directory
- Safety checks prevent accidental repository pollution
- Bash 4.0+
- Docker 20.10+
- Docker Compose v2
- Git
- curl
/
โโโ bin/ # All executable scripts
โ โโโ nself.sh # Main command dispatcher
โ โโโ *.sh # Individual command files
โ โโโ shared/ # Shared utilities and libraries
โ โ โโโ utils/ # Utility functions
โ โ โโโ config/ # Configuration defaults
โ โ โโโ hooks/ # Pre/post command hooks
โ โ โโโ auto-fix/ # Auto-fix strategies
โ โโโ services/ # Service-related scripts
โ โโโ templates/ # Service templates
โ โโโ VERSION # Version file
โโโ docs/ # Documentation
โโโ install.sh # Installation script
-
Modular Commands
- One
.shfile per command in/bin/ - Commands export a
cmd_<name>function - Wrapper dispatches to appropriate command
- One
-
Shared Utilities
- Common functions in
/bin/shared/utils/ - Always source utilities, never duplicate code
- Utilities must be idempotent (safe to source multiple times)
- Common functions in
-
Docker Compose Wrapper
# Always use the wrapper, never direct docker compose compose() { local env_file="${COMPOSE_ENV_FILE:-.env.local}" local project="${PROJECT_NAME:-nself}" if [[ -f "$env_file" ]]; then docker compose --project-name "$project" --env-file "$env_file" "$@" else docker compose --project-name "$project" "$@" fi }
-
Hooks System
- Every command calls
pre_commandat start - Every command calls
post_commandat end - Hooks handle validation, logging, cleanup
- Every command calls
-
Auto-Fix Philosophy
- Only 4 safe, predictable scenarios
- Never attempt risky operations
- Always log attempts
- User can disable with
--no-autofix
-
File Headers
#!/bin/bash # <filename> - <brief description> # Source shared utilities SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" source "$SCRIPT_DIR/shared/utils/display.sh"
-
Error Handling
set -eo pipefail # Use carefully, not always appropriate # For commands that might fail if ! some_command; then log_error "Command failed" return 1 fi
-
Function Naming
- Command functions:
cmd_<name> - Utilities:
<verb>_<noun>(e.g.,load_env,validate_port) - Internal: prefix with underscore
_internal_function
- Command functions:
-
Variable Naming
- Environment variables:
UPPERCASE_WITH_UNDERSCORES - Local variables:
lowercase_with_underscores - Constants:
readonly CONSTANT_NAME="value"
- Environment variables:
-
Logging Standards
log_info "Informational message" log_success "Operation succeeded" log_warning "Warning message" log_error "Error message" log_debug "Debug message (only if DEBUG=true)"
-
Output Formatting
- Use structured output functions from
display.sh - Never use raw
echofor user-facing output - Errors go to stderr:
>&2 - Keep output concise and actionable
- Use structured output functions from
-
Repository Protection
# Prevent running in nself repository if [[ -f "bin/nself.sh" ]] && [[ -d "bin/shared" ]]; then log_error "Cannot run in nself repository!" return 1 fi
-
Environment Validation
# Safe environment loading load_env_safe() { local env_file="${1:-.env.local}" # Validates and sources without executing }
-
Path Handling
# Always use absolute paths for safety SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-
Command Testing
cd ~/test-project nself init nself build nself up nself status nself down
-
Hook Verification
- Check logs in
logs/nself.log - Verify pre/post hooks execute
- Confirm error handling works
- Check logs in
-
Auto-Fix Testing
- Test port conflicts
- Test Docker build failures
- Test missing dependencies
- Verify limited scope
~/test-nself/ # Manual testing
/tmp/nself-test-*/ # Automated test runs
-
Branch Naming
- Features:
feature/description - Fixes:
fix/description - Docs:
docs/description
- Features:
-
Commit Messages
type: Brief description Longer explanation if needed. Fixes #123Types:
feat,fix,docs,style,refactor,test,chore -
PR Description Template
## Description Brief description of changes ## Type of Change - [ ] Bug fix - [ ] New feature - [ ] Breaking change - [ ] Documentation update ## Testing - [ ] Tested locally - [ ] Hooks verified - [ ] Auto-fix tested (if applicable) ## Checklist - [ ] Follows coding standards - [ ] Documentation updated - [ ] No duplicate code - [ ] Uses shared utilities
-
File Naming
- Use UPPERCASE with underscores:
ARCHITECTURE.MD - Exception:
README.md(GitHub convention)
- Use UPPERCASE with underscores:
-
Documentation Types
-
README.md- User-facing documentation -
ARCHITECTURE.MD- System design -
CODE_STYLE.MD- Detailed coding standards -
API.MD- Command reference
-
-
Inline Documentation
# Function: Brief description # Arguments: # $1 - Description # $2 - Description # Returns: # 0 - Success # 1 - Failure function_name() { local arg1="$1" local arg2="$2" }
Special documentation in /docs/ helps AI agents understand the codebase:
- ARCHITECTURE.MD - System design and principles
- CODE_STYLE.MD - Detailed coding patterns
- DIRECTORY_STRUCTURE.MD - File organization
- OUTPUT_STANDARDS.MD - User interface and output standards
AI agents should reference these when making changes.
-
Version File:
/bin/VERSION -
Format: Semantic versioning
MAJOR.MINOR.PATCH -
Update Process:
- Update
/bin/VERSION - Update
CHANGELOG.md - Tag release:
git tag v0.3.0
- Update
-
Create
/bin/mycommand.sh:#!/bin/bash # mycommand.sh - Brief description SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" source "$SCRIPT_DIR/shared/utils/display.sh" source "$SCRIPT_DIR/shared/hooks/pre-command.sh" source "$SCRIPT_DIR/shared/hooks/post-command.sh" cmd_mycommand() { # Implementation } export -f cmd_mycommand # Execute if run directly if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then pre_command "mycommand" || exit $? cmd_mycommand "$@" exit_code=$? post_command "mycommand" $exit_code exit $exit_code fi
-
Update help in
/bin/help.sh -
Add documentation
-
Test thoroughly
- Add to appropriate file in
/bin/shared/utils/ - Export the function
- Add safety check for double-sourcing if needed
- Document parameters and return values
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Support Development: nself.org/commercial
By contributing, you agree that your contributions will be licensed under the same license as the project (see LICENSE file).