Skip to main content
Contributions are welcome. This guide covers everything from forking the repository to passing the pre-PR checklist.

Prerequisites

  • Docker 20.10+ and Docker Compose 2.0+
  • Python 3.12.3
  • Flutter 3.38.0+ (Dart SDK ≥3.10.8)
  • Git

Setting up your development environment

1

Fork and clone

Fork the repository on GitHub, then clone your fork:
git clone https://github.com/YOUR_USERNAME/soft-architect-ai.git
cd soft-architect-ai
2

Create a Python virtual environment

python3 -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install -r src/server/requirements.txt
3

Install Flutter dependencies

cd src/client && flutter pub get
cd ../../tests && flutter pub get
4

Configure environment variables

cp .env.example .env
# Edit .env — choose LLM_PROVIDER=local or LLM_PROVIDER=cloud
5

Start the Docker stack

scripts/devops/start_stack.sh
# API:      http://localhost:8000
# API docs: http://localhost:8000/docs
# ChromaDB: http://localhost:8001
# Ollama:   http://localhost:11434
6

Set up pre-commit hooks

chmod +x .git/hooks/pre-commit
# Or use the pre-commit framework:
pip install pre-commit && pre-commit install

Gitflow branching model

The project follows Gitflow strictly. Never commit directly to main or develop.
BranchPurpose
mainProduction-ready releases only
developIntegration branch for completed features
feature/*New features and non-emergency changes
fix/*Bug fixes
security/*Security patches
# Create a feature branch from develop
git checkout develop
git pull origin develop
git checkout -b feature/my-feature

# When ready, open a PR targeting develop
git push origin feature/my-feature

Development workflow

Follow this sequence for every change:
1

Write code and tests

Follow TDD for business logic. Write a failing test first, then implement the minimum code to pass it.
# Run tests as you work
scripts/testing/run_tests.sh python
scripts/testing/run_tests.sh flutter
2

Format your code

# Python
black src/server/ --line-length 100
ruff check --fix src/server/

# Dart
dart format src/client/
3

Run type checking

# Python
python -m pyright src/server/services src/server/core

# Dart
dart analyze src/client/
4

Run the full validation suite

./scripts/testing/PRE_PUSH_VALIDATION_MASTER.sh
This script must exit with code 0 before you push. It takes approximately 4–5 minutes.
5

Commit with a conventional message

git add -A
git commit -m "feat: add RAG chunk size configuration endpoint"
Valid prefixes: feat:, fix:, docs:, style:, security:
6

Push and open a PR

git push origin feature/my-feature
Open a pull request targeting the develop branch. GitHub Actions will run the CI pipeline automatically.

Code style rules

Python

  • Formatter: Black, line length 100
  • Linter: Ruff with rule sets E, W, F, I, C90, N, UP, B, S
  • Types: Pyright strict mode — every function must have a return type annotation
  • Hashing: SHA-256 only. Never MD5 or SHA-1.
  • Imports: Typed imports only. Annotate external library types explicitly.
# ✅ Correct: annotated return type
def query(self, text: str) -> dict[str, Any]:
    ...

# ✅ Correct: SHA-256 for IDs
hashlib.sha256(raw_id.encode("utf-8")).hexdigest()

# ❌ Wrong: missing return type annotation
def query(self, text: str):
    ...

# ❌ Wrong: MD5 (flagged by Ruff S324)
hashlib.md5(raw_id.encode("utf-8")).hexdigest()

Dart / Flutter

  • Linter: flutter_lints (strict rules in analysis_options.yaml)
  • Color opacity: Always use withValues(alpha: x.x), never the deprecated withOpacity()
  • Error handling: Use Either<Failure, Success> for all domain-layer error propagation
  • Code generation: Run dart run build_runner build after modifying annotated files
// ✅ Correct: withValues(alpha:)
color.withValues(alpha: 0.5)

// ❌ Wrong: withOpacity() is deprecated
color.withOpacity(0.5)

// ✅ Correct: Either for error handling
Future<Either<Failure, ArchitectureModel>> getRecommendation(
  String projectId,
) async {
  try {
    final result = await _repository.fetch(projectId);
    return Right(result);
  } on NetworkFailure catch (e) {
    return Left(e);
  }
}

Security rules (both languages)

These rules are non-negotiable. Violations will fail code review and CI.
  • Never expose stack traces to users. Log internally; return controlled error responses.
  • Never hardcode credentials. Use .env files and runtime injection only.
  • Never commit .env files. They are listed in .gitignore.
  • Define custom exceptions in the domain layer and re-raise them from service layers.
# ❌ Wrong: exposes internals to the user
except Exception as e:
    return {"error": str(e)}

# ✅ Correct: controlled error response
except DatabaseReadError as e:
    logger.error(f"Query failed: {e.reason}", extra={"error_code": e.code})
    return {"error": e.to_dict()}

Pre-PR checklist

Copy this checklist into your pull request description before requesting a review:
### Code quality
- [ ] Black formatted: `black --check src/server/`
- [ ] Ruff clean: `ruff check src/server/`
- [ ] Pyright 0 errors: `pyright src/server/services`
- [ ] Tests pass: `pytest tests/ --cov-fail-under=80 -q`

### Security and cryptography
- [ ] No MD5 or SHA-1 usage
- [ ] No sensitive data in logs
- [ ] No hardcoded credentials or secrets
- [ ] Custom exceptions used for error handling

### Type safety
- [ ] All functions have return type annotations
- [ ] All Optional values checked explicitly
- [ ] No broad `Exception` catches (use specific types)

### Testing
- [ ] Unit tests written for all new business logic
- [ ] Edge cases covered (empty inputs, None, error paths)
- [ ] External dependencies mocked in unit tests
- [ ] Coverage ≥80% verified locally

### Documentation
- [ ] Docstrings added to all public functions
- [ ] Architecture decisions documented in code comments
- [ ] New doc pages added to both `doc/English/` and `doc/Español/`

### Git hygiene
- [ ] `PRE_PUSH_VALIDATION_MASTER.sh` passed (exit 0)
- [ ] Commit messages follow `feat:|fix:|docs:|style:|security:` convention
- [ ] No `.env` files committed
- [ ] No hardcoded paths or credentials in source code

Documentation standards

All project documentation lives in doc/ and follows a bilingual mirror structure:
doc/
├── English/    # English documentation
└── Español/    # Spanish documentation (identical structure)
Every document added to doc/English/ must have a corresponding translation in doc/Español/ with the same filename and directory path. The language is determined by the parent directory, not by a file extension.
File naming rules:
  • Use UPPERCASE_SNAKE_CASE for document filenames
  • Never use .en.md or .es.md extensions (these are the old system)
  • Place files in the correct category subfolder (01-PROJECT_REPORT/, 02-SETUP_DEV/, etc.)
Run the sync script after adding documents to keep the mirror consistent:
python3 doc/scripts/sync_mirror_bilingual.py

# Verify both directories have the same structure
diff -r doc/English/ doc/Español/ --brief | grep -v "Binary"

License

SoftArchitect AI is released under the GPL-3.0 license. By contributing, you agree that your contributions will be licensed under GPL-3.0.

Build docs developers (and LLMs) love