Welcome to the sage-development guide! This document will help you get started with contributing to SAGE.
Use ./quickstart.sh for installation to ensure consistency across all environments.
- Development Setup
- Prerequisites
- Initial Setup
- Dependency Management
- Layer Ownership Matrix
- Core Dependencies Architecture
- Per-Layer Dependencies
- Capability Packages
- Installation Examples
- Development Workflow
- Code Quality
- Testing
- Documentation
- Release Process
- Python 3.11 or higher
- Git
- (Optional) Conda for environment management
🔧 作为框架贡献者,推荐使用 dev 模式安装:
# Clone repository
git clone https://github.com/RIDE-Lab/SAGE.git
cd SAGE
# Use canonical branch
git checkout main
# One-command setup for contributors (recommended)
./quickstart.sh --dev --yes--dev 模式会自动:
- ✅ 安装所有开发依赖(pytest, pre-commit, 代码检查工具等)
- ✅ 配置 Git hooks(自动代码质量检查)
- ✅ 安装 sage-dev 工具(用于维护和测试)
- ✅ 尽量将同级工作区本地子仓库安装为 editable(
-e,若仓库存在)
--standard 模式会自动:
- ✅ 安装本地根目录
isagemeta 包 - ✅ 子包依赖按版本约束从 PyPI 解析(稳定/发布导向)
主仓当前维护的 sage 命令表面刻意保持精简,仅覆盖核心产品边界:
sage versionsage statussage doctorsage verifysage runtime nodessage serve gateway --jsonsage serve gateway --probe --jsonsage chatsage chat --ask "Hello, SAGE!"sage index ingest --source ./docs --index local-docs
💡 注意: 用户文档已迁移到独立的 SAGE-Docs 仓库。
当前主仓运行时对 parallelism 的约定如下:
LocalEnvironment对非 source transformation 生效,会创建本地 in-process replica worker。- replica 上下文会暴露
ctx.parallel_index与ctx.parallelism,便于算子感知自身副本编号。 - keyed 数据流在本地运行时按稳定分区路由到固定 replica;非 keyed 数据流按 round-robin 分发。
- source transformation 仍由本地 source polling 路径驱动,不会因为
parallelism自动变成多个独立本地 source 进程。 FlowNetEnvironment会把相同的parallelismhint 编译到 FlowNet actor replica 配置中;本地与 FlowNet 的用户侧并行语义保持一致。
-
Clone and switch to canonical branch
git clone https://github.com/RIDE-Lab/SAGE.git && cd SAGE git checkout main
-
Install development environment
./quickstart.sh --dev --yes
💡 For multi-folder VS Code editing, clone the
sage-docsrepository in the parent directory.
pre-commit install
# Optional: verify the current core CLI surface
sage verify
sage statusFor cross-repo boundary refactor reviews, use the canonical ownership matrix:
This matrix defines current workspace L1-L4 ownership, forbidden dependency direction, violation
examples, and remediation priority for Phase 1, including independent sub-repo coordination and
sagellm capability boundaries.
SAGE follows a minimalist core dependency strategy with a modular feature model:
- Core Dependencies (
dependencies): Only packages necessary for base functionality - Dev Dependencies (
devextra): Testing tools, linters, and development utilities - Feature Modules: Functionality available through in-tree extras or independent PyPI packages
Key Principle: We maintain minimal core to reduce bloat and installation time. Specialized functionality is available either through in-tree extras when it belongs to the SAGE product surface, or through independent packages when ownership should stay external.
The root package only publishes code discovered from src/ in pyproject.toml, so ownership
decisions must follow the release boundary instead of repository convenience.
- Code that is imported by the public
sage.foundation,sage.stream,sage.runtime,sage.serving, orsage.edgeruntime surface must live undersrc/sage. - Code used only by
quickstart.sh,manage.sh, Git hooks, CI checks, maintenance commands, or one-shot migration flows must stay undertools/. - Do not add imports from
src/sage/foundation,src/sage/runtime,src/sage/stream,src/sage/serving, orsrc/sage/edgeintotoolsorsage.tools, and do not hard-code repository-relativetools/paths from those runtime layers. - Install bootstrap, cleanup, repo-governance, documentation checks, hook management, and
dependency audit helpers are repository tooling and must remain in
tools/. - Move a
tools/implementation intosrc/sageonly when it is required by a published user path after install and is reused as product behavior rather than as repository maintenance. - Do not migrate test harnesses, validation reports, sample hook files, or developer-only shell
helpers into
src/sage, even if they are frequently invoked. - Roll back a boundary migration if it introduces upward/development dependencies, expands default
release dependencies without product justification, or breaks
quickstart.sh,sage verify, or the core import surface. - Every PR that moves code across the boundary must include evidence for call sites, packaging impact, and validation scope in the description so reviewers can verify the ownership change.
The automated guard is python3 tools/maintenance/checks/check_release_tools_boundary.py, wired
into pre-commit as release-tools-boundary-check. It blocks CRITICAL/HIGH violations and keeps
new misplaced runtime-layer files as MEDIUM warnings until they are intentionally promoted.
Current workspace numbering is normalized to the actively maintained main repos:
Core:
pyyaml>=6.0- Configuration filespsutil>=6.1.0- System informationdill>=0.3.8- Object serializationnumpy>=1.26.0,<2.3.0- Numerical computationpydantic>=2.10.0,<3.0.0- Data validationplatformdirs>=4.0.0- User paths
Also owns now: former platform abstractions and the shared interface surface that used to live in historical split algorithm packages.
Core:
- in-tree
sage.runtime.flownetpackage - distributed runtime backend (merged into SAGE) fastapi>=0.115.0,<1.0.0- Kernel HTTP servicegrpcio>=1.74.0,<2.0.0- RPC communicationmsgpack>=1.1.0,<2.0.0- Serializationopenai>=1.52.0/httpx>=0.28.0- absorbed middleware runtime operators
Also owns now: former runtime-bound adapter/operator responsibilities.
Core:
typer>=0.15.0- CLI frameworkrich>=13.0.0- Pretty outputclick>=8.0.0- Command parsingjinja2>=3.1.0- Templates- in-tree
sage-devcommand - Dev utilities
Role: top layer of the core workspace stack; applications should extend it rather than sit as peers.
Typical deps:
isage>=...- full framework integrationfastapi>=.../ frontend stacks - application API & UI- app-specific packages such as
isagellm,isage-agentic,isage-neuromem
Note: optional apps are above sage-cli, not the same layer, because they extend the core via
plugin, service, or API surfaces rather than defining the core product boundary.
Packages such as isage-rag, isage-neuromem, isage-libs-intent, and isage-sias remain
important capability dependencies, but they are no longer used as separate main-repo layer labels in
the workspace numbering.
Thin-wrapper rule: do not introduce new external packages that merely re-export SAGE-owned runtime, stream, or serving-boundary logic. If a package does not own substantial functionality, keep it in-tree.
Current application of this rule: sage-edge has been folded back into the main repo as
sage.edge; treat the former split repo as retired instead of retaining it as a separate Zoo
package.
Immediate non-Zoo retirement candidates follow the same logic: historical split foundation, runtime, and CLI repos are increasingly just release channels for product surfaces that already belong to the main repo, and duplicate stream surfaces should not be expanded as a separate ownership line.
The product direction is now to converge the highest-value capabilities into the main SAGE
repository and reduce dependency on UI-first or thin-wrapper repos.
Priority order:
- Foundation in-tree: keep centralized config, ports, user paths, model asset registry, logging, and shared contracts close to the main repo.
- Stream/runtime in-tree: keep
DataStream,LocalEnvironment,JobManager, scheduling, and service lifecycle as the execution core. - Serving boundary in-tree, engine out-of-tree: keep OpenAI-compatible access, health/status,
and integration contracts in SAGE, while leaving inference-engine internals in
isagellm. - Edge shell in-tree: keep edge aggregation as part of the SAGE serving contract instead of a long-lived thin wrapper repository.
- Capabilities as adapters: RAG, memory, tool-use, evaluation, and benchmark modules should be optional adapters unless they clearly strengthen the inference-service core.
Distributed-runtime rule: FlowNetEnvironment should remain a first-class optional public API
for cluster execution. The consolidation target is not “distributed-only SAGE”; it is “stream-first
SAGE” with a strong local default plus FlowNet-backed scale-out when needed, and no new Ray-oriented
dependency path.
Inference-engine rule: do not absorb isagellm internals into SAGE. isagellm is itself an
independent inference engine and should remain separately owned/released. SAGE may standardize the
integration boundary around it, but not re-home its backend/control-plane internals.
Migration rule: do not add compatibility shims for old repo boundaries during consolidation; instead, move ownership deliberately and update call sites directly.
Retirement rule: do not delete historical split foundation/runtime repositories until both conditions are true: (1) main-repo call sites and install/verification workflows no longer rely on their implementation modules as hard dependencies, and (2) external example/tutorial/adapter repos no longer need those repos as transitional compatibility owners.
Zoo rule of thumb: if a repository is not an MCP-facing tool surface, not an independently valuable
engine/runtime, and not a clearly optional adapter with substantial owned logic, it should default
back into the main SAGE repo instead of living forever as a split package.
Current status note: the main repo now owns the primary sage.foundation, sage.stream,
sage.runtime, sage.serving, and sage.cli product surfaces directly. The local runtime path and
scheduler / packet / job-manager primitives are now also owned in-tree, so the historical runtime
split package is no longer a direct root dependency of isage. Remaining kernel/common usage is now
primarily a compatibility and ecosystem-migration concern rather than a main-repo public-API
dependency.
Interpreter note: in Python 3.13 environments, root installation currently skips automatic
isagellm resolution because upstream isagellm-protocol wheels are not yet available there. This
does not block stream/runtime development in the main repo.
Current optional functionality is exposed through root-package extras and a small set of external adapter packages:
| Install Target | Purpose |
|---|---|
isage[sagellm] |
External inference engine integration (isagellm) |
isage[serving-edge] |
In-tree edge shell runtime (sage-edge) |
isage[capability-adapters] |
Intent, RAG, and memory adapters |
isage[capability-tooluse] |
SIAS tool-use adapter |
isage[full] |
All supported extras plus isage-data |
Avoid treating historical split module names as the current install contract. The preferred surface
is the in-tree sage.foundation, sage.stream, sage.runtime, sage.serving, sage.edge, and
sage.cli packages.
python -m pip install isagepython -m pip install isageThen add extras as needed:
python -m pip install 'isage[sagellm]'
python -m pip install 'isage[capability-adapters]'
python -m pip install 'isage[capability-tooluse]'cd /path/to/SAGE
./quickstart.sh --dev --yes # Installs core + dev tools + editable-first local deps
./quickstart.sh --standard --yes # Installs core + dependencies from PyPI (stable path)The sage-dev CLI now ships in-tree with the main SAGE repository and provides the same development
workflows:
# Format code / auto-fix quality issues
sage-dev quality fix --all-files
# Run the full quality gate used in contributor docs
sage-dev quality check --all-files --readme
# Run tests
sage-dev project test --coverage
# Clean build artifacts
sage-dev project clean --target all
# Clean build cache (egg-info, build, dist)
make clean-cache
# Or use the cache cleaner directly
bash tools/install/fixes/build_cache_cleaner.sh clean
# Build documentation
sage-dev docs build
# Get help
sage-dev --helpSAGE includes automatic build cache detection and cleaning to prevent version inconsistencies:
Automatic Cache Cleaning (during installation):
quickstart.shautomatically detects and cleans staleegg-infocaches- Checks for version mismatches between cached metadata and source code
- Only cleans caches when inconsistencies are detected
Manual Cache Cleaning (when needed):
# Clean all build caches (egg-info, build, dist)
make clean-cache
# Or use the cleaner tool directly
bash tools/install/fixes/build_cache_cleaner.sh clean
# Just detect and clean egg-info (automatic during install)
bash tools/install/fixes/build_cache_cleaner.sh detectWhen to clean cache manually:
- After git pull if versions seem wrong
- Before reinstalling after version changes
- When
pip listshows inconsistent versions
Note: The quickstart.sh script handles this automatically, so manual cleaning is rarely
needed.
SAGE centralizes all development tool caches in the .sage/cache/ directory to keep the project
root clean. The following environment variables are configured in .env:
# Ruff cache directory (for linting)
RUFF_CACHE_DIR=.sage/cache/ruff
# Mypy cache directory (for type checking)
MYPY_CACHE_DIR=.sage/cache/mypyPytest cache is configured in pytest.ini:
cache_dir = .sage/cache/pytestWhy centralize caches?
- ✅ Keeps project root directory clean
- ✅ Easy to clean all caches with
sage-dev project clean - ✅ Consistent location across all tools
- ✅ Follows SAGE architectural design (
.sage/for project-level artifacts)
To clean all caches:
# Clean all temporary files and caches
sage-dev project clean --target all
# Clean only cache files
sage-dev project clean --target cache
# Preview what will be cleaned
sage-dev project clean --dry-runPre-commit hooks run automatically on git commit. They include:
- Code Formatting: ruff format
- Linting: ruff check
- Shell Scripts: shellcheck
- File Checks: trailing whitespace, end-of-file fixer, etc.
- Security: detect-secrets
To run pre-commit manually:
pre-commit run --all-filesSAGE uses the root .pre-commit-config.yaml as the single source of truth for pre-commit.
Installation and Usage:
# Recommended: Use sage-dev (auto-detects correct config)
sage-dev maintain hooks install
# Alternative: Standard pre-commit
pre-commit install
# Manual: Explicit config path
pre-commit install --config .pre-commit-config.yaml
# Run checks manually (same as CI)
pre-commit run --all-filesLocal and CI Consistency:
Both local Git hooks and GitHub Actions CI use the same configuration file
(.pre-commit-config.yaml):
- ✅ Local: Uses
.pre-commit-config.yamldirectly - ✅ CI: Uses
--config .pre-commit-config.yamlexplicitly - ✅ Result: Identical checks locally and in CI
Verify your setup:
# Check hook configuration
cat .git/hooks/pre-commit | grep "ARGS="
# Expected: ARGS=(hook-impl --config=.pre-commit-config.yaml ...)
# Run full checks (matches CI exactly)
pre-commit run --all-files
# Check individual hooks
pre-commit run ruff --all-files
pre-commit run ruff-format --all-filesSAGE uses Ruff as the primary formatter and linter. Black and isort are intentionally disabled
in .pre-commit-config.yaml to avoid formatter conflicts.
# Format all code
sage-dev quality fix --all-files
# Or run Ruff directly
ruff format --config tools/ruff.tomlConfiguration:
- Line length: 100 characters
- Formatter and linter config:
tools/ruff.toml
Use Ruff for linting and mypy as an optional type-checking pass when your change touches typed Python APIs.
# Run all linters
sage-dev quality check --all-files --readme
# Or run individually:
ruff check --config tools/ruff.toml
mypy src || trueRuff Configuration (in pyproject.toml or .ruff.toml):
- Line length: 100
- Target Python version: 3.11
- Enable modern Python features
Shell scripts are checked with shellcheck:
shellcheck scripts/**/*.sh tools/**/*.sh# Run all tests
sage-dev project test --coverage
# Run specific test file
pytest src/tests/test_cli_main.py -v
# Run integration-marked tests only
pytest src/tests -m integration -v- Place repository tests under
src/tests/ - Use
@pytest.mark.integrationfor integration coverage - Use descriptive test names:
test_<function>_<scenario>_<expected_result> - Use pytest fixtures for common setup
- Keep test imports rooted at the current in-tree surface
Example:
import pytest
from sage.runtime import LocalEnvironment
def test_local_environment_initialization_creates_instance():
"""Test that LocalEnvironment can be initialized."""
env = LocalEnvironment("test_env")
assert env is not None
assert env.name == "test_env"
@pytest.mark.integration
def test_pipeline_execution_with_real_data():
"""Integration test with actual data processing."""
# Your integration test here
passUser-facing documentation belongs in the separate sage-docs repository. In this meta repo, keep
only root entry documents and machine-owned governance artifacts.
-
API Documentation: Use docstrings with Google style
def example_function(param1: str, param2: int) -> bool: """Brief description of function. Detailed description of what the function does. Args: param1: Description of param1 param2: Description of param2 Returns: Description of return value Raises: ValueError: When invalid input is provided Examples: >>> example_function("test", 42) True """ pass
-
User guides: update
sage-docsinstead of adding new duplicated user-facing pages under the rootdocs/directory. -
Repo-local docs: limit changes here to root entry docs such as
README.md,DEVELOPER.md,CONTRIBUTING.md, or machine-owned governance artifacts. -
Changelog: 重要变更统一记录到
CHANGELOG.md
When documenting fixes or features:
# Edit repo changelog directly
$EDITOR CHANGELOG.md
# Add key changes under [Unreleased]We follow Semantic Versioning:
- MAJOR: Incompatible API changes
- MINOR: Backwards-compatible functionality additions
- PATCH: Backwards-compatible bug fixes
-
Update CHANGELOG.md
- Move items from
[Unreleased]to new version section - Add release date
- Update comparison links
- Move items from
-
Update version numbers
- Update the version source referenced by
pyproject.toml - Keep changelog and release metadata aligned with the published package version
- Update the version source referenced by
-
Run validation
sage-dev quality check --all-files --readme
-
Create git tag
git tag -a v0.2.0 -m "Release version 0.2.0" git push origin v0.2.0 -
Create GitHub release
- Go to GitHub releases page
- Create new release from tag
- Copy CHANGELOG entry to release notes
-
Publish to PyPI (maintainers only)
python -m build python -m twine upload dist/*
- Check existing issues and PRs to avoid duplicates
- For large changes, open an issue first to discuss
- Read
CONTRIBUTING.mdfor detailed guidelines
-
Create a feature branch
git checkout -b feature/my-feature # or git checkout -b fix/issue-123 -
Make your changes
- Write clean, documented code
- Add tests for new functionality
- Update documentation as needed
-
Run validation
sage-dev quality check --all-files --readme
-
Commit your changes
git add . git commit -m "feat: add new feature"
Follow Conventional Commits:
feat:New featuresfix:Bug fixesdocs:Documentation changesstyle:Code style changes (formatting)refactor:Code refactoringtest:Test changeschore:Build/tooling changes
-
Push and create PR
git push origin feature/my-feature
Then create a pull request on GitHub.
- All PRs require at least one approval
- Address review comments promptly
- Keep PR scope focused and manageable
- Update PR description if scope changes
- Documentation: Check
docs/,README.md, andCONTRIBUTING.md - Examples: See sage-examples repository
- Issues: Search existing issues or create new one
- Community: Join our Slack or WeChat
Thank you for contributing to SAGE! 🚀