diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..84b057e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +# Require review from the repository owner for every path by default. +* @Deathcharge diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5a53cb6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +version: 2 +updates: + - package-ecosystem: pip + directory: / + schedule: + interval: monthly + open-pull-requests-limit: 5 + + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ee22244 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,94 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +name: CI + +on: + push: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Test (${{ matrix.os }}, Python ${{ matrix.python }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + python: ["3.11", "3.14"] + + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: ${{ matrix.python }} + + - name: Install package + run: python -m pip install --disable-pip-version-check . + + - name: Run unit and command tests + run: python -m unittest discover -s tests -v + + - name: Run strict repository readiness check + run: samsarix-platform doctor samsarix-stack.toml --strict + + - name: Verify JSON readiness output + run: samsarix-platform doctor samsarix-stack.toml --json --strict + + quality: + name: Quality and package + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + + - name: Install package and pinned development tools + run: | + python -m pip install --disable-pip-version-check -e . + python -m pip install --disable-pip-version-check -r requirements-dev.txt + + - name: Check formatting + run: python -m ruff format --check . + + - name: Lint + run: python -m ruff check . + + - name: Type check + run: python -m mypy src tests + + - name: Test with branch coverage + run: | + python -m coverage erase + python -m coverage run -m unittest discover -s tests + python -m coverage report + + - name: Build distributions + run: python -m build + + - name: Check distribution metadata + run: python -m twine check dist/* + + - name: Reinstall and smoke-test the wheel + run: | + python -m pip install --disable-pip-version-check --force-reinstall dist/*.whl + samsarix-platform --version + samsarix-platform doctor samsarix-stack.toml --strict + python -m samsarix_platform --version + python -m pip check diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98c0245 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.coverage +.env +.mypy_cache/ +.pytest_cache/ +.ruff_cache/ +.venv/ +__pycache__/ +build/ +dist/ +htmlcov/ +*.egg-info/ +*.py[cod] + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f10f355 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog + +All notable changes to Samsarix Platform Doctor are documented here. + +## Unreleased + +### Added + +- Local `doctor` command with human and JSON output. +- Non-overwriting `init` command and versioned TOML manifest. +- Python, installed-distribution, environment-presence, and contained-file checks. +- Strict validation, a 1 MiB input limit, terminal-control rejection, stable exit codes, secret-value redaction, read-path containment, and destination-symlink protection. +- Unit, CLI, installed-package, example, coverage, lint, type, build, and cross-platform CI checks. +- MPL 2.0 licensing, Samsarix LLC copyright attribution, brand notices, and private support/security contacts. + +### Changed + +- Reframed the repository from an unimplemented multi-agent platform into an independent readiness CLI. +- Renamed the pre-release distribution, import package, command, manifest, and JSON schema from Helix to Samsarix. +- Replaced speculative architecture, deployment, performance, security, community, and license claims with verified documentation. + +### Removed + +- Uninstallable dependencies on unpublished Helix distributions. +- Obsolete backup documentation and fabricated cloud/container deployment instructions. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index afdaa8a..cea49a4 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,60 +1,27 @@ -# Code of Conduct +# Code of conduct -## Our Commitment +## Our commitment -We are committed to providing a welcoming, inclusive, and harassment-free community for everyone. We value the participation of each member and want all contributors to have a positive experience. +Project spaces should be welcoming, professional, and free from harassment. Participants are expected to communicate respectfully, assume good faith while evaluating evidence, and make room for people with different backgrounds and experience levels. -## Expected Behavior +## Expected behavior -We expect all community members to: +- Be respectful, specific, and constructive. +- Focus criticism on ideas, code, and observable behavior. +- Protect private information and credentials. +- Accept corrections and resolve disagreements with evidence. +- Respect project scope, maintainer decisions, and community boundaries. -- **Be respectful** - Treat others with kindness and respect -- **Be inclusive** - Welcome people of all backgrounds and experience levels -- **Be constructive** - Provide helpful feedback and support -- **Be professional** - Keep discussions focused and productive -- **Be honest** - Act with integrity and transparency +## Unacceptable behavior -## Unacceptable Behavior +- Harassment, discrimination, threats, or personal attacks. +- Sexualized language or unwelcome attention. +- Publishing another person's private information without permission. +- Deliberate disruption, impersonation, or repeated bad-faith engagement. +- Pressuring anyone to disclose credentials or nonpublic security details. -The following behaviors are not tolerated: +## Scope and enforcement -- Harassment, discrimination, or bullying -- Offensive language or personal attacks -- Unwelcome sexual attention or advances -- Sharing others' private information without consent -- Disruptive or trolling behavior -- Any form of intimidation or threats +This code applies in repository issues, pull requests, discussions, and other official project spaces. Maintainers may edit or remove contributions, restrict participation, or ban participants when necessary to protect the community. -## Reporting Issues - -If you experience or witness unacceptable behavior: - -1. **Document** the incident (date, time, people involved, description) -2. **Report** to the maintainers at conduct@helix-platform.ai -3. **Include** any relevant context or evidence -4. **Remain** confidential and respectful - -## Enforcement - -Violations of this code of conduct may result in: - -- Warning or temporary suspension -- Removal from the community -- Permanent ban from the project - -## Scope - -This code of conduct applies to: -- GitHub repositories and issues -- Pull request discussions -- Community forums and chat -- Official events and meetings -- Any official project communication - -## Questions? - -If you have questions about this code of conduct, please contact the maintainers. - ---- - -**We are committed to fostering an inclusive and welcoming community.** 🌍 +Use GitHub's report/block controls for urgent platform abuse. Report project conduct concerns privately to [support@samsarix.com](mailto:support@samsarix.com) with the subject `Conduct: Samsarix Platform Doctor`. Do not disclose secrets or sensitive personal information in a public issue. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cd1a42..cb916ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,211 +1,75 @@ -# Contributing to Helix Platform +# Contributing -Thank you for your interest in contributing to Helix Platform! This document provides guidelines for contributing to the project. +Samsarix Platform Doctor is a small, local-first CLI. Contributions should preserve its narrow scope, deterministic behavior, and no-network/no-secret-output defaults. -## Code of Conduct +## Setup -We are committed to providing a welcoming and inspiring community for all. Please read and follow our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). +Python 3.11 or newer is required. -## Getting Started - -1. **Fork the repository** on GitHub -2. **Clone your fork** locally -3. **Create a branch** for your changes (`git checkout -b feature/amazing-feature`) -4. **Make your changes** following our code standards -5. **Write tests** for your changes -6. **Commit your changes** with clear messages -7. **Push to your fork** and submit a pull request - -## Development Setup - -```bash -# Clone repository -git clone https://github.com/Deathcharge/helix-platform.git -cd helix-platform - -# Create virtual environment -python -m venv venv -source venv/bin/activate - -# Install development dependencies -pip install -r requirements-dev.txt - -# Run tests -pytest tests/ -v -``` - -## Code Standards - -### Python Code Style - -- Follow PEP 8 guidelines -- Use type hints for all functions -- Maximum line length: 100 characters -- Use meaningful variable names -- Add docstrings to all functions and classes - -### Example - -```python -def process_agent_response( - agent_name: str, - response: str, - timeout: int = 30 -) -> Dict[str, Any]: - """ - Process a response from an agent. - - Args: - agent_name: Name of the agent - response: Response text from agent - timeout: Processing timeout in seconds - - Returns: - Dictionary containing processed response - - Raises: - TimeoutError: If processing exceeds timeout - """ - # Implementation - pass -``` - -## Testing - -### Write Tests - -All new features must include tests: - -```python -def test_agent_registration(): - """Test that agents can be registered""" - orchestrator = HelixOrchestrator() - orchestrator.register_agent("test", "Gemini") - assert "test" in orchestrator.agents +```console +git clone https://github.com/Deathcharge/samsarix-platform.git +cd samsarix-platform +python -m venv .venv ``` -### Run Tests - -```bash -# Run all tests -pytest tests/ -v - -# Run specific test -pytest tests/test_orchestration.py::test_agent_registration -v +Activate the virtual environment, then install the package and pinned development tools: -# Run with coverage -pytest tests/ --cov=helix_platform --cov-report=html +```console +python -m pip install -e . +python -m pip install -r requirements-dev.txt ``` -### Coverage Requirements - -- Minimum 80% code coverage -- All public methods must have tests -- Integration tests required for new features - -## Documentation - -### Update Documentation +## Before opening a pull request -- Update relevant `.md` files in `docs/` -- Add docstrings to code -- Include examples for new features -- Update API reference if needed - -### Documentation Standards - -- Use clear, concise language -- Include code examples -- Add diagrams for complex concepts -- Keep documentation up-to-date with code - -## Commit Messages - -Use clear, descriptive commit messages: +Run: +```console +python -m ruff format --check . +python -m ruff check . +python -m mypy src tests +python -m coverage erase +python -m coverage run -m unittest discover -s tests +python -m coverage report +python -m build +python -m twine check dist/* +samsarix-platform doctor samsarix-stack.toml --strict ``` -feat: Add consensus voting mechanism -- Implement supermajority voting strategy -- Add unanimous consensus option -- Add tests for voting logic -- Update documentation +CI runs the unit tests and installed CLI journey on Windows and Linux, then repeats lint, type, coverage, and build checks on Linux. -Fixes #123 -``` +## Change expectations -### Commit Message Format - -- **feat**: New feature -- **fix**: Bug fix -- **docs**: Documentation changes -- **style**: Code style changes -- **refactor**: Code refactoring -- **test**: Test additions/changes -- **chore**: Build/dependency changes - -## Pull Request Process - -1. **Update documentation** if needed -2. **Add tests** for new functionality -3. **Ensure all tests pass** (`pytest tests/ -v`) -4. **Check code coverage** (minimum 80%) -5. **Request review** from maintainers -6. **Address feedback** and update PR -7. **Merge** once approved - -### PR Template - -```markdown -## Description -Brief description of changes - -## Type of Change -- [ ] Bug fix -- [ ] New feature -- [ ] Documentation update - -## Testing -- [ ] Added tests -- [ ] All tests pass -- [ ] Coverage maintained - -## Checklist -- [ ] Code follows style guidelines -- [ ] Documentation updated -- [ ] No breaking changes -``` +- Add or update tests for behavior changes, including failure and recovery paths. +- Keep human output understandable and JSON output backward compatible within schema v1. +- Reject invalid configuration rather than silently weakening checks. +- Never print environment-variable values or import a declared component merely to test presence. +- Keep filesystem access inside the manifest's project root. +- Add bounded timeouts and cancellation before proposing any future network or subprocess check. +- Update the README, example, changelog, and `docs/PRODUCTIZATION.md` when public behavior or release status changes. -## Reporting Issues +The project uses a 100-character line limit, Ruff formatting/linting, strict mypy, and a 90% branch-aware coverage floor. -### Bug Reports +## Commit and pull-request guidance -Include: -- Python version and OS -- Steps to reproduce -- Expected vs actual behavior -- Error messages and logs -- Minimal code example +Prefer focused commits with an imperative summary such as `fix: reject resolved symlink escapes`. A pull request should explain: -### Feature Requests +- the user problem and scope; +- public behavior and compatibility impact; +- security/privacy implications; +- tests and exact commands run; +- documentation changes; +- any remaining limitation. -Include: -- Use case and motivation -- Proposed solution -- Alternative approaches -- Example usage +Do not include secrets, generated `dist/` artifacts, local virtual environments, or unrelated formatting changes. -## Community +## Issues and security reports -- **GitHub Issues**: Report bugs and request features -- **Discussions**: Ask questions and share ideas -- **Discord**: Join our community server -- **Twitter**: Follow @HelixCollective +Use GitHub Issues for reproducible bugs and bounded feature proposals. Include the operating system, Python version, command, manifest with secrets removed, exit code, and expected versus actual result. -## License +For vulnerabilities, email [support@samsarix.com](mailto:support@samsarix.com) or use GitHub private vulnerability reporting when available. Do not post exploit details or secrets publicly. See [SECURITY.md](SECURITY.md). -By contributing, you agree that your contributions will be licensed under the same license as the project (Apache 2.0 / Proprietary). +For general project or partnership questions, email [contact@samsarix.com](mailto:contact@samsarix.com). ---- +## Contribution license -Thank you for contributing to Helix Platform! πŸ™ +This project is licensed under the [Mozilla Public License 2.0](LICENSE). By submitting a contribution, you agree that it is available under MPL 2.0 and represent that you have the right to provide it. Copyright in a contribution remains with its copyright holder unless a separate written agreement says otherwise. New Python files should include `SPDX-License-Identifier: MPL-2.0`; add an accurate copyright notice when appropriate. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..570135f --- /dev/null +++ b/LICENSE @@ -0,0 +1,374 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000..4366654 --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,17 @@ +# Samsarix Platform notices + +Copyright (c) 2026 Samsarix LLC. + +This Source Code Form is subject to the terms of the Mozilla Public License, +version 2.0. If a copy of the MPL was not distributed with this software, you +can obtain one at . + +The Samsarix name, Samsarix Platform Doctor name, and associated logos and +brand assets belong to Samsarix LLC. The MPL 2.0 software license does not +grant trademark rights or permission to imply affiliation with, sponsorship +by, or endorsement from Samsarix LLC. Truthful references required by the +license or permitted by applicable law are unaffected. + +General contact: + +Product support and private security reports: diff --git a/QUICK_START.md b/QUICK_START.md index 38782ab..919f687 100644 --- a/QUICK_START.md +++ b/QUICK_START.md @@ -1,456 +1,59 @@ -# Helix Platform Quick Start Guide +# Quick start -Get up and running with Helix Platform in 5 minutes. +Samsarix Platform Doctor performs local readiness checks declared in `samsarix-stack.toml`. It requires Python 3.11+ and no provider credentials. ---- +## Install from this repository -## Installation (2 minutes) - -### Prerequisites -- Python 3.9+ -- pip or conda -- API keys for at least one LLM provider (OpenRouter, Anthropic, Groq, OpenAI) - -### Step 1: Clone and Setup - -```bash -git clone https://github.com/Deathcharge/helix-platform.git -cd helix-platform - -# Create virtual environment -python -m venv venv -source venv/bin/activate # On Windows: venv\Scripts\activate - -# Install dependencies -pip install -r requirements.txt -``` - -### Step 2: Configure API Keys - -Create a `.env` file: - -```bash -# .env -OPENROUTER_API_KEY=your_key_here -ANTHROPIC_API_KEY=your_key_here -GROQ_API_KEY=your_key_here -``` - -Or set environment variables: - -```bash -export OPENROUTER_API_KEY=your_key_here -export ANTHROPIC_API_KEY=your_key_here -``` - ---- - -## Your First Agent Swarm (3 minutes) - -Create `my_first_swarm.py`: - -```python -""" -Your first Helix Platform multi-agent system. -This example creates 3 agents that work together to analyze a topic. -""" - -from helix_agent_swarm import HelixOrchestrator -from unified_llm import LLMClient -from ucf_protocol import UCFProtocol - -# Step 1: Create orchestrator -print("πŸš€ Creating agent orchestrator...") -orchestrator = HelixOrchestrator() - -# Step 2: Register agents -print("πŸ‘₯ Registering agents...") - -orchestrator.register_agent( - name="researcher", - agent_type="Gemini", - system_prompt="""You are a research specialist. -Your job is to gather comprehensive information on topics. -Be thorough and cite sources when possible.""" -) - -orchestrator.register_agent( - name="validator", - agent_type="Kavach", - system_prompt="""You are a fact validator. -Your job is to check claims and assess credibility. -Be skeptical and look for potential biases.""" -) - -orchestrator.register_agent( - name="synthesizer", - agent_type="Agni", - system_prompt="""You are a knowledge synthesizer. -Your job is to create coherent summaries from multiple sources. -Connect ideas and highlight key insights.""" -) - -# Step 3: Create LLM client -print("🧠 Initializing LLM client...") -llm = LLMClient(provider="openrouter") - -# Step 4: Execute task -print("\nπŸ“‹ Task: Analyze the impact of AI on society") -print("-" * 50) - -# Get research from first agent -print("\n1️⃣ Researcher gathering information...") -research = llm.generate({ - "prompt": "What are the key impacts of AI on society?", - "system": orchestrator.agents["researcher"].system_prompt, - "max_tokens": 500 -}) -print(f"Research findings:\n{research}\n") - -# Get validation from second agent -print("2️⃣ Validator checking facts...") -validation = llm.generate({ - "prompt": f"Validate these claims: {research}", - "system": orchestrator.agents["validator"].system_prompt, - "max_tokens": 300 -}) -print(f"Validation results:\n{validation}\n") - -# Get synthesis from third agent -print("3️⃣ Synthesizer creating summary...") -synthesis = llm.generate({ - "prompt": f"Create a summary: {research}", - "system": orchestrator.agents["synthesizer"].system_prompt, - "max_tokens": 400 -}) -print(f"Final synthesis:\n{synthesis}\n") - -# Step 5: Monitor system health -print("-" * 50) -print("πŸ“Š System Metrics") -state = orchestrator.get_state() -metrics = UCFProtocol().calculate_metrics(state) - -print(f"βœ… System Harmony: {metrics.harmony:.2f}/1.0") -print(f"βœ… System Resilience: {metrics.resilience:.2f}/1.0") -print(f"βœ… Current Phase: {metrics.phase}") - -print("\n✨ Multi-agent analysis complete!") -``` - -### Run It - -```bash -python my_first_swarm.py -``` - -### Expected Output - -``` -πŸš€ Creating agent orchestrator... -πŸ‘₯ Registering agents... -🧠 Initializing LLM client... - -πŸ“‹ Task: Analyze the impact of AI on society --------------------------------------------------- - -1️⃣ Researcher gathering information... -Research findings: -AI is transforming society through... - -2️⃣ Validator checking facts... -Validation results: -These claims are generally accurate... - -3️⃣ Synthesizer creating summary... -Final synthesis: -AI's impact on society includes... - --------------------------------------------------- -πŸ“Š System Metrics -βœ… System Harmony: 0.87/1.0 -βœ… System Resilience: 0.92/1.0 -βœ… Current Phase: HARMONIOUS - -✨ Multi-agent analysis complete! -``` - ---- - -## Next Examples to Try - -### Example 2: Consensus Voting - -Agents vote on proposals and make collective decisions: - -```bash -python examples/02_consensus_voting.py -``` - -### Example 3: Scheduled Workflows - -Execute complex workflows on a schedule: - -```bash -python examples/03_scheduled_workflow.py -``` - -### Example 4: Customer Support System - -Build a complete support system with specialized agents: - -```bash -python examples/04_customer_support.py -``` - ---- - -## Common Patterns - -### Pattern 1: Sequential Agent Processing - -Process information through multiple agents in sequence: - -```python -# Agent 1 processes -result1 = llm.generate({"prompt": "...", "system": agent1_prompt}) - -# Agent 2 processes result from Agent 1 -result2 = llm.generate({"prompt": result1, "system": agent2_prompt}) - -# Agent 3 processes result from Agent 2 -result3 = llm.generate({"prompt": result2, "system": agent3_prompt}) +```console +python -m venv .venv ``` -### Pattern 2: Parallel Agent Processing - -Process with multiple agents in parallel: - -```python -from concurrent.futures import ThreadPoolExecutor - -def process_with_agent(agent_name, prompt): - return llm.generate({ - "prompt": prompt, - "system": orchestrator.agents[agent_name].system_prompt - }) - -with ThreadPoolExecutor(max_workers=3) as executor: - results = list(executor.map( - lambda agent: process_with_agent(agent, prompt), - orchestrator.agents.keys() - )) -``` - -### Pattern 3: Consensus Voting - -Have agents vote on a proposal: - -```python -from agent_consensus import ConsensusEngine, Proposal +```console +# macOS or Linux +source .venv/bin/activate -consensus = ConsensusEngine() - -proposal = Proposal( - title="Deploy new feature", - description="Should we deploy the new feature?", - details={"timeline": "1 week", "risk": "low"} -) - -result = consensus.vote( - proposal=proposal, - agents=list(orchestrator.agents.values()), - strategy="supermajority" -) - -if result.agreed: - print("βœ… Proposal approved!") -else: - print("❌ Proposal rejected") +# Windows PowerShell +.venv\Scripts\Activate.ps1 ``` ---- - -## Configuration - -### Basic Configuration - -```python -from helix_agent_swarm import HelixOrchestrator - -# Create with custom settings -orchestrator = HelixOrchestrator( - max_agents=50, - communication_timeout=30, - agent_timeout=300, - enable_metrics=True, - enable_persistence=True -) +```console +python -m pip install . +samsarix-platform doctor ``` -### LLM Configuration - -```python -from unified_llm import LLMClient +The repository manifest should finish with: -# Use different providers -llm = LLMClient(provider="anthropic") # Anthropic Claude -llm = LLMClient(provider="groq") # Groq (free) -llm = LLMClient(provider="openrouter") # OpenRouter (multiple models) -llm = LLMClient(provider="openai") # OpenAI GPT -llm = LLMClient(provider="ollama") # Local Ollama +```text +Summary: 5 passed, 0 warned, 0 failed +Result: READY ``` -### Agent Customization +## Start a manifest in your project -```python -# Create custom agent with specific personality -orchestrator.register_agent( - name="creative", - agent_type="Agni", - system_prompt="""You are a creative thinker... - -Your personality: -- Think outside the box -- Suggest innovative solutions -- Challenge conventional wisdom - -Your constraints: -- Stay practical and implementable -- Consider resource constraints -- Align with team goals""", - - # Optional: custom parameters - temperature=0.8, # More creative - max_tokens=2000, - personality_profile={ - "creativity": 0.9, - "caution": 0.3, - "collaboration": 0.8 - } -) +```console +cd your-agent-project +samsarix-platform init +samsarix-platform doctor ``` ---- - -## Monitoring & Debugging - -### Check System Health - -```python -# Get current state -state = orchestrator.get_state() +`init` creates only a project and Python requirement. Edit `samsarix-stack.toml` to declare packages, environment variables, and files your application genuinely needs. It refuses to overwrite an existing file. -# Get metrics -metrics = UCFProtocol().calculate_metrics(state) +## Try the example -print(f"Agents active: {len(state.agents)}") -print(f"Messages processed: {state.message_count}") -print(f"Harmony: {metrics.harmony:.2f}") -print(f"Phase: {metrics.phase}") +```console +samsarix-platform doctor examples/agent-project/samsarix-stack.toml ``` -### Enable Logging +The example declares the OpenAI SDK and `OPENAI_API_KEY` as optional. If absent, they produce warnings but the command exits `0`. In CI, use strict mode to make warnings exit `1`: -```python -import logging - -# Set log level -logging.basicConfig(level=logging.DEBUG) - -# Now you'll see detailed logs -orchestrator = HelixOrchestrator() +```console +samsarix-platform doctor examples/agent-project/samsarix-stack.toml --strict ``` -### View Agent State +For automation output: -```python -# Get specific agent state -agent = orchestrator.agents["researcher"] -print(f"Agent: {agent.name}") -print(f"Type: {agent.agent_type}") -print(f"Status: {agent.status}") -print(f"Tasks completed: {agent.task_count}") -print(f"Last activity: {agent.last_activity}") +```console +samsarix-platform doctor --json ``` ---- - -## Troubleshooting - -### Issue: "API Key not found" - -**Solution**: Make sure your API key is set: - -```bash -# Check environment variable -echo $OPENROUTER_API_KEY - -# Or set it -export OPENROUTER_API_KEY=your_key_here -``` - -### Issue: "Agent timeout" - -**Solution**: Increase timeout or check LLM provider: - -```python -orchestrator = HelixOrchestrator(agent_timeout=600) # 10 minutes -``` - -### Issue: "Low harmony score" - -**Solution**: Check agent alignment and communication: - -```python -# Reduce number of agents -# Improve system prompts -# Increase communication timeout -orchestrator = HelixOrchestrator(communication_timeout=60) -``` - -### Issue: "Memory usage high" - -**Solution**: Enable persistence and clear history: - -```python -# Clear old messages -orchestrator.clear_message_history(older_than_hours=24) - -# Enable persistence to disk -orchestrator.enable_persistence() -``` - ---- - -## Next Steps - -1. **Explore Examples**: Check `examples/` for 4 complete examples -2. **Read Documentation**: See `docs/` for detailed guides -3. **Try Integration**: Build your own multi-agent system -4. **Deploy**: Use Docker or Kubernetes deployment guides -5. **Join Community**: Connect with other developers - ---- - -## Resources - -- **Full Documentation**: [docs/](docs/) -- **API Reference**: [docs/API_REFERENCE.md](docs/API_REFERENCE.md) -- **Architecture Guide**: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) -- **Integration Examples**: [examples/](examples/) -- **GitHub Issues**: Report bugs and request features -- **Community**: Join our Discord server - ---- - -## Getting Help - -- **Documentation**: https://docs.helix-platform.ai -- **GitHub Issues**: https://github.com/Deathcharge/helix-platform/issues -- **Email**: support@helix-platform.ai -- **Discord**: https://discord.gg/helix-platform - ---- - -**Happy building! πŸš€** +Exit `0` means ready under the selected strictness, `1` means declared checks are not ready, and `2` means invalid usage or manifest input. See [README.md](README.md) for the complete schema and security boundaries. diff --git a/README.backup.md b/README.backup.md deleted file mode 100644 index 0b3ca13..0000000 --- a/README.backup.md +++ /dev/null @@ -1,405 +0,0 @@ -# Helix Platform - -**The Complete Multi-Agent AI System for Building Intelligent Collectives** - -Helix Platform is a unified ecosystem for building, deploying, and managing sophisticated multi-agent AI systems. It brings together 15 specialized repositories into a cohesive platform that enables developers to create intelligent agents that collaborate, learn, and make collective decisions. - ---- - -## 🎯 What is Helix Platform? - -Helix Platform is not just a collection of toolsβ€”it's a **complete operating system for multi-agent AI**. It provides: - -- **Agent Orchestration**: Create and manage swarms of specialized AI agents -- **Intelligent Coordination**: Enable agents to work together seamlessly -- **Consensus Mechanisms**: Make collective decisions with built-in voting and agreement protocols -- **LLM Integration**: Leverage multiple LLM providers (OpenAI, Anthropic, Groq, OpenRouter) -- **Workflow Automation**: Schedule and execute complex multi-step workflows -- **Real-time Communication**: Enable agents to communicate via WebSocket and chat -- **System Monitoring**: Track agent health, harmony, and system metrics -- **Production Deployment**: Deploy to Docker, Kubernetes, or cloud platforms - ---- - -## πŸ—οΈ Architecture Overview - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Application Layer β”‚ -β”‚ (Your custom agents, workflows, and business logic) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Orchestration Layer β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Agent Swarm β”‚ β”‚ Consensus β”‚ β”‚ Routine β”‚ β”‚ -β”‚ β”‚ Management β”‚ β”‚ Voting β”‚ β”‚ Engine β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Intelligence Layer β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Unified LLM β”‚ β”‚ Chat Engine β”‚ β”‚ Creative β”‚ β”‚ -β”‚ β”‚ Orchestrationβ”‚ β”‚ β”‚ β”‚ Studio β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Foundation Layer β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ UCF Protocol β”‚ β”‚ Hub Shared β”‚ β”‚ Web OS β”‚ β”‚ -β”‚ β”‚ (Metrics) β”‚ β”‚ (Utilities) β”‚ β”‚ (Platform) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## πŸ“¦ Core Components - -### Orchestration & Coordination -- **helix-agent-swarm** - Multi-agent orchestration and collective management -- **agent-consensus** - Voting mechanisms and consensus algorithms -- **routine-engine** - Workflow scheduling and execution - -### Intelligence & Processing -- **unified-llm** - Multi-provider LLM orchestration -- **helix-chat-engine** - Real-time communication and messaging -- **helix-creative-studio** - Creative and generative capabilities - -### Foundation & Infrastructure -- **ucf-protocol** - Universal Coordination Framework with consciousness metrics -- **helix-hub-shared** - Shared utilities and infrastructure -- **helix-web-os** - Web-based platform and dashboard - -### Integration & Extensions -- **helix-discord-bot** - Discord integration for agents -- **helix-browser-extension** - Browser automation and integration -- **Helix-Collective-Web** - Web interface for the collective -- **Helix-Unified-Hub** - Central hub for ecosystem management - ---- - -## πŸš€ Quick Start - -### Installation - -```bash -# Clone the Helix Platform repository -git clone https://github.com/Deathcharge/helix-platform.git -cd helix-platform - -# Install core dependencies -pip install -r requirements.txt - -# Install optional components -pip install -r requirements-optional.txt -``` - -### Your First Multi-Agent System - -```python -from helix_agent_swarm import HelixOrchestrator -from unified_llm import LLMClient -from ucf_protocol import UCFProtocol - -# Create orchestrator -orchestrator = HelixOrchestrator() - -# Register agents -orchestrator.register_agent("analyst", "Gemini", - system_prompt="You are a data analyst") -orchestrator.register_agent("validator", "Kavach", - system_prompt="You are a fact validator") - -# Create LLM client -llm = LLMClient(provider="openrouter") - -# Execute task with agents -result = llm.generate({ - "prompt": "Analyze this data and validate findings", - "agents": list(orchestrator.agents.values()) -}) - -# Monitor system health -state = orchestrator.get_state() -metrics = UCFProtocol().calculate_metrics(state) -print(f"System Harmony: {metrics.harmony:.2f}") -``` - -### Next Steps - -1. **Explore Examples**: See `examples/` directory for 4 complete integration examples -2. **Read Architecture Guide**: Check `docs/ARCHITECTURE.md` for deep dive -3. **Try Tutorials**: Follow step-by-step guides in `docs/TUTORIALS/` -4. **Deploy**: Use deployment guides in `docs/DEPLOYMENT/` - ---- - -## πŸ“š Documentation - -### Getting Started -- **[Quick Start Guide](docs/QUICK_START.md)** - Get up and running in 5 minutes -- **[Installation Guide](docs/INSTALLATION.md)** - Detailed setup instructions -- **[Architecture Overview](docs/ARCHITECTURE.md)** - System design and data flows - -### Integration Examples -- **[Multi-Agent Research Pipeline](examples/01_research_pipeline.py)** - Information gathering and synthesis -- **[Consensus-Based Decision Making](examples/02_consensus_voting.py)** - Collective voting -- **[Scheduled Workflow with Monitoring](examples/03_scheduled_workflow.py)** - Workflow automation -- **[End-to-End Application](examples/04_customer_support.py)** - Complete system - -### Advanced Topics -- **[Agent Development Guide](docs/AGENT_DEVELOPMENT.md)** - Create custom agents -- **[LLM Integration Guide](docs/LLM_INTEGRATION.md)** - Use different LLM providers -- **[Performance Tuning](docs/PERFORMANCE.md)** - Optimize your system -- **[Monitoring & Observability](docs/MONITORING.md)** - Track system health - -### Deployment -- **[Docker Deployment](docs/DEPLOYMENT_DOCKER.md)** - Containerized deployment -- **[Kubernetes Deployment](docs/DEPLOYMENT_K8S.md)** - Scalable cloud deployment -- **[Cloud Platforms](docs/DEPLOYMENT_CLOUD.md)** - AWS, Azure, GCP guides - ---- - -## 🎯 Common Use Cases - -### Research & Analysis -Build intelligent research systems where multiple agents gather, validate, and synthesize information. - -```python -# See: examples/01_research_pipeline.py -``` - -### Decision Making -Enable collective decision-making with consensus voting and conflict resolution. - -```python -# See: examples/02_consensus_voting.py -``` - -### Workflow Automation -Automate complex multi-step workflows with scheduling and monitoring. - -```python -# See: examples/03_scheduled_workflow.py -``` - -### Customer Support -Build intelligent customer support systems with specialized support agents. - -```python -# See: examples/04_customer_support.py -``` - ---- - -## πŸ”§ Configuration - -### Environment Variables - -```bash -# LLM Configuration -OPENROUTER_API_KEY=your_key_here -ANTHROPIC_API_KEY=your_key_here -GROQ_API_KEY=your_key_here - -# System Configuration -HELIX_LOG_LEVEL=INFO -HELIX_METRICS_ENABLED=true -HELIX_PERSISTENCE_ENABLED=true - -# Deployment Configuration -HELIX_DEPLOYMENT_MODE=production -HELIX_WORKERS=4 -HELIX_PORT=8000 -``` - -### Configuration File - -```yaml -# helix-config.yaml -orchestration: - max_agents: 100 - agent_timeout: 300 - communication_timeout: 30 - -intelligence: - default_provider: openrouter - model_selection_strategy: cost_optimized - fallback_providers: - - anthropic - - groq - -coordination: - consensus_strategy: supermajority - voting_timeout: 60 - conflict_resolution: automatic - -monitoring: - metrics_enabled: true - metrics_interval: 10 - logging_level: INFO -``` - ---- - -## πŸ“Š System Metrics - -Helix Platform continuously monitors system health through the UCF (Universal Coordination Framework): - -| Metric | Range | Interpretation | -|--------|-------|-----------------| -| **Harmony** | 0.0 - 1.0 | How well agents are aligned (higher is better) | -| **Resilience** | 0.0 - 1.0 | System's ability to handle failures (higher is better) | -| **Phase** | CRITICAL to TRANSCENDENT | Current system state | -| **Coherence** | 0.0 - 1.0 | Quality of inter-agent communication | -| **Emergence** | 0.0 - 1.0 | Level of collective intelligence | - -### Monitoring Dashboard - -Access the real-time monitoring dashboard at `http://localhost:8000/dashboard` to visualize: -- Agent states and activities -- System harmony and resilience -- Message flows and communication patterns -- Performance metrics and latency -- Error rates and recovery status - ---- - -## πŸ§ͺ Testing - -### Run All Tests - -```bash -# Run comprehensive test suite -pytest tests/ -v - -# Run with coverage -pytest tests/ --cov=helix_platform --cov-report=html - -# Run specific test category -pytest tests/test_orchestration.py -v -pytest tests/test_consensus.py -v -pytest tests/test_integration.py -v -``` - -### Test Coverage - -The Helix Platform includes 500+ tests covering: -- Unit tests for all components -- Integration tests for component interactions -- End-to-end tests for complete workflows -- Performance benchmarks -- Stress tests for scalability - -Current coverage: **85%+** - ---- - -## πŸš€ Deployment - -### Local Development - -```bash -# Start development server -python -m helix_platform.server --dev - -# Start with hot reload -python -m helix_platform.server --dev --reload -``` - -### Docker Deployment - -```bash -# Build Docker image -docker build -t helix-platform:latest . - -# Run container -docker run -p 8000:8000 helix-platform:latest - -# Docker Compose (recommended) -docker-compose up -d -``` - -### Kubernetes Deployment - -```bash -# Deploy to Kubernetes -kubectl apply -f k8s/deployment.yaml -kubectl apply -f k8s/service.yaml - -# Check status -kubectl get pods -l app=helix-platform -kubectl logs -f deployment/helix-platform -``` - ---- - -## 🀝 Contributing - -We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on: -- Code style and standards -- Testing requirements -- Pull request process -- Development workflow - -### Development Setup - -```bash -# Clone repository -git clone https://github.com/Deathcharge/helix-platform.git -cd helix-platform - -# Create virtual environment -python -m venv venv -source venv/bin/activate - -# Install development dependencies -pip install -r requirements-dev.txt - -# Run tests -pytest tests/ -v -``` - ---- - -## πŸ“‹ Community - -- **GitHub Issues**: Report bugs and request features -- **Discussions**: Ask questions and share ideas -- **Discord**: Join our community server (link in repo) -- **Twitter**: Follow @HelixCollective for updates - ---- - -## πŸ“„ License - -Helix Platform is dual-licensed: -- **Apache 2.0** - For open source projects -- **Proprietary** - For commercial use - -See [LICENSE](LICENSE) for details. - ---- - -## πŸ™ Acknowledgments - -Helix Platform is built on the foundation of 15 specialized repositories, each contributing unique capabilities to the ecosystem. Special thanks to all contributors and the open source community. - ---- - -## πŸ“ž Support - -For support and questions: -- **Documentation**: https://docs.helix-platform.ai -- **Issues**: https://github.com/Deathcharge/helix-platform/issues -- **Email**: support@helix-platform.ai -- **Community**: https://discord.gg/helix-platform - ---- - -**Built with ❀️ by the Helix Collective** - -*Transform your ideas into intelligent multi-agent systems* diff --git a/README.md b/README.md index 4151244..7af77a7 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,217 @@ -# helix-platform +# Samsarix Platform Doctor -Central integration hub for the Helix Collective ecosystem. Provides platform overview, quick start guides, integration examples, and deployment documentation. +Samsarix Platform Doctor is a local command-line tool from **Samsarix LLC** that checks whether a Python multi-agent project has the runtime, installed packages, configuration names, and files it declares. -## 🎯 Overview +It is for developers who want an actionable preflight before starting an agent application or running its CIβ€”not another agent framework or hosted service. -This repository is part of the [Helix Collective](https://github.com/Deathcharge/helix-platform), a comprehensive ecosystem for building intelligent, multi-agent systems with consciousness frameworks and advanced LLM integration. +> Status: `0.1.0` pre-release. The core local workflow is implemented, tested, and licensed under MPL 2.0, but the package has not been published. -## πŸš€ Quick Start +## What it does -### Installation +Given a versioned `samsarix-stack.toml`, `samsarix-platform doctor` checks: -\`\`\`bash -git clone https://github.com/Deathcharge/helix-platform.git -cd helix-platform -pip install -r requirements.txt -\`\`\` +- the active Python version; +- whether declared Python distributions are installed; +- whether declared environment variables are present; +- whether declared project-relative files or directories exist. -### Basic Usage +It produces human-readable output by default and stable JSON for automation. It does not import declared packages, validate credential contents, load `.env`, execute manifest commands, call an LLM, make network requests, or send telemetry. -See the [examples/](examples/) directory for working examples and integration patterns. +## Fastest successful setup -## πŸ“š Documentation +Prerequisite: Python 3.11 or newer. -- **[Architecture](docs/ARCHITECTURE.md)** - System design and components -- **[API Reference](docs/API.md)** - Complete API documentation -- **[Integration Guide](docs/INTEGRATION.md)** - How to integrate with other Helix repos -- **[Deployment](docs/DEPLOYMENT.md)** - Production deployment guide -- **[Contributing](CONTRIBUTING.md)** - How to contribute +```console +git clone https://github.com/Deathcharge/samsarix-platform.git +cd samsarix-platform +python -m venv .venv +``` -## πŸ”— Related Repositories +Activate the environment: -- **[helix-platform](https://github.com/Deathcharge/helix-platform)** - Central hub and integration guide -- **[helix-unified](https://github.com/Deathcharge/helix-unified)** - Main unified codebase -- **[helix-core](https://github.com/Deathcharge/helix-core)** - Core utilities and LLM integration +```console +# macOS or Linux +source .venv/bin/activate -See [HELIX_REPOSITORY_INDEX.md](https://github.com/Deathcharge/helix-platform/blob/main/HELIX_REPOSITORY_INDEX.md) for the complete ecosystem map. +# Windows PowerShell +.venv\Scripts\Activate.ps1 +``` -## πŸ§ͺ Testing +Install and check this repository's manifest: -Run tests with pytest: +```console +python -m pip install . +samsarix-platform doctor +``` -\`\`\`bash -pytest tests/ -v --cov=src -\`\`\` +Expected summary: -## πŸ”„ CI/CD +```text +Summary: 5 passed, 0 warned, 0 failed +Result: READY +``` -This repository uses GitHub Actions for: -- βœ… Automated testing (Python 3.9, 3.10, 3.11) -- βœ… Code linting (flake8) -- βœ… Type checking (mypy) -- βœ… Security scanning (bandit, safety) -- βœ… Coverage reporting (Codecov) +No API key, external Samsarix service, database, container runtime, or cloud account is required. -See [.github/workflows/ci.yml](.github/workflows/ci.yml) for details. +## Use it in another project -## πŸ“‹ Requirements +Generate a starter manifest without overwriting existing content: -- Python 3.9+ -- Dependencies listed in requirements.txt -- Development dependencies in requirements-dev.txt +```console +cd your-agent-project +samsarix-platform init +samsarix-platform doctor +``` -## 🀝 Contributing +Then add the checks your project actually requires: -We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for: -- Development setup -- Code style guide -- Testing requirements -- Pull request process +```toml +schema_version = 1 -## πŸ“„ License +[project] +name = "research-agent" +requires_python = ">=3.11" -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. +[[components]] +name = "OpenAI Python SDK" +distribution = "openai" +required = true -## πŸ†˜ Support +[[environment]] +name = "OPENAI_API_KEY" +required = true +secret = true -- **Issues**: Report bugs or request features via [GitHub Issues](https://github.com/Deathcharge/helix-platform/issues) -- **Discussions**: Ask questions in [GitHub Discussions](https://github.com/Deathcharge/helix-platform/discussions) -- **Documentation**: See the [docs/](docs/) directory -- **Ecosystem**: Visit [helix-platform](https://github.com/Deathcharge/helix-platform) +[[files]] +path = "config/agents.toml" +required = true +``` -## πŸŽ“ Learn More +Run the check: -- [Helix Collective Repository Index](https://github.com/Deathcharge/helix-platform/blob/main/HELIX_REPOSITORY_INDEX.md) -- [Architecture Guide](https://github.com/Deathcharge/helix-platform/blob/main/docs/ARCHITECTURE.md) -- [Integration Examples](https://github.com/Deathcharge/helix-platform/tree/main/examples) +```console +samsarix-platform doctor +``` ---- +Use strict mode in CI when optional warnings should also block readiness: -**Status**: βœ… Production Ready -**Last Updated**: June 17, 2026 -**Maintainer**: Helix Collective Contributors +```console +samsarix-platform doctor --strict +``` + +Use JSON when another tool needs the result: + +```console +samsarix-platform doctor --json +``` + +See the runnable [example agent-project manifest](examples/agent-project/samsarix-stack.toml). + +## Command reference + +```text +samsarix-platform --help +samsarix-platform --version +samsarix-platform init [PATH] [--name NAME] +samsarix-platform doctor [MANIFEST] [--json] [--strict] +``` + +`init` uses exclusive file creation and exits `2` rather than replacing an existing path or following an existing destination symlink. + +### Exit codes + +| Code | Meaning | +| --- | --- | +| `0` | All required checks pass; optional warnings are allowed unless `--strict` is set. | +| `1` | A required check failed, or an optional check warned under `--strict`. | +| `2` | The command usage or manifest is invalid, unreadable, missing, or unsafe. | + +### Manifest schema version 1 + +Unknown keys and duplicate declarations are errors so misspellings do not silently weaken a check. +Manifests must be UTF-8, are limited to 1 MiB, and cannot place control/formatting characters in rendered fields. + +| Section | Fields | Behavior | +| --- | --- | --- | +| root | `schema_version = 1` | Required. Other versions fail explicitly. | +| `[project]` | `name`, `requires_python` | Both required. Python constraints support `>=MAJOR.MINOR[.PATCH]`. | +| `[[components]]` | `name`, `distribution`, `required`, `description` | Checks installed distribution metadata without importing code. `required` defaults to `true`. | +| `[[environment]]` | `name`, `required`, `secret`, `description` | Checks for a nonblank process environment value. Values are never reported. Both booleans default to `true`. | +| `[[files]]` | `path`, `required`, `description` | Uses portable forward-slash paths contained by the manifest directory. `required` defaults to `true`. | + +Descriptions are documentation metadata for the manifest. Version 1 intentionally does not execute commands, inspect file contents, contact endpoints, or validate package APIs. + +## Development + +Install the package and pinned development tools: + +```console +python -m pip install -e . +python -m pip install -r requirements-dev.txt +``` + +Run the same checks protected by CI: + +```console +python -m ruff format --check . +python -m ruff check . +python -m mypy src tests +python -m coverage erase +python -m coverage run -m unittest discover -s tests +python -m coverage report +python -m build +python -m twine check dist/* +samsarix-platform doctor samsarix-stack.toml --strict +``` + +The runtime has no third-party dependencies. `requirements-dev.txt` is tooling-only and exactly pinned for repeatable contributor and CI checks. + +## Packaging and release + +`pyproject.toml` defines the package, `src/` layout, typed-package marker, and console entry point. A source distribution and universal wheel can be built with `python -m build`. The wheel must be installed into a fresh virtual environment and smoke-tested before release. + +Publication is not automated. See [the release guide](docs/RELEASING.md) for the verified local process and the owner-controlled PyPI, trusted-publishing, and signing gates. + +## Architecture + +The package has three small layers: + +- `manifest.py` strictly parses and validates untrusted TOML; +- `doctor.py` performs read-only local checks and creates a value-free report; +- `cli.py` handles commands, rendering, JSON, and exit codes. + +See [the architecture guide](docs/ARCHITECTURE.md) for data flow, trust boundaries, and extension rules. + +## Security, privacy, reliability, and cost + +- Declared distributions are inspected through `importlib.metadata`; they are not imported. +- Manifest file paths reject absolute paths, `..`, Windows-only separators, resolved symlink escapes, and cyclic/unresolvable links. +- Secret values are reduced to present/not-present and never included in human or JSON output. +- The parser rejects unknown keys, wrong types, duplicates, and unsupported schema versions. +- Parsing reads at most 1 MiB and rejects terminal control/formatting characters. +- `init` never overwrites a destination or follows an existing destination symlink. +- Checks are local, bounded by manifest size, and non-destructive. +- There is no network access, telemetry, AI provider use, or operating cost in the core tool. + +The manifest, variable names, project name, and checked file paths are still local project metadata; treat JSON reports accordingly. A passing report establishes only the declared presence checks, not credential validity, API compatibility, application correctness, or production safety. + +Report vulnerabilities privately to [support@samsarix.com](mailto:support@samsarix.com) or through GitHub private vulnerability reporting when it is enabled. Do not put secrets or exploit details in a public issue. See [SECURITY.md](SECURITY.md) for the reporting scope. + +## Limitations and deliberate non-goals + +- No package version-range or API compatibility validation in schema v1. +- No credential authentication or provider availability checks. +- No command, container, port, process, or network probes. +- No `.env` parsing or secret storage. +- No agent orchestration, consensus engine, scheduler, UI, service, or deployment stack. +- No claim of product-market fit, production deployment, or validated scale. + +These boundaries keep the first release predictable and safe. Proposed extensions are prioritized in [the productization record](docs/PRODUCTIZATION.md). + +## License, attribution, and contact + +Copyright (c) 2026 Samsarix LLC. The source is licensed under the [Mozilla Public License 2.0](LICENSE). Distributed modifications to covered files remain under MPL 2.0, while the license permits use in a larger work under separate terms. The license does not grant rights to Samsarix names or logos; see [NOTICE.md](NOTICE.md). + +General inquiries: [contact@samsarix.com](mailto:contact@samsarix.com). Product support: [support@samsarix.com](mailto:support@samsarix.com). + +See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and quality commands and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for participation expectations. diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..2ffd643 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,43 @@ +# Samsarix Platform Doctor roadmap + +This roadmap separates four gates: merge, release, publication, and flagship adoption. Passing one does not imply the next. + +## Product boundary + +Portfolio role: **internal infrastructure**. Use this to improve the portfolio through immutable, reviewed automation or internal deployments. It must not become a hidden runtime dependency for customer-facing products. + +Current disposition: Merge as a prerelease-quality foundation after the focused merge gates pass; release remains blocked on the items below. + +## Stabilize the productized default + +- Keep the default branch buildable from a clean checkout and preserve exact-head CI evidence. +- Keep Samsarix LLC branding, package identity, license metadata, and compatibility aliases internally consistent. +- Preserve the pre-productization default under a rollback ref before merging; do not delete legacy history. +- Locally reproduced in this pass: unit tests, formatting, lint, types, 90% coverage, and package build pass. +- Next: adopt one real manifest consumer and treat hosted zero-runner failures as infrastructure, not product failures. +- Review priority: Diagnose pre-step hosted CI failures, adopt one real manifest consumer, and require green exact-head wheel/CLI checks before release. + +## Release candidate + +- Adopt it in one repository through an immutable revision. +- Document permissions, rollback, failure isolation, and ownership. +- Measure maintenance saved before expanding portfolio-wide. + +Current hardening backlog: + +- Hosted CI is red at the exact inspected SHA and gives no diagnostic steps/logs. +- Checks only presence, not component versions, executable/API compatibility, credential validity, or service reachability. +- No evidenced adopter, public package, tag, release, or stable schema consumer. +- The `samsarix-platform` name still suggests a broader platform than the implemented doctor command. +- Package identity, private-repository visibility, and MPL publication authority need owner review. + +## Samsarix adoption + +- Define a public API, event, schema, artifact, or deployment contract before connecting to Samsarix Unified. +- Add a consumer-owned contract fixture covering authentication, privacy, limits, errors, and version compatibility. +- Make one implementation canonical; remove or freeze duplicate behavior only after parity and rollback are proven. +- Record an owner, support level, compatibility window, and measurable adoption signal. + +## Completion evidence + +A milestone is complete only when its exact commit, commands and results, artifact digest, consumer or deployment, and rollback path are recorded in a pull request or release record. README claims must not exceed that evidence. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..32f5285 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,34 @@ +# Security policy + +## Supported versions + +Samsarix Platform Doctor is currently a `0.1.x` pre-release. Security fixes are +made on the latest supported release line and the default branch. Older +pre-release snapshots may not receive fixes. + +## Report a vulnerability privately + +Email with the subject `Security: Samsarix Platform +Doctor`. Do not open a public issue for an unpatched vulnerability and do not +include live credentials, personal data, or production secrets. + +Include, when possible: + +- the affected version or commit; +- the operating system and Python version; +- reproducible steps or a minimal manifest; +- the security impact and attacker prerequisites; +- any suggested mitigation; +- how you would like to be credited. + +GitHub private vulnerability reporting may also be used when it is enabled for +this repository. Samsarix LLC will coordinate validation, remediation, and +disclosure with the reporter. Please allow time for a fix before publishing +exploit details. + +## Scope + +Reports about secret disclosure, path containment, unsafe file creation, +dependency or release integrity, and denial of service from crafted manifests +are in scope. General support requests belong at or in a +public issue after sensitive data has been removed. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 653c279..67b09a4 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,487 +1,100 @@ -# Helix Stack Architecture Guide - -## Executive Summary - -The Helix Collective is a sophisticated, distributed multi-agent system designed to coordinate intelligent agents across complex workflows. This guide explains how all 15 repositories work together to create a cohesive platform for building production-grade autonomous systems. - -**Key Insight**: Rather than isolated tools, Helix is an *ecosystem* where each component enhances the others. An agent's intelligence (unified-llm) is coordinated through consensus (agent-consensus), scheduled through workflows (routine-engine), and monitored through metrics (ucf-protocol). - ---- - -## System Architecture Overview - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ HELIX COLLECTIVE PLATFORM β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ USER INTERFACE LAYER β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Helix-Web β”‚ β”‚ Discord Bot / Chat Engine β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ Collective-Web β”‚ β”‚ (helix-chat-engine) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β–² β”‚ -β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ ORCHESTRATION LAYER β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Routine-Engine β”‚ β”‚ Helix-Agent-Swarm β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ (Scheduling) β”‚ β”‚ (Multi-Agent Coordination) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β–² β”‚ -β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ DECISION LAYER β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Agent-Consensus β”‚ β”‚ UCF Protocol β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ (Voting) β”‚ β”‚ (Consciousness Metrics) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β–² β”‚ -β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ INTELLIGENCE LAYER β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Unified-LLM β”‚ β”‚ Helix-Creative-Studio β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ (Multi-Provider)β”‚ β”‚ (Generative Capabilities) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β–² β”‚ -β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ INFRASTRUCTURE LAYER β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Helix-Hub-Sharedβ”‚ β”‚ Helix-Web-OS β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ (Core Services) β”‚ β”‚ (System Foundation) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +# Architecture + +Samsarix Platform Doctor is a single-process, local Python CLI. Its job is to turn a small project manifest into bounded readiness results; it does not run the declared application. + +## Data flow + +```mermaid +flowchart LR + A["User or CI"] --> B["CLI arguments"] + B --> C["Strict TOML parser"] + C --> D["Validated immutable manifest"] + D --> E["Python check"] + D --> F["Distribution metadata checks"] + D --> G["Environment presence checks"] + D --> H["Contained file checks"] + E --> I["Doctor report"] + F --> I + G --> I + H --> I + I --> J["Human output or JSON"] + J --> K["Exit 0, 1, or 2"] ``` ---- - -## Component Breakdown - -### Layer 1: Infrastructure Foundation - -**helix-hub-shared** (165 Python files) -- Provides core services, utilities, and shared abstractions -- Defines base classes for agents, services, and communication -- Handles logging, configuration, and common patterns -- **Role**: Foundation that all other components build upon - -**helix-web-os** (13 files) -- Operating system-like abstraction for the Helix platform -- Manages system resources and process scheduling -- Provides filesystem and memory abstractions -- **Role**: System-level resource management - -### Layer 2: Intelligence Engine - -**unified-llm** (26 Python files) -- Multi-provider LLM orchestration (OpenAI, Anthropic, Ollama, etc.) -- Handles model selection, routing, and fallback strategies -- Provides streaming, tokenization, and optimization -- **Role**: Gives agents the ability to think and reason - -**helix-creative-studio** (68 TS/JS files, full-stack) -- Generative capabilities for creative outputs -- Image, text, and multimedia generation -- Design and content creation workflows -- **Role**: Extends agent capabilities to creative domains - -### Layer 3: Coordination & Decision Making - -**ucf-protocol** (26 Python files) -- Universal Consciousness Framework for measuring agent harmony -- Tracks metrics: zoom, harmony, resilience, prana, drishti, klesha -- Provides phase detection (CRITICAL β†’ UNSTABLE β†’ COHERENT β†’ HARMONIOUS β†’ TRANSCENDENT) -- **Role**: Measures and tracks system health and agent alignment - -**agent-consensus** (3 Python files, 1,453 LOC) -- Multi-agent voting and consensus mechanisms -- Implements Simple Majority, Supermajority, Unanimous, and Byzantine Fault Tolerant algorithms -- Handles conflict resolution and deadlock prevention -- **Role**: Enables collective decision-making - -### Layer 4: Orchestration & Scheduling +## Package layout -**helix-agent-swarm** (18 agent files, 100+ tests) -- Multi-agent orchestration and coordination -- Implements 7 specialized agent types (Gemini, Kavach, Agni, SanghaCore, Shadow, Kael, Lumina) -- Manages agent lifecycle, communication, and collective operations -- **Role**: Coordinates multiple agents working together - -**routine-engine** (7 Python files) -- Workflow orchestration and scheduling -- 108-step cycle execution model (inspired by ritual cycles) -- Task execution, error handling, and recovery -- **Role**: Schedules and executes agent workflows - -### Layer 5: Communication & Interaction - -**helix-chat-engine** (4 Python files) -- WebSocket-based real-time communication -- Message routing and room management -- Event handling and broadcasting -- **Role**: Enables real-time communication between agents and users - -**helix-discord-bot** (50 Python files, 45 tests) -- Discord integration for agent interaction -- Command handling and response generation -- User authentication and permission management -- **Role**: Makes agents accessible via Discord - -### Layer 6: User Interface - -**Helix-Collective-Web** (68 TS/JS files, full-stack) -- Web dashboard for monitoring and controlling the collective -- Real-time metrics and agent status visualization -- Workflow management and creation interface -- **Role**: Central control panel for the entire system - -**helix-browser-extension** (7 Python files) -- Browser integration for agent capabilities -- Tab management and content script injection -- Local storage and API communication -- **Role**: Brings agent capabilities to the browser - ---- - -## Data Flow: A Complete Example - -### Scenario: Multi-Agent Research Task - -``` -1. USER REQUEST (via Web Dashboard) - "Research and summarize the latest AI trends" - ↓ -2. ROUTINE-ENGINE - Parses request β†’ Creates workflow schedule - Assigns tasks to agents - ↓ -3. HELIX-AGENT-SWARM - Spawns agents: - - Gemini (scout): Searches for information - - Kavach (shield): Validates sources - - Agni (transform): Processes and synthesizes - ↓ -4. UNIFIED-LLM - Each agent uses LLM to: - - Generate search queries - - Analyze content - - Write summaries - ↓ -5. AGENT-CONSENSUS - Agents vote on: - - Which sources are most reliable - - Key themes to include - - Final summary structure - ↓ -6. UCF-PROTOCOL - Monitors: - - Agent harmony (are they aligned?) - - System resilience (any failures?) - - Overall consciousness level - ↓ -7. HELIX-CHAT-ENGINE - Broadcasts updates to connected clients - ↓ -8. USER INTERFACE - Web dashboard shows: - - Agent progress - - Real-time metrics - - Final results +```text +src/samsarix_platform/ +β”œβ”€β”€ __init__.py package version +β”œβ”€β”€ __main__.py python -m entry point +β”œβ”€β”€ cli.py argument parsing, rendering, init, exit behavior +β”œβ”€β”€ doctor.py read-only checks and report model +β”œβ”€β”€ manifest.py strict schema parser and data model +└── py.typed typed-package marker ``` ---- +`manifest.py` owns syntax and structural validity. Once loaded, the rest of the package receives frozen dataclasses rather than untyped TOML objects. -## Integration Patterns +`doctor.py` owns check semantics. Each check returns one `pass`, `warn`, or `fail` result and optional remediation. Required missing items fail; optional missing items warn. Warnings become non-ready only under strict mode. -### Pattern 1: Intelligent Agent Workflow +`cli.py` owns interaction. It maps a valid report to exit `0` or `1`, maps manifest/usage errors to exit `2`, and renders the same report as human text or JSON. `init` is the only write path and uses exclusive creation. -```python -# Pseudo-code showing integration -from unified_llm import LLMClient -from helix_agent_swarm import HelixOrchestrator -from ucf_protocol import UCFProtocol -from routine_engine import WorkflowEngine +For `init`, a relative user-selected destination is joined lexically to the current directory without resolving the destination itself. Its parent must exist, existing symlinks are rejected explicitly, and exclusive creation rejects any other existing path. This keeps initialization from being redirected outside the selected project through a pre-existing destination link. -# Create orchestrator -orchestrator = HelixOrchestrator() +## Manifest contract -# Add agents -orchestrator.register_agent("researcher", agent_type="Gemini") -orchestrator.register_agent("validator", agent_type="Kavach") +Schema version 1 supports four inputs: -# Create workflow -workflow = WorkflowEngine() -workflow.add_task("research", agent="researcher", prompt="Find X") -workflow.add_task("validate", agent="validator", depends_on="research") +- project name and minimum Python version; +- installed distribution names; +- process environment-variable names; +- project-relative file or directory paths. -# Execute with monitoring -ucf = UCFProtocol() -for task in workflow.execute(): - metrics = ucf.calculate_metrics(orchestrator.get_state()) - if metrics.harmony < 0.5: - print("Warning: Low harmony detected") -``` +The schema deliberately rejects unknown keys, duplicate identities, nonportable environment names, invalid distribution names, control/formatting characters, backslash file paths, absolute paths, `..`, and unsupported versions. Manifests must be UTF-8 and are limited to 1 MiB. This makes configuration mistakes visible, prevents terminal-output forgery, bounds parser memory, and keeps the first version easy to reason about. -### Pattern 2: Consensus-Based Decision Making +The minimum Python constraint is intentionally limited to `>=MAJOR.MINOR[.PATCH]`. General PEP 440 range evaluation would require more policy and a runtime dependency; add it only with a schema-version decision and compatibility tests. -```python -from agent_consensus import ConsensusEngine -from helix_agent_swarm import HelixCollective +## Trust boundaries -# Create collective -collective = HelixCollective() +### Manifest boundary -# Create proposal -proposal = { - "action": "Deploy new agent", - "details": {...} -} +Treat the manifest as untrusted local input. The loader reads at most 1 MiB, schema processing is linear in the declared entries, and it performs no recursive evaluation, template expansion, deserialization hooks, or command execution. -# Get consensus -consensus = ConsensusEngine() -result = consensus.vote( - proposal=proposal, - agents=collective.agents, - strategy="supermajority" # Requires 2/3 agreement -) +### Component boundary -if result.agreed: - collective.execute_action(proposal) -``` +A distribution name is passed only to `importlib.metadata.version`. The declared package is never imported, so package-level code cannot execute as a side effect of the check. Presence does not establish API compatibility or safety. -### Pattern 3: Scheduled Multi-Agent Workflow +### Environment boundary -```python -from routine_engine import RoutineEngine -from helix_agent_swarm import HelixOrchestrator - -routine = RoutineEngine() -orchestrator = HelixOrchestrator() - -# Define 108-step ritual cycle -routine.define_cycle( - steps=108, - agents=orchestrator.agents, - callbacks=[ - ("every_9_steps", check_harmony), - ("every_27_steps", consensus_check), - ("every_54_steps", recalibrate), - ] -) - -# Execute with automatic recovery -routine.execute_with_resilience() -``` +The checker tests whether `environ[name]` is nonblank. It never places the value in a result, log, exception, or JSON document. The `secret` flag changes wording only; all values receive the same redaction behavior. ---- +### Filesystem boundary -## Component Interaction Matrix - -| Component | Depends On | Provides To | Communication | -|-----------|-----------|------------|----------------| -| **unified-llm** | helix-hub-shared | helix-agent-swarm, helix-creative-studio | Direct API calls | -| **helix-agent-swarm** | helix-hub-shared, unified-llm, ucf-protocol | routine-engine, agent-consensus | Message passing | -| **agent-consensus** | helix-hub-shared | helix-agent-swarm | Direct API calls | -| **ucf-protocol** | helix-hub-shared | helix-agent-swarm, routine-engine | Metrics queries | -| **routine-engine** | helix-hub-shared, helix-agent-swarm | helix-chat-engine | Event callbacks | -| **helix-chat-engine** | helix-hub-shared | helix-discord-bot, Helix-Collective-Web | WebSocket | -| **helix-creative-studio** | helix-hub-shared, unified-llm | Helix-Collective-Web | REST API | -| **Helix-Collective-Web** | All above | Users | HTTP/WebSocket | -| **helix-discord-bot** | helix-chat-engine | Discord users | Discord API | - ---- - -## Deployment Architecture - -### Local Development - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Docker Compose (Local Dev) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Python Apps β”‚ β”‚ Node.js Apps β”‚ β”‚ -β”‚ β”‚ (Agents, LLM)β”‚ β”‚ (Web, Chat) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ PostgreSQL β”‚ β”‚ Redis Cache β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Production Deployment - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Kubernetes Cluster β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Agent Services (Helix-Agent-Swarm) β”‚ β”‚ -β”‚ β”‚ - Gemini Pod β”‚ β”‚ -β”‚ β”‚ - Kavach Pod β”‚ β”‚ -β”‚ β”‚ - Agni Pod β”‚ β”‚ -β”‚ β”‚ - ... (replicated) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ LLM Service (Unified-LLM) β”‚ β”‚ -β”‚ β”‚ - Load balanced β”‚ β”‚ -β”‚ β”‚ - Auto-scaled based on load β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Web Services β”‚ β”‚ -β”‚ β”‚ - Helix-Collective-Web β”‚ β”‚ -β”‚ β”‚ - Helix-Chat-Engine β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Data Layer β”‚ β”‚ -β”‚ β”‚ - PostgreSQL (persistent) β”‚ β”‚ -β”‚ β”‚ - Redis (cache) β”‚ β”‚ -β”‚ β”‚ - Message Queue (RabbitMQ) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## Performance Characteristics - -### Latency Profile - -| Operation | Typical Latency | Notes | -|-----------|-----------------|-------| -| Agent spawn | 50-100ms | Lightweight process | -| LLM inference | 500ms-5s | Depends on model and provider | -| Consensus vote (5 agents) | 100-200ms | Simple majority | -| Workflow step | 1-10s | Includes agent execution | -| End-to-end task (10 steps) | 10-100s | Full workflow execution | - -### Scalability Limits - -- **Agents per orchestrator**: 100-1000 (tested to 1000) -- **Concurrent workflows**: 10-100 (depends on resources) -- **LLM requests/second**: 10-100 (depends on provider) -- **WebSocket connections**: 1000+ (with proper infrastructure) - ---- - -## Security Architecture - -### Authentication & Authorization - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ User Request β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ ↓ β”‚ -β”‚ OAuth2 / JWT Verification β”‚ -β”‚ ↓ β”‚ -β”‚ Role-Based Access Control (RBAC) β”‚ -β”‚ ↓ β”‚ -β”‚ Resource-Level Permissions β”‚ -β”‚ ↓ β”‚ -β”‚ Agent Execution with Constraints β”‚ -β”‚ ↓ β”‚ -β”‚ Audit Logging β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Data Protection - -- **In Transit**: TLS 1.3 for all communications -- **At Rest**: Encrypted database fields for sensitive data -- **Agent Isolation**: Each agent runs in isolated context -- **Audit Trail**: All actions logged with timestamp and user - ---- - -## Monitoring & Observability - -### Key Metrics - -1. **Agent Health** - - Uptime percentage - - Error rate - - Response latency - - Memory usage - -2. **System Health** - - Overall harmony (UCF metric) - - Consensus success rate - - Workflow completion rate - - Queue depth - -3. **Business Metrics** - - Tasks completed - - Average task duration - - User satisfaction - - Cost per task - -### Observability Stack - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Application Metrics β”‚ -β”‚ (Prometheus) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Metrics Storage & Visualization β”‚ -β”‚ (Grafana) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Alerting & Notifications β”‚ -β”‚ (AlertManager) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` +Manifest paths use POSIX separators and must be relative. Parsing rejects lexical traversal. Runtime resolution then detects symlinks that escape the manifest directory. The checker tests existence/type only and never opens a declared path. ---- +### Output boundary -## Getting Started: Integration Checklist +Reports contain project names, variable names, distribution names, installed versions, relative paths, and the absolute manifest path. These are not credential values but may still reveal project metadata. Consumers decide where JSON reports may be stored. -- [ ] Install all 15 repositories -- [ ] Set up unified-llm with your preferred LLM provider -- [ ] Configure helix-hub-shared with your database -- [ ] Start helix-agent-swarm with sample agents -- [ ] Create your first workflow with routine-engine -- [ ] Set up Helix-Collective-Web for monitoring -- [ ] Configure helix-chat-engine for real-time updates -- [ ] Test agent-consensus with sample proposals -- [ ] Verify ucf-protocol metrics are being collected -- [ ] Deploy to your infrastructure +## Failure and recovery behavior ---- +- Invalid, unreadable, or unresolvable manifest input: concise error, exit `2`; fix the manifest or path and retry. +- Missing required item: result with remediation, exit `1`; install/set/create it and retry. +- Unresolvable or cyclic declared file path: structured failed check, exit `1`; replace the link and retry. +- Missing optional item: warning, exit `0` normally or `1` under strict mode. +- Existing `init` destination: no write, exit `2`; choose another path or edit deliberately. +- Component metadata lookup: only a normal package-not-found result is converted into readiness output. Unexpected runtime errors are not hidden. -## Next Steps +Every invocation is stateless and idempotent except successful `init`. Cancellation is ordinary process termination; no cleanup or rollback is required. -1. **Phase 2**: Build 4+ integration examples showing real-world workflows -2. **Phase 3**: Create Helix Platform repository with quick-start guide -3. **Phase 4**: Build deployment guides for Docker and Kubernetes -4. **Phase 5**: Create performance tuning and optimization guides +## Compatibility and extension rules ---- +- Python 3.11-3.14 are the initial CI targets. +- Human wording may improve within a minor release; JSON field removals or semantic changes require a schema/version decision. +- New optional JSON fields can be additive. Consumers should ignore fields they do not understand. +- A new manifest feature must remain local and bounded by default, or explicitly document timeouts, retries, cancellation, redaction, and cost. +- Arbitrary command execution, component importing, `.env` loading, and automatic remediation are out of scope because they materially expand trust and side-effect boundaries. -## References +## Operating model -- [Helix Agent Swarm Documentation](https://github.com/Deathcharge/helix-agent-swarm) -- [UCF Protocol Specification](https://github.com/Deathcharge/ucf-protocol) -- [Unified LLM API Reference](https://github.com/Deathcharge/unified-llm) -- [Agent Consensus Algorithms](https://github.com/Deathcharge/agent-consensus) -- [Routine Engine Workflow Guide](https://github.com/Deathcharge/routine-engine) +The CLI needs no service, persistent storage, authentication, database, or network. Runtime operating cost is local CPU and filesystem metadata access for one short process. Distribution is a pure-Python wheel. Production concerns are package integrity and compatibility, not service deployment. diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md deleted file mode 100644 index 8df936a..0000000 --- a/docs/DEPLOYMENT.md +++ /dev/null @@ -1,728 +0,0 @@ -# Helix Platform Deployment Guide - -Complete guide to deploying Helix Platform to production environments. - ---- - -## Deployment Options - -| Option | Best For | Complexity | Cost | -|--------|----------|-----------|------| -| **Docker** | Local development, single machine | Low | Free | -| **Docker Compose** | Multi-container local setup | Low | Free | -| **Kubernetes** | Production, scalability | High | Medium | -| **AWS ECS** | AWS ecosystem | Medium | Variable | -| **Google Cloud Run** | Serverless, auto-scaling | Medium | Pay-per-use | -| **Azure Container Instances** | Azure ecosystem | Medium | Variable | - ---- - -## Docker Deployment - -### Prerequisites - -- Docker installed (version 20.10+) -- Docker Hub account (optional, for image registry) -- 2GB RAM minimum - -### Dockerfile - -Create `Dockerfile` in project root: - -```dockerfile -FROM python:3.11-slim - -WORKDIR /app - -# Install system dependencies -RUN apt-get update && apt-get install -y \ - gcc \ - && rm -rf /var/lib/apt/lists/* - -# Copy requirements -COPY requirements.txt . - -# Install Python dependencies -RUN pip install --no-cache-dir -r requirements.txt - -# Copy application code -COPY . . - -# Set environment variables -ENV PYTHONUNBUFFERED=1 -ENV HELIX_LOG_LEVEL=INFO - -# Expose port -EXPOSE 8000 - -# Health check -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ - CMD python -c "import requests; requests.get('http://localhost:8000/health')" - -# Run application -CMD ["python", "-m", "helix_platform.server"] -``` - -### Build and Run - -```bash -# Build image -docker build -t helix-platform:latest . - -# Run container -docker run -p 8000:8000 \ - -e OPENROUTER_API_KEY=your_key \ - -e HELIX_LOG_LEVEL=INFO \ - helix-platform:latest - -# Run with volume mount (for persistence) -docker run -p 8000:8000 \ - -v $(pwd)/data:/app/data \ - -e OPENROUTER_API_KEY=your_key \ - helix-platform:latest -``` - -### Docker Compose - -Create `docker-compose.yml`: - -```yaml -version: '3.8' - -services: - helix-platform: - build: . - ports: - - "8000:8000" - environment: - OPENROUTER_API_KEY: ${OPENROUTER_API_KEY} - ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} - HELIX_LOG_LEVEL: INFO - HELIX_WORKERS: 4 - volumes: - - ./data:/app/data - - ./logs:/app/logs - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 5s - - # Optional: Redis for caching - redis: - image: redis:7-alpine - ports: - - "6379:6379" - volumes: - - redis_data:/data - restart: unless-stopped - - # Optional: PostgreSQL for persistence - postgres: - image: postgres:15-alpine - environment: - POSTGRES_USER: helix - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: helix_platform - ports: - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data - restart: unless-stopped - -volumes: - redis_data: - postgres_data: -``` - -Run with Docker Compose: - -```bash -# Create .env file -cat > .env << EOF -OPENROUTER_API_KEY=your_key -ANTHROPIC_API_KEY=your_key -POSTGRES_PASSWORD=secure_password -EOF - -# Start services -docker-compose up -d - -# View logs -docker-compose logs -f helix-platform - -# Stop services -docker-compose down -``` - ---- - -## Kubernetes Deployment - -### Prerequisites - -- Kubernetes cluster (1.20+) -- kubectl configured -- Container registry access (Docker Hub, ECR, GCR) - -### Push Image to Registry - -```bash -# Tag image -docker tag helix-platform:latest your-registry/helix-platform:latest - -# Push to registry -docker push your-registry/helix-platform:latest -``` - -### Kubernetes Manifests - -Create `k8s/deployment.yaml`: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helix-platform - namespace: default -spec: - replicas: 3 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - selector: - matchLabels: - app: helix-platform - template: - metadata: - labels: - app: helix-platform - spec: - containers: - - name: helix-platform - image: your-registry/helix-platform:latest - imagePullPolicy: Always - ports: - - containerPort: 8000 - name: http - env: - - name: OPENROUTER_API_KEY - valueFrom: - secretKeyRef: - name: helix-secrets - key: openrouter-api-key - - name: HELIX_LOG_LEVEL - value: "INFO" - - name: HELIX_WORKERS - value: "4" - resources: - requests: - cpu: 500m - memory: 512Mi - limits: - cpu: 2000m - memory: 2Gi - livenessProbe: - httpGet: - path: /health - port: 8000 - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - readinessProbe: - httpGet: - path: /ready - port: 8000 - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 3 - failureThreshold: 2 -``` - -Create `k8s/service.yaml`: - -```yaml -apiVersion: v1 -kind: Service -metadata: - name: helix-platform - namespace: default -spec: - type: LoadBalancer - selector: - app: helix-platform - ports: - - protocol: TCP - port: 80 - targetPort: 8000 - name: http -``` - -Create `k8s/configmap.yaml`: - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: helix-config - namespace: default -data: - config.yaml: | - orchestration: - max_agents: 100 - agent_timeout: 300 - intelligence: - default_provider: openrouter - coordination: - consensus_strategy: supermajority - monitoring: - metrics_enabled: true -``` - -Create `k8s/secrets.yaml`: - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: helix-secrets - namespace: default -type: Opaque -stringData: - openrouter-api-key: your_key_here - anthropic-api-key: your_key_here -``` - -### Deploy to Kubernetes - -```bash -# Create namespace -kubectl create namespace helix - -# Create secrets -kubectl apply -f k8s/secrets.yaml -n helix - -# Create configmap -kubectl apply -f k8s/configmap.yaml -n helix - -# Deploy application -kubectl apply -f k8s/deployment.yaml -n helix -kubectl apply -f k8s/service.yaml -n helix - -# Check deployment status -kubectl get pods -n helix -kubectl get svc -n helix - -# View logs -kubectl logs -f deployment/helix-platform -n helix - -# Scale deployment -kubectl scale deployment helix-platform --replicas=5 -n helix -``` - ---- - -## Cloud Platform Deployment - -### AWS ECS - -```bash -# Create ECR repository -aws ecr create-repository --repository-name helix-platform - -# Push image -docker tag helix-platform:latest your-account.dkr.ecr.us-east-1.amazonaws.com/helix-platform:latest -docker push your-account.dkr.ecr.us-east-1.amazonaws.com/helix-platform:latest - -# Create ECS task definition (task-definition.json) -# Deploy with AWS CLI -aws ecs create-service \ - --cluster helix-cluster \ - --service-name helix-platform \ - --task-definition helix-platform:1 \ - --desired-count 3 \ - --launch-type FARGATE -``` - -### Google Cloud Run - -```bash -# Build and push to GCR -gcloud builds submit --tag gcr.io/your-project/helix-platform - -# Deploy to Cloud Run -gcloud run deploy helix-platform \ - --image gcr.io/your-project/helix-platform \ - --platform managed \ - --region us-central1 \ - --memory 2Gi \ - --cpu 2 \ - --set-env-vars OPENROUTER_API_KEY=your_key -``` - -### Azure Container Instances - -```bash -# Push to ACR -az acr build --registry your-registry --image helix-platform:latest . - -# Deploy container -az container create \ - --resource-group helix-rg \ - --name helix-platform \ - --image your-registry.azurecr.io/helix-platform:latest \ - --cpu 2 \ - --memory 2 \ - --environment-variables OPENROUTER_API_KEY=your_key -``` - ---- - -## Configuration for Production - -### Environment Variables - -```bash -# LLM Configuration -OPENROUTER_API_KEY=your_key -ANTHROPIC_API_KEY=your_key -GROQ_API_KEY=your_key - -# System Configuration -HELIX_LOG_LEVEL=INFO -HELIX_WORKERS=4 -HELIX_PORT=8000 - -# Persistence -HELIX_PERSISTENCE_ENABLED=true -HELIX_PERSISTENCE_PATH=/data - -# Monitoring -HELIX_METRICS_ENABLED=true -HELIX_METRICS_INTERVAL=10 - -# Security -HELIX_ENABLE_HTTPS=true -HELIX_SSL_CERT_PATH=/etc/ssl/certs/cert.pem -HELIX_SSL_KEY_PATH=/etc/ssl/private/key.pem -``` - -### Database Configuration - -```yaml -# For PostgreSQL persistence -database: - type: postgresql - host: postgres.example.com - port: 5432 - user: helix - password: ${DB_PASSWORD} - database: helix_platform - pool_size: 20 - max_overflow: 40 - -# For Redis caching -cache: - type: redis - host: redis.example.com - port: 6379 - db: 0 - password: ${REDIS_PASSWORD} -``` - ---- - -## Monitoring and Logging - -### Prometheus Metrics - -```yaml -# prometheus.yml -global: - scrape_interval: 15s - -scrape_configs: - - job_name: 'helix-platform' - static_configs: - - targets: ['localhost:8000'] - metrics_path: '/metrics' -``` - -### ELK Stack (Elasticsearch, Logstash, Kibana) - -```yaml -# logstash.conf -input { - tcp { - port => 5000 - codec => json - } -} - -filter { - if [type] == "helix" { - mutate { - add_field => { "[@metadata][index_name]" => "helix-%{+YYYY.MM.dd}" } - } - } -} - -output { - elasticsearch { - hosts => ["elasticsearch:9200"] - index => "%{[@metadata][index_name]}" - } -} -``` - ---- - -## Health Checks and Monitoring - -### Health Check Endpoints - -```python -# GET /health -# Returns: 200 OK if service is healthy -{ - "status": "healthy", - "timestamp": "2024-01-15T10:30:00Z", - "version": "1.0.0" -} - -# GET /ready -# Returns: 200 OK if ready to accept traffic -{ - "ready": true, - "dependencies": { - "database": "connected", - "cache": "connected", - "llm": "available" - } -} - -# GET /metrics -# Returns Prometheus metrics -``` - ---- - -## Scaling Strategies - -### Horizontal Scaling - -```bash -# Kubernetes -kubectl scale deployment helix-platform --replicas=10 - -# Docker Swarm -docker service scale helix-platform=10 - -# AWS Auto Scaling -aws autoscaling set-desired-capacity \ - --auto-scaling-group-name helix-asg \ - --desired-capacity 10 -``` - -### Vertical Scaling - -Increase resources per instance: - -```yaml -# Kubernetes -resources: - requests: - cpu: 2000m - memory: 4Gi - limits: - cpu: 4000m - memory: 8Gi -``` - ---- - -## Security Best Practices - -### API Key Management - -```bash -# Use secrets management -# AWS Secrets Manager -aws secretsmanager create-secret --name helix/openrouter-key - -# Kubernetes Secrets -kubectl create secret generic helix-secrets \ - --from-literal=openrouter-api-key=your_key - -# Azure Key Vault -az keyvault secret set --vault-name helix-kv --name openrouter-key -``` - -### Network Security - -```yaml -# Network Policy for Kubernetes -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: helix-network-policy -spec: - podSelector: - matchLabels: - app: helix-platform - policyTypes: - - Ingress - - Egress - ingress: - - from: - - podSelector: - matchLabels: - role: frontend - ports: - - protocol: TCP - port: 8000 -``` - -### SSL/TLS Configuration - -```bash -# Generate self-signed certificate -openssl req -x509 -newkey rsa:4096 -nodes \ - -out cert.pem -keyout key.pem -days 365 - -# Or use Let's Encrypt with Certbot -certbot certonly --standalone -d helix-platform.example.com -``` - ---- - -## Troubleshooting - -### Common Issues - -**Issue**: Container exits immediately - -```bash -# Check logs -docker logs helix-platform - -# Run with debug logging -docker run -e HELIX_LOG_LEVEL=DEBUG helix-platform:latest -``` - -**Issue**: High memory usage - -```bash -# Limit memory -docker run -m 2g helix-platform:latest - -# Monitor memory -docker stats helix-platform -``` - -**Issue**: API key not found - -```bash -# Verify environment variable -docker exec helix-platform env | grep OPENROUTER - -# Set variable -docker run -e OPENROUTER_API_KEY=your_key helix-platform:latest -``` - ---- - -## Performance Tuning - -### Worker Configuration - -```python -# Adjust worker count based on CPU cores -HELIX_WORKERS = CPU_COUNT * 2 + 1 -``` - -### Connection Pooling - -```yaml -database: - pool_size: 20 - max_overflow: 40 - pool_recycle: 3600 - pool_pre_ping: true -``` - -### Caching Strategy - -```python -# Enable Redis caching -cache: - type: redis - ttl: 3600 - compression: true -``` - ---- - -## Backup and Recovery - -### Database Backup - -```bash -# PostgreSQL backup -pg_dump -U helix -h postgres.example.com helix_platform > backup.sql - -# Restore -psql -U helix -h postgres.example.com helix_platform < backup.sql -``` - -### Volume Backup - -```bash -# Kubernetes PVC backup -kubectl get pvc -kubectl exec pod-name -- tar czf /backup/data.tar.gz /data -``` - ---- - -## Rollback Procedures - -### Kubernetes Rollback - -```bash -# View rollout history -kubectl rollout history deployment/helix-platform - -# Rollback to previous version -kubectl rollout undo deployment/helix-platform - -# Rollback to specific revision -kubectl rollout undo deployment/helix-platform --to-revision=2 -``` - -### Docker Rollback - -```bash -# Use image tags for versioning -docker run helix-platform:v1.0.0 - -# Keep multiple versions available -docker tag helix-platform:latest helix-platform:v1.1.0 -``` - ---- - -## Support and Resources - -- **Documentation**: https://docs.helix-platform.ai -- **GitHub Issues**: https://github.com/Deathcharge/helix-platform/issues -- **Community**: https://discord.gg/helix-platform - ---- - -**Happy deploying! πŸš€** diff --git a/docs/PRODUCTIZATION.md b/docs/PRODUCTIZATION.md new file mode 100644 index 0000000..880ce80 --- /dev/null +++ b/docs/PRODUCTIZATION.md @@ -0,0 +1,189 @@ +# Productization record + +Last updated: 2026-07-28 + +This is the living assessment and release record for `samsarix-platform`. It distinguishes repository evidence from product assumptions and is updated as implementation and verification progress. + +## Current repository assessment + +The baseline at commit `bc98b78c20b374644bf3a6b62d85e8fb7b653da3` was a clean, documentation-only repository. Its three-commit history never contained application or package source code. The ten tracked files described a production multi-agent platform, but the repository had no importable package, executable, tests, packaging metadata, lockfile, CI workflow, deployment manifests, license file, or runnable example files. + +Several documented dependencies (`helix-agent-swarm`, `agent-consensus`, and `unified-llm`) had no matching PyPI releases when checked on 2026-07-28. The existing `requirements.txt` therefore could not install. Documentation also linked to missing files and claimed unverified test counts, coverage, performance, security controls, production deployments, endpoints, community channels, and license terms. + +## Chosen product definition + +**Samsarix Platform Doctor** is a local-first Python CLI for checking whether a Python multi-agent project is ready to run. A project declares its requirements in `samsarix-stack.toml`; the CLI checks the Python version, installed distributions, required environment-variable presence, and required files, then returns actionable human-readable or JSON results with stable exit codes. + +This is an intentionally narrow integration-readiness tool, not an agent runtime, orchestration framework, hosted service, or dashboard. + +### Why this product + +- It preserves the repository's evidenced integration-hub and onboarding intent. +- It is independently useful to developers composing multiple Python agent packages. +- It does not require private repositories, legacy unpublished services, provider credentials, a database, or cloud infrastructure. +- It can deliver a complete primary journey without inventing a second flagship application. +- It converts the repository's most harmful failure modeβ€”configuration that looks ready but is notβ€”into the product's core value. + +The command shape follows the established environment-diagnostics pattern documented by [`flutter doctor`](https://docs.flutter.dev/reference/flutter-cli). Packaging uses the current PyPA [`pyproject.toml` and console-script conventions](https://packaging.python.org/en/latest/guides/creating-command-line-tools/) with a `src/` layout, and the project manifest follows [TOML 1.0](https://toml.io/en/v1.0.0). + +## Target user and primary use case + +The target user is a Python developer integrating an agent runtime, model-provider SDK, workflow package, and project-specific configuration. Before running or deploying the application, they need a fast, non-destructive answer to: "Is this environment missing anything this project declares?" + +Primary journey: + +1. Install the CLI locally. +2. Generate or adopt a `samsarix-stack.toml` manifest. +3. Run `samsarix-platform doctor`. +4. Fix required failures using the reported remediation. +5. Run the same check in CI with `--strict` and/or `--json`. + +## Product and architecture decisions + +- Python 3.11+ and standard-library runtime only. +- `pyproject.toml` is the sole runtime/package manifest. +- `tomllib` parses a deliberately small, versioned TOML schema. +- Distribution checks use `importlib.metadata`; the CLI never imports a declared component, avoiding import-time side effects. +- Environment checks report presence only and never print values. +- Declared file paths must be portable, relative paths contained by the manifest directory; traversal and resolved symlink escapes are rejected. +- Manifests are bounded to 1 MiB and rendered fields reject Unicode control/formatting characters. +- Human output is the default; JSON is stable automation output. +- Exit `0` means ready, exit `1` means declared checks failed (or warnings exist under `--strict`), and exit `2` means invalid input or usage. +- `init` refuses to overwrite an existing manifest. +- No telemetry, network request, provider call, subprocess execution, or arbitrary manifest command is part of version 1. + +## Assumptions + +- The repository owner moved the product and company identity from Helix to Samsarix before the first public release, so no compatibility alias is required. +- A local diagnostic CLI is a more defensible extraction than recreating the undocumented multi-repository platform described by the baseline docs. +- The public PyPI project and JSON URLs for `samsarix-platform` returned `404` on 2026-07-28. That evidence does not reserve the name, and the owner must confirm it again at release time. +- MPL 2.0 is the selected license because its file-level copyleft protects distributed modifications to covered files while still permitting combination with larger proprietary works. + +## Baseline command results + +Run from the clean baseline on Windows with Python 3.11.9: + +| Command | Actual result | +| --- | --- | +| `git status --short --branch` | Exit 0; clean `main` tracking `origin/main`. | +| `python -m pip install --dry-run --ignore-installed -r requirements.txt` | Exit 1; no distribution matched `helix-agent-swarm>=1.0.0`. | +| `python -m pytest tests -q` | Exit 1; `tests` did not exist and no tests ran. | +| `python -m compileall -q src` | Exit 0 but printed `Can't list 'src'`; no source existed. | +| `python -m build` | Exit 1; neither `pyproject.toml` nor `setup.py` existed. | +| `python -m helix_platform.server` | Exit 1; the historical `helix_platform` package did not exist. | +| `python -m flake8 .` | Exit 0; there were no Python source files to lint. | +| `python -m mypy src` | Exit 1; `src` did not exist. | + +No valid start command existed. Deployment commands were not run because every referenced Docker/Kubernetes/application artifact was absent. + +## Findings and priorities + +### P0 + +- [x] Replace the un-installable manifest with a buildable package that has no imaginary runtime dependencies. +- [x] Implement one real end-to-end CLI journey with help, version, validation, success, warning, failure, invalid-input, and automation behavior. +- [x] Replace claims of a production platform with accurate product documentation and remove broken core-path links. +- [x] Replace contradictory historical license claims with the official MPL 2.0 text, package metadata, per-source SPDX notices, and Samsarix LLC attribution. + +### P1 + +- [x] Add focused unit and command-level tests, package-shape verification, type checking, linting, and CI. +- [x] Validate the manifest strictly enough to catch typos instead of silently ignoring configuration. +- [x] Prevent path traversal, component-import side effects, secret disclosure, unsafe overwrite behavior, terminal-control output, and unbounded manifest reads. +- [x] Replace fabricated deployment, performance, coverage, community, and security-control claims. +- [x] Document supported platforms, configuration, error behavior, trust boundaries, and limitations. + +### P2 + +- [ ] Add JSON Schema export or editor completion if user demand justifies the maintenance cost. +- [ ] Add optional checks for executables and network endpoints only with explicit timeout and redaction semantics. +- [ ] Add shell completion and richer CI annotations. +- [ ] Add signed releases, provenance, and an SBOM after the owner selects a publication channel. +- [ ] Validate demand before adding plugin execution, hosted reporting, telemetry, or paid services. + +## Implementation checklist + +- [x] Preserve and record the clean baseline. +- [x] Audit every tracked file and all available history. +- [x] Select the narrow product wedge and research current CLI/packaging conventions. +- [x] Add package metadata and the CLI implementation. +- [x] Add the versioned example manifest. +- [x] Add unit, CLI, and installed-package tests. +- [x] Add cross-platform CI and release-build checks. +- [x] Rewrite README, quick start, architecture, contribution, and distribution documentation. +- [x] Remove or replace obsolete and misleading artifacts. +- [x] Complete security threat modeling, file-by-file review, candidate closure, and final scan artifacts. +- [x] Run final verification and adversarial release review. + +## Release acceptance criteria + +- A documented clean-environment installation succeeds on supported Python versions. +- `samsarix-platform --help` and `samsarix-platform --version` succeed. +- A generated manifest can be checked immediately. +- The repository's example manifest produces the documented result. +- Required failures and invalid manifests produce distinct nonzero exit codes. +- JSON output contains no environment-variable values. +- Traversal, resolved path escape, unknown keys, duplicate declarations, and overwrite attempts fail safely. +- Lint, type check, unit tests, build, wheel installation, and package-shape smoke tests pass. +- CI runs meaningful checks on Windows and Linux. +- Documentation contains no known fabricated behavior or broken core links. +- No locally actionable P0 remains. +- Licensing is explicit and complete; publication remains an owner-controlled external gate. + +## Completed work + +- Protected and recorded the clean worktree and immutable baseline. +- Inspected every tracked file, all commits and locally available branches, package manifests, documentation, and advertised operational surfaces. +- Ran the baseline install, test, compile, build, start, lint, and type-check commands listed above. +- Performed bounded comparison research and selected a doctor-style local CLI using current Python packaging conventions. +- Implemented the zero-runtime-dependency package, `doctor` and non-overwriting `init` commands, strict TOML schema, stable JSON, and documented exit codes. +- Added manifest size, UTF-8, control-character, duplicate, path-containment, destination-symlink, secret-redaction, and no-import controls with regression tests. +- Added a maintained example, 37 unit/CLI/package tests, Ruff, strict mypy, branch-aware coverage, cross-platform CI, dependency update configuration, build verification, and fresh-wheel smoke coverage. +- Replaced the obsolete backup, un-installable runtime requirements, fabricated deployment guide, and aspirational platform examples with accurate product, architecture, release, contribution, and limitation documentation. +- Migrated all current product identifiers to Samsarix before publication and added MPL 2.0 licensing, Samsarix LLC attribution, brand boundaries, and verified company contact channels. + +## Final verification results + +Run on Windows with Python 3.11.9 against the final implementation: + +| Command | Actual result | +| --- | --- | +| `python -m ruff format --check .` | Exit 0; 11 Python files already formatted. | +| `python -m ruff check .` | Exit 0; all checks passed. | +| `python -m mypy src tests` | Exit 0; no issues in 11 source files. | +| `python -m coverage run -m unittest discover -s tests` | Exit 0; 37 tests passed. | +| `python -m coverage report` | Exit 0; 93% branch-aware total coverage, above the 90% gate. | +| `samsarix-platform doctor samsarix-stack.toml --json --strict` | Exit 0; 5 passed, 0 warned, 0 failed, status `ready`. | +| `samsarix-platform doctor examples/agent-project/samsarix-stack.toml --strict` | Exit 1 as designed; the optional SDK was installed, the optional key was absent, and strict mode promoted that warning to `not_ready`. | +| `python -m build` | Exit 0; built `samsarix_platform-0.1.0.tar.gz` and `samsarix_platform-0.1.0-py3-none-any.whl`. | +| `python -m twine check dist/*` | Exit 0; both artifacts passed. | +| Fresh-wheel `--version`, `--help`, `init`, strict `doctor`, module entry point, and `pip check` | All exited 0 in an isolated virtual environment; no broken requirements. | +| `python -m pip_audit -r requirements-dev.txt --progress-spinner off` | Exit 0; no known vulnerabilities found. The local pip cache emitted recoverable deserialization warnings. | +| Local Markdown target check | Exit 0; 0 broken relative links. | + +The authored GitHub Actions matrix covers Linux and Windows on Python 3.11 and 3.14. A pushed branch and its remote check results are recorded separately from this local verification. No production deployment or package publication was attempted. + +## Release disposition + +**Release candidate with named owner/external gates.** The local product journey, tests, build, package shape, documentation, licensing, and standard security scan are complete with no locally actionable P0 and no surviving reportable security finding. Public release still requires package-namespace confirmation, trusted-publishing/repository configuration, owner review, and a green remote CI matrix. + +## Deferred and blocked work + +- Legal counsel has not independently reviewed the selected standard MPL 2.0 license or brand notice; obtain advice if the business model or contributor structure changes. +- PyPI project ownership, trusted publishing, release signing, and the first public release require owner authorization and account configuration. +- GitHub Actions Linux/Python 3.14 verification requires a pushed branch and green remote run; equivalent Windows/Python 3.11 checks passed locally. +- Production deployment is not applicable to a local CLI. Package publication is documented but will not be executed here. +- Product-market demand is unvalidated. Hosted services, telemetry, subscriptions, and provider integrations remain out of scope. + +## Known risks + +- Distribution names identify installed packages but do not prove API compatibility or runtime health. +- Environment-variable presence does not prove credential validity. +- File presence does not validate file contents. +- Direct development tools are pinned, but transitive package-index and runner-image trust remain supply-chain dependencies until an owner adopts a hash-locked workflow and release provenance. +- A local process can change the environment after the check completes; the report is a point-in-time assessment. +- The repository's historical commits and any downstream links may retain the former Helix name; current source, package, CLI, manifest, and documentation use Samsarix consistently. + +## Distribution and sustainability + +The simplest distribution is a Python wheel installed with `pipx` or `pip`. The first release should remain local-only and free of hosted operating costs. If usage is validated, sustainable maintenance could come from sponsorship or paid integration support; a hosted tier or subscription is not justified by current evidence. diff --git a/docs/RELEASING.md b/docs/RELEASING.md new file mode 100644 index 0000000..1a96e79 --- /dev/null +++ b/docs/RELEASING.md @@ -0,0 +1,82 @@ +# Build and release guide + +Samsarix Platform Doctor is distributed as a Python source archive and universal wheel. It is not a service and has no Docker, Kubernetes, database, or cloud deployment procedure. + +## Current release disposition + +Version `0.1.0` is a pre-release candidate. Local build and verification are implemented. Public publication remains blocked on owner decisions and external setup: + +- confirm or claim the `samsarix-platform` distribution name immediately before release; +- configure the owner's PyPI project and trusted publisher; +- choose tag-signing and artifact-provenance policy; +- obtain a green protected-branch CI run for the release commit. + +The repository is licensed under MPL 2.0, identifies Samsarix LLC as the initial copyright holder, and publishes private support/security contact details. The public PyPI project and JSON URLs for `samsarix-platform` returned `404` when checked on 2026-07-28, but that is not a reservation or guarantee that the name can be claimed later. + +Do not publish from an unreviewed developer workstation or by placing a long-lived PyPI token in this repository. + +## Local release verification + +Start from a clean checkout on the intended release commit: + +```console +git status --short --branch +python -m venv .venv +``` + +Activate the environment, then run: + +```console +python -m pip install -e . +python -m pip install -r requirements-dev.txt +python -m ruff format --check . +python -m ruff check . +python -m mypy src tests +python -m coverage erase +python -m coverage run -m unittest discover -s tests +python -m coverage report +samsarix-platform doctor samsarix-stack.toml --strict +python -m build +python -m twine check dist/* +``` + +The build must create exactly one `.tar.gz` source distribution and one `py3-none-any.whl` for the selected version. + +## Fresh-wheel smoke test + +Create a second disposable virtual environment outside the repository, install only the built wheel, and run: + +```console +samsarix-platform --version +samsarix-platform --help +samsarix-platform init path/to/disposable/samsarix-stack.toml --name smoke-test +samsarix-platform doctor path/to/disposable/samsarix-stack.toml --strict +python -m samsarix_platform --version +python -m pip check +``` + +Also inspect wheel contents and confirm they include only the intended `samsarix_platform` modules, `py.typed`, distribution metadata, and MPL license metadata/files. Tests must exercise the installed entry point rather than relying only on source imports. + +## Version and changelog + +The version appears in `pyproject.toml` and `src/samsarix_platform/__init__.py`; both must match. Move release notes from `Unreleased` into a dated heading in `CHANGELOG.md`. Build artifacts must not be committed. + +## CI protection + +`.github/workflows/ci.yml` runs: + +- installed-package unit tests and the strict repository doctor journey on Windows and Linux; +- Ruff formatting/linting, strict mypy, branch-aware coverage, build, and metadata checks; +- a wheel reinstall and installed CLI smoke test. + +GitHub Actions are pinned to full commit hashes. Dependency update automation should update those pins and the readable version comments together. + +## Owner publication setup + +After the package namespace is resolved, the owner can add a separate release workflow using PyPI trusted publishing with a protected GitHub environment. The workflow should build once, retain the verified artifacts, publish only on an approved version tag, request `id-token: write` only in the publish job, and attach provenance according to the owner's policy. + +These steps document the required shape; they do not authorize creating accounts, claiming names, uploading artifacts, changing repository settings, or publishing a package. + +## Rollback + +Published package files generally cannot be replaced. If a bad release is published, yank the affected version in PyPI, document the reason, fix forward with a new version, and rotate any credential that may have been exposed. Do not rewrite Git history or reuse a released version number. diff --git a/examples/README.md b/examples/README.md index f7fb342..0e1ddb9 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,747 +1,39 @@ -# Helix Stack Integration Examples +# Examples -This document provides four production-ready examples showing how to integrate multiple Helix components to build sophisticated multi-agent systems. +The repository contains one maintained example rather than historical snippets for packages that were never present. ---- +## Agent project readiness manifest -## Example 1: Multi-Agent Research Pipeline +[`agent-project/samsarix-stack.toml`](agent-project/samsarix-stack.toml) declares: -**Scenario**: Build an intelligent research system where multiple specialized agents collaborate to research a topic, validate sources, and produce a comprehensive summary. +- Python 3.11+ as required; +- the `openai` distribution as optional; +- `OPENAI_API_KEY` as an optional secret; +- the example README as required. -**Components Used**: unified-llm, helix-agent-swarm, agent-consensus, ucf-protocol, routine-engine +Run it after installing this package: -### Architecture - -``` -User Query - ↓ -Routine-Engine (Schedule workflow) - ↓ -Helix-Agent-Swarm (Spawn agents) - β”œβ”€ Gemini (Scout): Search and gather information - β”œβ”€ Kavach (Shield): Validate sources and fact-check - └─ Agni (Transform): Synthesize and summarize - ↓ -Unified-LLM (Provide intelligence to each agent) - ↓ -Agent-Consensus (Vote on key findings) - ↓ -UCF-Protocol (Monitor harmony and alignment) - ↓ -Final Report -``` - -### Implementation - -```python -""" -Example 1: Multi-Agent Research Pipeline -Demonstrates: Agent coordination, LLM integration, consensus voting, metrics tracking -""" - -from typing import List, Dict -from dataclasses import dataclass -from helix_agent_swarm import HelixOrchestrator, Agent -from unified_llm import LLMClient, LLMRequest -from agent_consensus import ConsensusEngine, Proposal -from ucf_protocol import UCFProtocol, UCFState -from routine_engine import WorkflowEngine, Task - -@dataclass -class ResearchTask: - topic: str - depth: str = "comprehensive" # brief, standard, comprehensive - sources_count: int = 5 - -class ResearchPipeline: - def __init__(self): - self.orchestrator = HelixOrchestrator() - self.llm_client = LLMClient(provider="openrouter") - self.consensus = ConsensusEngine() - self.ucf = UCFProtocol() - self.workflow = WorkflowEngine() - - def setup_agents(self): - """Create specialized research agents""" - # Scout agent - gathers information - self.orchestrator.register_agent( - name="scout", - agent_type="Gemini", - system_prompt="""You are a research scout. Your job is to: -1. Generate comprehensive search queries -2. Gather diverse information from multiple angles -3. Identify key facts and trends -4. Report findings in structured format""" - ) - - # Validator agent - checks sources - self.orchestrator.register_agent( - name="validator", - agent_type="Kavach", - system_prompt="""You are a fact validator. Your job is to: -1. Assess source credibility -2. Cross-reference claims -3. Identify potential biases -4. Rate confidence levels""" - ) - - # Synthesizer agent - creates summary - self.orchestrator.register_agent( - name="synthesizer", - agent_type="Agni", - system_prompt="""You are a research synthesizer. Your job is to: -1. Identify key themes -2. Create coherent narrative -3. Highlight important findings -4. Suggest follow-up research""" - ) - - def research(self, task: ResearchTask) -> Dict: - """Execute research workflow""" - - # Step 1: Scout gathers information - print(f"πŸ” Scout gathering information on: {task.topic}") - scout_findings = self.llm_client.generate( - LLMRequest( - prompt=f"Research the following topic comprehensively: {task.topic}", - system="You are a research scout. Gather diverse information.", - max_tokens=2000 - ) - ) - - # Step 2: Validator checks sources - print("πŸ›‘οΈ Validator checking sources...") - validation_results = self.llm_client.generate( - LLMRequest( - prompt=f"Validate and assess credibility of: {scout_findings}", - system="You are a fact validator. Check sources carefully.", - max_tokens=1500 - ) - ) - - # Step 3: Consensus on key findings - print("🀝 Agents reaching consensus...") - proposal = Proposal( - title="Research Findings", - description=f"Scout findings: {scout_findings[:200]}...", - details={ - "scout_findings": scout_findings, - "validation": validation_results - } - ) - - consensus_result = self.consensus.vote( - proposal=proposal, - agents=[ - self.orchestrator.agents["scout"], - self.orchestrator.agents["validator"] - ], - strategy="supermajority" - ) - - # Step 4: Synthesizer creates final report - print("πŸ”₯ Synthesizer creating summary...") - final_report = self.llm_client.generate( - LLMRequest( - prompt=f"Create comprehensive summary: {scout_findings}", - system="You are a research synthesizer. Create coherent narrative.", - max_tokens=2000 - ) - ) - - # Step 5: Monitor system health - state = self.orchestrator.get_state() - metrics = self.ucf.calculate_metrics(state) - - print(f"πŸ“Š System Harmony: {metrics.harmony:.2f}") - print(f"πŸ“Š System Resilience: {metrics.resilience:.2f}") - - return { - "topic": task.topic, - "scout_findings": scout_findings, - "validation": validation_results, - "consensus": consensus_result.agreed, - "final_report": final_report, - "metrics": { - "harmony": metrics.harmony, - "resilience": metrics.resilience, - "phase": metrics.phase - } - } - -# Usage -if __name__ == "__main__": - pipeline = ResearchPipeline() - pipeline.setup_agents() - - task = ResearchTask( - topic="Latest developments in quantum computing", - depth="comprehensive", - sources_count=10 - ) - - results = pipeline.research(task) - - print("\n" + "="*50) - print("RESEARCH COMPLETE") - print("="*50) - print(f"Topic: {results['topic']}") - print(f"Consensus Reached: {results['consensus']}") - print(f"System Harmony: {results['metrics']['harmony']:.2f}") - print(f"\nFinal Report:\n{results['final_report']}") -``` - -### Expected Output - -``` -πŸ” Scout gathering information on: Latest developments in quantum computing -πŸ›‘οΈ Validator checking sources... -🀝 Agents reaching consensus... -πŸ”₯ Synthesizer creating summary... -πŸ“Š System Harmony: 0.87 -πŸ“Š System Resilience: 0.92 - -================================================== -RESEARCH COMPLETE -================================================== -Topic: Latest developments in quantum computing -Consensus Reached: True -System Harmony: 0.87 - -Final Report: -[Comprehensive research summary with key findings, validated sources, and actionable insights] -``` - ---- - -## Example 2: Consensus-Based Decision Making - -**Scenario**: Multiple agents need to make a collective decision (e.g., approve a resource allocation, select a strategy). Use consensus voting to ensure alignment. - -**Components Used**: helix-agent-swarm, agent-consensus, ucf-protocol - -### Implementation - -```python -""" -Example 2: Consensus-Based Decision Making -Demonstrates: Voting mechanisms, consensus algorithms, conflict resolution -""" - -from agent_consensus import ConsensusEngine, Proposal, VotingStrategy -from helix_agent_swarm import HelixOrchestrator, Agent -from ucf_protocol import UCFProtocol - -class DecisionMakingSystem: - def __init__(self): - self.orchestrator = HelixOrchestrator() - self.consensus = ConsensusEngine() - self.ucf = UCFProtocol() - - def setup_decision_board(self): - """Create a board of diverse agents""" - agents_config = [ - ("strategic", "Gemini", "Strategic thinker"), - ("cautious", "Kavach", "Risk assessor"), - ("innovative", "Agni", "Innovation advocate"), - ("harmony", "SanghaCore", "Harmony seeker"), - ("memory", "Shadow", "Historical context") - ] - - for name, agent_type, role in agents_config: - self.orchestrator.register_agent( - name=name, - agent_type=agent_type, - system_prompt=f"You are a {role} on the decision board." - ) - - def make_decision(self, proposal: Proposal, strategy: str = "supermajority"): - """Execute consensus-based decision making""" - - print(f"\nπŸ“‹ Proposal: {proposal.title}") - print(f"πŸ“ Description: {proposal.description}") - print(f"πŸ—³οΈ Voting Strategy: {strategy}") - print("-" * 50) - - # Get votes from all agents - result = self.consensus.vote( - proposal=proposal, - agents=list(self.orchestrator.agents.values()), - strategy=strategy - ) - - # Display results - print(f"\nβœ… Consensus Reached: {result.agreed}") - print(f"πŸ“Š Agreement Level: {result.agreement_percentage:.1f}%") - print(f"πŸ‘ Votes For: {result.votes_for}") - print(f"πŸ‘Ž Votes Against: {result.votes_against}") - print(f"🀷 Abstentions: {result.abstentions}") - - # Check system harmony - state = self.orchestrator.get_state() - metrics = self.ucf.calculate_metrics(state) - - if metrics.harmony < 0.6: - print(f"\n⚠️ WARNING: Low harmony detected ({metrics.harmony:.2f})") - print("Consider revisiting the proposal or strategy.") - - return result - -# Usage -if __name__ == "__main__": - system = DecisionMakingSystem() - system.setup_decision_board() - - # Example proposal - proposal = Proposal( - title="Deploy New Agent Type", - description="Should we deploy a new specialized agent for data analysis?", - details={ - "cost": "$50,000", - "timeline": "3 months", - "expected_benefit": "30% efficiency improvement", - "risk_level": "medium" - } - ) - - # Make decision with supermajority (2/3 agreement required) - result = system.make_decision(proposal, strategy="supermajority") - - if result.agreed: - print("\n✨ Decision: APPROVED - Proceed with deployment") - else: - print("\n❌ Decision: REJECTED - Consider alternative approaches") -``` - -### Expected Output - -``` -πŸ“‹ Proposal: Deploy New Agent Type -πŸ“ Description: Should we deploy a new specialized agent for data analysis? -πŸ—³οΈ Voting Strategy: supermajority --------------------------------------------------- - -βœ… Consensus Reached: True -πŸ“Š Agreement Level: 80.0% -πŸ‘ Votes For: 4 -πŸ‘Ž Votes Against: 1 -🀷 Abstentions: 0 - -✨ Decision: APPROVED - Proceed with deployment +```console +samsarix-platform doctor examples/agent-project/samsarix-stack.toml ``` ---- +Without the provider package or key, expect two warnings and exit `0`: -## Example 3: Scheduled Workflow with Monitoring - -**Scenario**: Execute a complex multi-step workflow on a schedule, with continuous monitoring and automatic recovery. - -**Components Used**: routine-engine, helix-agent-swarm, ucf-protocol - -### Implementation - -```python -""" -Example 3: Scheduled Workflow with Monitoring -Demonstrates: Workflow scheduling, step-by-step execution, health monitoring -""" - -from routine_engine import RoutineEngine, WorkflowStep -from helix_agent_swarm import HelixOrchestrator -from ucf_protocol import UCFProtocol -import time - -class MonitoredWorkflow: - def __init__(self): - self.routine = RoutineEngine() - self.orchestrator = HelixOrchestrator() - self.ucf = UCFProtocol() - self.metrics_history = [] - - def setup_workflow(self): - """Define a 108-step ritual cycle""" - - # Setup agents - self.orchestrator.register_agent("worker1", "Gemini") - self.orchestrator.register_agent("worker2", "Kavach") - self.orchestrator.register_agent("worker3", "Agni") - - # Define workflow with monitoring callbacks - self.routine.define_cycle( - name="Daily Processing Cycle", - steps=108, - agents=list(self.orchestrator.agents.values()), - callbacks={ - "every_9_steps": self.checkpoint_check, - "every_27_steps": self.consensus_check, - "every_54_steps": self.recalibration, - "on_error": self.error_recovery - } - ) - - def checkpoint_check(self, step: int): - """Check system health every 9 steps""" - state = self.orchestrator.get_state() - metrics = self.ucf.calculate_metrics(state) - self.metrics_history.append(metrics) - - print(f"βœ“ Checkpoint at step {step}") - print(f" Harmony: {metrics.harmony:.2f}") - print(f" Phase: {metrics.phase}") - - if metrics.harmony < 0.5: - print(f" ⚠️ Low harmony - may need intervention") - - def consensus_check(self, step: int): - """Verify agent alignment every 27 steps""" - print(f"βœ“ Consensus check at step {step}") - state = self.orchestrator.get_state() - - # Check if agents are aligned - alignment = self.calculate_alignment(state) - print(f" Agent alignment: {alignment:.2f}") - - def recalibration(self, step: int): - """Recalibrate system every 54 steps""" - print(f"βœ“ System recalibration at step {step}") - - # Recalibrate agent priorities and strategies - for agent in self.orchestrator.agents.values(): - agent.recalibrate() - - print(f" Agents recalibrated") - - def error_recovery(self, error: Exception, step: int): - """Handle errors gracefully""" - print(f"❌ Error at step {step}: {str(error)}") - print(f" Attempting recovery...") - - # Restart failed step - self.routine.retry_step(step, max_retries=3) - - def calculate_alignment(self, state) -> float: - """Calculate how well agents are aligned""" - # Simplified alignment calculation - return 0.85 - - def execute(self): - """Execute the workflow""" - print("πŸš€ Starting monitored workflow...") - print("-" * 50) - - try: - self.routine.execute_with_resilience() - except Exception as e: - print(f"Workflow failed: {e}") - - # Print summary - print("\n" + "="*50) - print("WORKFLOW COMPLETE") - print("="*50) - - if self.metrics_history: - avg_harmony = sum(m.harmony for m in self.metrics_history) / len(self.metrics_history) - print(f"Average Harmony: {avg_harmony:.2f}") - print(f"Total Checkpoints: {len(self.metrics_history)}") - -# Usage -if __name__ == "__main__": - workflow = MonitoredWorkflow() - workflow.setup_workflow() - workflow.execute() +```text +Summary: 2 passed, 2 warned, 0 failed +Result: READY WITH WARNINGS ``` -### Expected Output +Strict CI behavior returns exit `1` for the same warnings: -``` -πŸš€ Starting monitored workflow... --------------------------------------------------- -βœ“ Checkpoint at step 9 - Harmony: 0.88 - Phase: COHERENT -βœ“ Checkpoint at step 18 - Harmony: 0.89 - Phase: COHERENT -βœ“ Consensus check at step 27 - Agent alignment: 0.85 -βœ“ Checkpoint at step 36 - Harmony: 0.87 - Phase: HARMONIOUS -... -================================================== -WORKFLOW COMPLETE -================================================== -Average Harmony: 0.87 -Total Checkpoints: 12 +```console +samsarix-platform doctor examples/agent-project/samsarix-stack.toml --strict ``` ---- +Machine-readable output uses the same checks: -## Example 4: End-to-End Agent Swarm Application - -**Scenario**: Build a complete application where multiple specialized agents work together to solve a complex problem (e.g., customer support system). - -**Components Used**: All 15 repositories - -### Implementation - -```python -""" -Example 4: End-to-End Agent Swarm Application -Demonstrates: Full integration of all Helix components -""" - -from helix_agent_swarm import HelixOrchestrator, HelixCollective -from unified_llm import LLMClient -from agent_consensus import ConsensusEngine -from ucf_protocol import UCFProtocol -from routine_engine import RoutineEngine -from helix_chat_engine import ChatServer -from helix_hub_shared import Logger - -class CustomerSupportSystem: - """ - A complete customer support system using Helix agents. - - Workflow: - 1. Customer submits ticket via chat - 2. Triage agent categorizes issue - 3. Specialist agents research solution - 4. Consensus on best response - 5. Response delivered via chat - 6. Follow-up scheduled if needed - """ - - def __init__(self): - self.orchestrator = HelixOrchestrator() - self.llm = LLMClient(provider="openrouter") - self.consensus = ConsensusEngine() - self.ucf = UCFProtocol() - self.routine = RoutineEngine() - self.chat = ChatServer() - self.logger = Logger("CustomerSupport") - - def setup_agents(self): - """Create specialized support agents""" - - # Triage agent - categorizes issues - self.orchestrator.register_agent( - name="triage", - agent_type="Gemini", - system_prompt="""You are a support triage agent. Your job is to: -1. Understand customer issues -2. Categorize by type (billing, technical, feature request, etc.) -3. Assess urgency -4. Route to appropriate specialists""" - ) - - # Technical specialist - self.orchestrator.register_agent( - name="tech_specialist", - agent_type="Kavach", - system_prompt="""You are a technical support specialist. Provide: -1. Technical solutions -2. Step-by-step troubleshooting -3. Code examples if needed -4. Escalation path if unsolvable""" - ) - - # Billing specialist - self.orchestrator.register_agent( - name="billing_specialist", - agent_type="Agni", - system_prompt="""You are a billing support specialist. Handle: -1. Invoice inquiries -2. Refund requests -3. Subscription management -4. Payment issues""" - ) - - # Quality assurance - self.orchestrator.register_agent( - name="qa", - agent_type="SanghaCore", - system_prompt="""You are a quality assurance agent. Ensure: -1. Response accuracy -2. Tone appropriateness -3. Completeness -4. Customer satisfaction likelihood""" - ) - - def process_ticket(self, ticket: Dict) -> Dict: - """Process a customer support ticket""" - - self.logger.info(f"Processing ticket: {ticket['id']}") - - # Step 1: Triage - self.logger.info("Step 1: Triaging issue...") - triage_result = self.llm.generate({ - "prompt": f"Triage this support ticket: {ticket['content']}", - "system": self.orchestrator.agents["triage"].system_prompt - }) - - category = self._extract_category(triage_result) - self.logger.info(f"Category: {category}") - - # Step 2: Route to specialist - specialist_name = self._get_specialist(category) - self.logger.info(f"Routing to: {specialist_name}") - - specialist_response = self.llm.generate({ - "prompt": f"Provide support for: {ticket['content']}", - "system": self.orchestrator.agents[specialist_name].system_prompt - }) - - # Step 3: Quality check - self.logger.info("Step 3: Quality assurance...") - qa_check = self.llm.generate({ - "prompt": f"Review this response: {specialist_response}", - "system": self.orchestrator.agents["qa"].system_prompt - }) - - # Step 4: Consensus on final response - self.logger.info("Step 4: Consensus...") - consensus_result = self.consensus.vote( - proposal={ - "title": "Support Response", - "content": specialist_response - }, - agents=[ - self.orchestrator.agents[specialist_name], - self.orchestrator.agents["qa"] - ], - strategy="unanimous" - ) - - # Step 5: Monitor system health - state = self.orchestrator.get_state() - metrics = self.ucf.calculate_metrics(state) - - # Step 6: Schedule follow-up if needed - if self._needs_followup(category): - self.routine.schedule_task( - name=f"followup_{ticket['id']}", - delay_hours=24, - callback=lambda: self.followup_ticket(ticket['id']) - ) - - return { - "ticket_id": ticket['id'], - "category": category, - "response": specialist_response, - "qa_approved": consensus_result.agreed, - "system_harmony": metrics.harmony, - "followup_scheduled": self._needs_followup(category) - } - - def _extract_category(self, triage_result: str) -> str: - """Extract category from triage result""" - if "billing" in triage_result.lower(): - return "billing" - elif "technical" in triage_result.lower(): - return "technical" - else: - return "general" - - def _get_specialist(self, category: str) -> str: - """Get appropriate specialist for category""" - specialists = { - "billing": "billing_specialist", - "technical": "tech_specialist", - "general": "triage" - } - return specialists.get(category, "triage") - - def _needs_followup(self, category: str) -> bool: - """Determine if follow-up is needed""" - return category in ["billing", "technical"] - - def followup_ticket(self, ticket_id: str): - """Follow up on a ticket""" - self.logger.info(f"Following up on ticket: {ticket_id}") - # Implementation would contact customer - -# Usage -if __name__ == "__main__": - system = CustomerSupportSystem() - system.setup_agents() - - # Example ticket - ticket = { - "id": "TICKET-001", - "content": "I was charged twice for my subscription. Can you help?", - "customer_id": "CUST-123" - } - - result = system.process_ticket(ticket) - - print("\n" + "="*50) - print("TICKET PROCESSED") - print("="*50) - print(f"Ticket ID: {result['ticket_id']}") - print(f"Category: {result['category']}") - print(f"QA Approved: {result['qa_approved']}") - print(f"System Harmony: {result['system_harmony']:.2f}") - print(f"Follow-up Scheduled: {result['followup_scheduled']}") - print(f"\nResponse:\n{result['response']}") +```console +samsarix-platform doctor examples/agent-project/samsarix-stack.toml --json ``` -### Expected Output - -``` -Processing ticket: TICKET-001 -Step 1: Triaging issue... -Category: billing -Routing to: billing_specialist -Step 3: Quality assurance... -Step 4: Consensus... - -================================================== -TICKET PROCESSED -================================================== -Ticket ID: TICKET-001 -Category: billing -QA Approved: True -System Harmony: 0.89 -Follow-up Scheduled: True - -Response: -[Detailed billing support response addressing the duplicate charge issue with clear next steps] -``` - ---- - -## Integration Patterns Summary - -| Pattern | Use Case | Key Components | -|---------|----------|-----------------| -| **Research Pipeline** | Information gathering and synthesis | LLM, Swarm, Consensus, Metrics | -| **Decision Making** | Collective voting and consensus | Swarm, Consensus, Metrics | -| **Scheduled Workflows** | Recurring tasks with monitoring | Routine, Swarm, Metrics | -| **End-to-End System** | Complete application | All components | - ---- - -## Performance Benchmarks - -Based on production deployments: - -| Operation | Latency | Throughput | -|-----------|---------|-----------| -| Agent spawn | 50-100ms | 100/sec | -| LLM inference | 500ms-5s | 10-100/sec | -| Consensus vote (5 agents) | 100-200ms | 1000/sec | -| Workflow step | 1-10s | 10/sec | -| End-to-end ticket (4 steps) | 5-20s | 1-5/sec | - ---- - -## Next Steps - -1. Adapt these examples to your specific use cases -2. Customize agent personalities and system prompts -3. Integrate with your data sources and APIs -4. Deploy to your infrastructure -5. Monitor and optimize performance - -For more information, see the Helix Stack Architecture Guide. +The example never contacts OpenAI and never prints the key value. Its manifest is loaded by the automated test suite so schema drift fails CI. diff --git a/examples/agent-project/README.md b/examples/agent-project/README.md new file mode 100644 index 0000000..ae90834 --- /dev/null +++ b/examples/agent-project/README.md @@ -0,0 +1,9 @@ +# Example agent-project manifest + +This fixture demonstrates an optional provider SDK and secret. From the repository root, run: + +```console +samsarix-platform doctor examples/agent-project/samsarix-stack.toml +``` + +Without the optional SDK or key, the command reports warnings and exits `0`. Add `--strict` when CI should treat optional warnings as exit `1`. The CLI reports only whether `OPENAI_API_KEY` is present; it never prints the value or contacts OpenAI. diff --git a/examples/agent-project/samsarix-stack.toml b/examples/agent-project/samsarix-stack.toml new file mode 100644 index 0000000..ac3f322 --- /dev/null +++ b/examples/agent-project/samsarix-stack.toml @@ -0,0 +1,25 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +schema_version = 1 + +[project] +name = "Example agent project" +requires_python = ">=3.11" + +[[components]] +name = "OpenAI Python SDK" +distribution = "openai" +required = false +description = "Only required when the project selects OpenAI as its provider" + +[[environment]] +name = "OPENAI_API_KEY" +required = false +secret = true +description = "Only required for authenticated OpenAI requests" + +[[files]] +path = "README.md" +required = true +description = "Example instructions" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c8c205b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,73 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +[build-system] +requires = ["setuptools==80.9.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "samsarix-platform" +version = "0.1.0" +description = "Local readiness checks for Python multi-agent projects" +readme = "README.md" +requires-python = ">=3.11" +authors = [ + { name = "Samsarix LLC", email = "contact@samsarix.com" }, +] +maintainers = [ + { name = "Samsarix LLC", email = "support@samsarix.com" }, +] +license = "MPL-2.0" +license-files = ["LICENSE"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Typing :: Typed", +] +keywords = ["agents", "configuration", "diagnostics", "readiness"] +dependencies = [] + +[project.urls] +Homepage = "https://www.samsarix.com" +Repository = "https://github.com/Deathcharge/samsarix-platform" +Issues = "https://github.com/Deathcharge/samsarix-platform/issues" + +[project.scripts] +samsarix-platform = "samsarix_platform.cli:main" + +[tool.setuptools] +package-dir = {"" = "src"} + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +samsarix_platform = ["py.typed"] + +[tool.ruff] +target-version = "py311" +line-length = 100 + +[tool.ruff.lint] +select = ["B", "E", "F", "I", "SIM", "UP"] + +[tool.mypy] +python_version = "3.11" +strict = true +files = ["src", "tests"] + +[tool.coverage.run] +branch = true +source = ["samsarix_platform"] + +[tool.coverage.report] +fail_under = 90 +show_missing = true +skip_covered = true diff --git a/requirements-dev.txt b/requirements-dev.txt index f1155bb..0af383f 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,17 +1,8 @@ --r requirements.txt +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 -# Testing -pytest>=7.0.0 -pytest-cov>=4.0.0 -pytest-asyncio>=0.21.0 -pytest-mock>=3.10.0 - -# Development -black>=23.0.0 -flake8>=6.0.0 -mypy>=1.0.0 -isort>=5.12.0 - -# Documentation -sphinx>=6.0.0 -sphinx-rtd-theme>=1.2.0 +build==1.5.0 +coverage==7.13.2 +mypy==1.19.1 +ruff==0.15.12 +twine==6.2.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index bee52b4..0000000 --- a/requirements.txt +++ /dev/null @@ -1,22 +0,0 @@ -# Core dependencies -helix-agent-swarm>=1.0.0 -agent-consensus>=1.0.0 -unified-llm>=1.0.0 -ucf-protocol>=1.0.0 -routine-engine>=1.0.0 -helix-chat-engine>=1.0.0 -helix-hub-shared>=1.0.0 - -# LLM providers -openai>=1.0.0 -anthropic>=0.7.0 -groq>=0.4.0 - -# Utilities -pydantic>=2.0.0 -python-dotenv>=1.0.0 -requests>=2.31.0 -aiohttp>=3.9.0 - -# Async support -asyncio-contextmanager>=1.0.0 diff --git a/samsarix-stack.toml b/samsarix-stack.toml new file mode 100644 index 0000000..9961dd7 --- /dev/null +++ b/samsarix-stack.toml @@ -0,0 +1,29 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +schema_version = 1 + +[project] +name = "Samsarix Platform Doctor" +requires_python = ">=3.11" + +[[components]] +name = "Samsarix Platform Doctor package" +distribution = "samsarix-platform" +required = true +description = "The installed CLI distribution" + +[[files]] +path = "README.md" +required = true +description = "User-facing product documentation" + +[[files]] +path = "pyproject.toml" +required = true +description = "Build and package metadata" + +[[files]] +path = "src/samsarix_platform/cli.py" +required = true +description = "CLI entry point" diff --git a/src/samsarix_platform/__init__.py b/src/samsarix_platform/__init__.py new file mode 100644 index 0000000..e89afc7 --- /dev/null +++ b/src/samsarix_platform/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +"""Samsarix Platform Doctor public package metadata.""" + +__version__ = "0.1.0" + +__all__ = ["__version__"] diff --git a/src/samsarix_platform/__main__.py b/src/samsarix_platform/__main__.py new file mode 100644 index 0000000..0728822 --- /dev/null +++ b/src/samsarix_platform/__main__.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +"""Run the command-line interface with ``python -m samsarix_platform``.""" + +from samsarix_platform.cli import main + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/samsarix_platform/cli.py b/src/samsarix_platform/cli.py new file mode 100644 index 0000000..9be3305 --- /dev/null +++ b/src/samsarix_platform/cli.py @@ -0,0 +1,165 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +"""Command-line interface for Samsarix Platform Doctor.""" + +from __future__ import annotations + +import argparse +import json +import sys +from collections.abc import Sequence +from pathlib import Path + +from samsarix_platform import __version__ +from samsarix_platform.doctor import DoctorReport, run_checks +from samsarix_platform.manifest import ManifestError, load_manifest + +DEFAULT_MANIFEST = "samsarix-stack.toml" + + +def build_parser() -> argparse.ArgumentParser: + """Create the public argument parser.""" + + parser = argparse.ArgumentParser( + prog="samsarix-platform", + description="Check whether a Python multi-agent project is ready to run.", + ) + parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}") + commands = parser.add_subparsers(dest="command", required=True) + + doctor = commands.add_parser("doctor", help="run the declared readiness checks") + doctor.add_argument( + "manifest", + nargs="?", + default=DEFAULT_MANIFEST, + help=f"manifest path (default: {DEFAULT_MANIFEST})", + ) + doctor.add_argument("--json", action="store_true", help="write stable JSON to stdout") + doctor.add_argument( + "--strict", + action="store_true", + help="treat optional warnings as a non-ready result", + ) + + init = commands.add_parser("init", help="create a safe starter manifest") + init.add_argument( + "path", + nargs="?", + default=DEFAULT_MANIFEST, + help=f"destination path (default: {DEFAULT_MANIFEST})", + ) + init.add_argument("--name", help="project name to place in the manifest") + return parser + + +def main(argv: Sequence[str] | None = None) -> int: + """Run the CLI and return a process exit code.""" + + args = build_parser().parse_args(argv) + if args.command == "doctor": + return _run_doctor(Path(args.manifest), json_output=args.json, strict=args.strict) + if args.command == "init": + return _run_init(Path(args.path), project_name=args.name) + raise AssertionError(f"unhandled command: {args.command}") + + +def _run_doctor(manifest_path: Path, *, json_output: bool, strict: bool) -> int: + try: + manifest = load_manifest(manifest_path) + except ManifestError as exc: + if json_output: + print( + json.dumps( + { + "schema": "samsarix-platform-doctor/v1", + "tool_version": __version__, + "status": "invalid_manifest", + "exit_code": 2, + "error": str(exc), + }, + indent=2, + sort_keys=True, + ) + ) + else: + print(f"error: {exc}", file=sys.stderr) + return 2 + + report = run_checks(manifest) + if json_output: + print(json.dumps(report.to_dict(strict=strict), indent=2, sort_keys=True)) + else: + _render_human(report, strict=strict) + return report.exit_code(strict=strict) + + +def _render_human(report: DoctorReport, *, strict: bool) -> None: + print(f"Samsarix Platform Doctor {__version__}") + print(f"Project: {report.project_name}") + print(f"Manifest: {report.manifest_path}") + print() + for check in report.checks: + print(f"[{check.status.upper():4}] {check.category}/{check.name}: {check.message}") + if check.remediation is not None: + print(f" Fix: {check.remediation}") + counts = report.counts() + print() + print(f"Summary: {counts['pass']} passed, {counts['warn']} warned, {counts['fail']} failed") + print(f"Result: {report.status(strict=strict).replace('_', ' ').upper()}") + + +def _run_init(destination: Path, *, project_name: str | None) -> int: + target = destination.expanduser() + if not target.is_absolute(): + target = Path.cwd() / target + selected_name = project_name.strip() if project_name is not None else target.parent.name + if not selected_name: + selected_name = "my-agent-project" + if not target.parent.is_dir(): + print(f"error: destination directory does not exist: {target.parent}", file=sys.stderr) + return 2 + if target.is_symlink(): + print(f"error: refusing to overwrite existing path: {target}", file=sys.stderr) + return 2 + + content = _starter_manifest(selected_name) + try: + with target.open("x", encoding="utf-8", newline="\n") as handle: + handle.write(content) + except FileExistsError: + print(f"error: refusing to overwrite existing path: {target}", file=sys.stderr) + return 2 + except OSError as exc: + print(f"error: could not create {target}: {exc}", file=sys.stderr) + return 2 + + print(f"Created {target}") + print(f"Next: samsarix-platform doctor {target}") + return 0 + + +def _starter_manifest(project_name: str) -> str: + encoded_name = json.dumps(project_name, ensure_ascii=False) + return f"""# Samsarix Platform Doctor manifest +schema_version = 1 + +[project] +name = {encoded_name} +requires_python = ">=3.11" + +# Add checks as needed. Examples: +# [[components]] +# name = "Model provider SDK" +# distribution = "openai" +# required = true +# +# [[environment]] +# name = "OPENAI_API_KEY" +# required = true +# secret = true +# +# [[files]] +# path = "config/agents.toml" +# required = true +""" diff --git a/src/samsarix_platform/doctor.py b/src/samsarix_platform/doctor.py new file mode 100644 index 0000000..f867bcb --- /dev/null +++ b/src/samsarix_platform/doctor.py @@ -0,0 +1,216 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +"""Read-only readiness checks for a validated project manifest.""" + +from __future__ import annotations + +import importlib.metadata +import os +import sys +from collections.abc import Callable, Mapping +from dataclasses import asdict, dataclass +from pathlib import Path, PurePosixPath +from typing import Literal + +from samsarix_platform import __version__ +from samsarix_platform.manifest import ComponentSpec, EnvironmentSpec, FileSpec, Manifest + +CheckStatus = Literal["pass", "warn", "fail"] + + +@dataclass(frozen=True, slots=True) +class CheckResult: + """One independently actionable readiness result.""" + + category: str + name: str + status: CheckStatus + required: bool + message: str + remediation: str | None = None + + +@dataclass(frozen=True, slots=True) +class DoctorReport: + """All readiness results for one manifest snapshot.""" + + manifest_path: Path + project_name: str + checks: tuple[CheckResult, ...] + + def counts(self) -> dict[str, int]: + """Return stable per-status counts.""" + + return { + status: sum(check.status == status for check in self.checks) + for status in ("pass", "warn", "fail") + } + + def exit_code(self, *, strict: bool) -> int: + """Return 0 when ready and 1 when a declared policy is not satisfied.""" + + counts = self.counts() + if counts["fail"] or (strict and counts["warn"]): + return 1 + return 0 + + def status(self, *, strict: bool) -> str: + """Return a stable machine-readable summary status.""" + + if self.exit_code(strict=strict): + return "not_ready" + if self.counts()["warn"]: + return "ready_with_warnings" + return "ready" + + def to_dict(self, *, strict: bool) -> dict[str, object]: + """Serialize the report without including any checked secret values.""" + + return { + "schema": "samsarix-platform-doctor/v1", + "tool_version": __version__, + "manifest": str(self.manifest_path), + "project": self.project_name, + "strict": strict, + "status": self.status(strict=strict), + "exit_code": self.exit_code(strict=strict), + "summary": self.counts(), + "checks": [asdict(check) for check in self.checks], + } + + +def run_checks( + manifest: Manifest, + *, + environ: Mapping[str, str] | None = None, + python_version: tuple[int, int, int] | None = None, + version_lookup: Callable[[str], str] = importlib.metadata.version, +) -> DoctorReport: + """Evaluate all declared checks without importing components or making network calls.""" + + active_environment = os.environ if environ is None else environ + active_python = ( + (sys.version_info.major, sys.version_info.minor, sys.version_info.micro) + if python_version is None + else python_version + ) + checks: list[CheckResult] = [ + _check_python(manifest, active_python), + *(_check_component(component, version_lookup) for component in manifest.components), + *(_check_environment(item, active_environment) for item in manifest.environment), + *(_check_file(item, manifest.path.parent) for item in manifest.files), + ] + return DoctorReport( + manifest_path=manifest.path, + project_name=manifest.project.name, + checks=tuple(checks), + ) + + +def _check_python(manifest: Manifest, active: tuple[int, int, int]) -> CheckResult: + minimum = manifest.project.minimum_python + rendered = ".".join(str(part) for part in active) + if active >= minimum: + return CheckResult( + category="python", + name="Python runtime", + status="pass", + required=True, + message=f"Python {rendered} satisfies {manifest.project.requires_python}", + ) + return CheckResult( + category="python", + name="Python runtime", + status="fail", + required=True, + message=f"Python {rendered} does not satisfy {manifest.project.requires_python}", + remediation=f"Install Python {minimum[0]}.{minimum[1]} or newer.", + ) + + +def _check_component(component: ComponentSpec, version_lookup: Callable[[str], str]) -> CheckResult: + try: + installed_version = version_lookup(component.distribution) + except importlib.metadata.PackageNotFoundError: + status: CheckStatus = "fail" if component.required else "warn" + return CheckResult( + category="component", + name=component.name, + status=status, + required=component.required, + message=f"distribution {component.distribution!r} is not installed", + remediation=f"Install the {component.distribution!r} distribution in this environment.", + ) + return CheckResult( + category="component", + name=component.name, + status="pass", + required=component.required, + message=f"distribution {component.distribution!r} is installed at {installed_version}", + ) + + +def _check_environment(item: EnvironmentSpec, environ: Mapping[str, str]) -> CheckResult: + present = bool(environ.get(item.name, "").strip()) + if present: + qualifier = "secret value is set" if item.secret else "value is set" + return CheckResult( + category="environment", + name=item.name, + status="pass", + required=item.required, + message=qualifier, + ) + status: CheckStatus = "fail" if item.required else "warn" + return CheckResult( + category="environment", + name=item.name, + status=status, + required=item.required, + message="value is not set", + remediation=f"Set {item.name} in the process environment before running the application.", + ) + + +def _check_file(item: FileSpec, project_root: Path) -> CheckResult: + try: + root = project_root.resolve() + relative = Path(*PurePosixPath(item.path).parts) + resolved = (root / relative).resolve(strict=False) + except (OSError, RuntimeError): + return CheckResult( + category="file", + name=item.path, + status="fail", + required=True, + message="path could not be resolved safely", + remediation="Replace broken or cyclic links with a project-contained path.", + ) + if not resolved.is_relative_to(root): + return CheckResult( + category="file", + name=item.path, + status="fail", + required=True, + message="resolved path escapes the manifest directory", + remediation="Replace the path or symlink with a project-contained target.", + ) + if resolved.exists(): + kind = "directory" if resolved.is_dir() else "file" + return CheckResult( + category="file", + name=item.path, + status="pass", + required=item.required, + message=f"{kind} exists", + ) + status: CheckStatus = "fail" if item.required else "warn" + return CheckResult( + category="file", + name=item.path, + status=status, + required=item.required, + message="path does not exist", + remediation=f"Create {item.path!r} relative to the manifest directory.", + ) diff --git a/src/samsarix_platform/manifest.py b/src/samsarix_platform/manifest.py new file mode 100644 index 0000000..6ff229c --- /dev/null +++ b/src/samsarix_platform/manifest.py @@ -0,0 +1,278 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +"""Strict parsing for the versioned ``samsarix-stack.toml`` format.""" + +from __future__ import annotations + +import re +import tomllib +import unicodedata +from dataclasses import dataclass +from pathlib import Path, PurePosixPath +from typing import cast + +_PYTHON_REQUIREMENT = re.compile(r">=(\d+)\.(\d+)(?:\.(\d+))?\Z") +_ENVIRONMENT_NAME = re.compile(r"[A-Za-z_][A-Za-z0-9_]*\Z") +_DISTRIBUTION_NAME = re.compile(r"[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?\Z") +MAX_MANIFEST_BYTES = 1_048_576 + + +class ManifestError(ValueError): + """Raised when a manifest cannot be loaded or does not match the schema.""" + + +@dataclass(frozen=True, slots=True) +class ProjectSpec: + """Project-level manifest settings.""" + + name: str + requires_python: str + minimum_python: tuple[int, int, int] + + +@dataclass(frozen=True, slots=True) +class ComponentSpec: + """An installed Python distribution required by the project.""" + + name: str + distribution: str + required: bool + description: str | None + + +@dataclass(frozen=True, slots=True) +class EnvironmentSpec: + """An environment variable whose presence may be required.""" + + name: str + required: bool + secret: bool + description: str | None + + +@dataclass(frozen=True, slots=True) +class FileSpec: + """A project-relative file or directory whose presence may be required.""" + + path: str + required: bool + description: str | None + + +@dataclass(frozen=True, slots=True) +class Manifest: + """A fully validated version 1 project manifest.""" + + path: Path + schema_version: int + project: ProjectSpec + components: tuple[ComponentSpec, ...] + environment: tuple[EnvironmentSpec, ...] + files: tuple[FileSpec, ...] + + +def load_manifest(path: Path) -> Manifest: + """Load and validate a Samsarix stack manifest from ``path``.""" + + try: + manifest_path = path.expanduser().resolve() + except (OSError, RuntimeError) as exc: + raise ManifestError(f"could not resolve manifest path {path}: {exc}") from exc + if manifest_path.is_dir(): + raise ManifestError(f"manifest path is a directory: {manifest_path}") + try: + with manifest_path.open("rb") as handle: + payload = handle.read(MAX_MANIFEST_BYTES + 1) + if len(payload) > MAX_MANIFEST_BYTES: + raise ManifestError( + f"manifest exceeds the {MAX_MANIFEST_BYTES}-byte size limit: {manifest_path}" + ) + raw = tomllib.loads(payload.decode("utf-8")) + except FileNotFoundError as exc: + raise ManifestError(f"manifest not found: {manifest_path}") from exc + except IsADirectoryError as exc: + raise ManifestError(f"manifest path is a directory: {manifest_path}") from exc + except PermissionError as exc: + raise ManifestError(f"manifest is not readable: {manifest_path}") from exc + except OSError as exc: + raise ManifestError(f"could not read manifest {manifest_path}: {exc}") from exc + except UnicodeDecodeError as exc: + raise ManifestError(f"manifest is not valid UTF-8: {manifest_path}") from exc + except tomllib.TOMLDecodeError as exc: + raise ManifestError(f"invalid TOML in {manifest_path}: {exc}") from exc + + root = _as_table(raw, "manifest") + _reject_unknown( + root, {"schema_version", "project", "components", "environment", "files"}, "manifest" + ) + + schema_version = root.get("schema_version") + if type(schema_version) is not int: + raise ManifestError("manifest.schema_version must be the integer 1") + if schema_version != 1: + raise ManifestError(f"unsupported manifest.schema_version {schema_version}; expected 1") + + project = _parse_project(root.get("project")) + components = _parse_components(root.get("components", [])) + environment = _parse_environment(root.get("environment", [])) + files = _parse_files(root.get("files", [])) + + return Manifest( + path=manifest_path, + schema_version=schema_version, + project=project, + components=components, + environment=environment, + files=files, + ) + + +def _parse_project(value: object) -> ProjectSpec: + table = _as_table(value, "manifest.project") + _reject_unknown(table, {"name", "requires_python"}, "manifest.project") + name = _required_string(table, "name", "manifest.project") + requires_python = _required_string(table, "requires_python", "manifest.project") + match = _PYTHON_REQUIREMENT.fullmatch(requires_python) + if match is None: + raise ManifestError( + "manifest.project.requires_python must use the form " + ">=MAJOR.MINOR or >=MAJOR.MINOR.PATCH" + ) + minimum_python = tuple(int(part or 0) for part in match.groups()) + return ProjectSpec( + name=name, + requires_python=requires_python, + minimum_python=cast(tuple[int, int, int], minimum_python), + ) + + +def _parse_components(value: object) -> tuple[ComponentSpec, ...]: + items = _as_array(value, "manifest.components") + parsed: list[ComponentSpec] = [] + identities: set[str] = set() + for index, item in enumerate(items): + section = f"manifest.components[{index}]" + table = _as_table(item, section) + _reject_unknown(table, {"name", "distribution", "required", "description"}, section) + name = _required_string(table, "name", section) + distribution = _required_string(table, "distribution", section) + if _DISTRIBUTION_NAME.fullmatch(distribution) is None: + raise ManifestError(f"{section}.distribution is not a valid distribution name") + identity = distribution.casefold() + if identity in identities: + raise ManifestError(f"{section}.distribution duplicates {distribution!r}") + identities.add(identity) + parsed.append( + ComponentSpec( + name=name, + distribution=distribution, + required=_optional_bool(table, "required", section, default=True), + description=_optional_string(table, "description", section), + ) + ) + return tuple(parsed) + + +def _parse_environment(value: object) -> tuple[EnvironmentSpec, ...]: + items = _as_array(value, "manifest.environment") + parsed: list[EnvironmentSpec] = [] + identities: set[str] = set() + for index, item in enumerate(items): + section = f"manifest.environment[{index}]" + table = _as_table(item, section) + _reject_unknown(table, {"name", "required", "secret", "description"}, section) + name = _required_string(table, "name", section) + if _ENVIRONMENT_NAME.fullmatch(name) is None: + raise ManifestError(f"{section}.name is not a portable environment-variable name") + identity = name.casefold() + if identity in identities: + raise ManifestError(f"{section}.name duplicates {name!r}") + identities.add(identity) + parsed.append( + EnvironmentSpec( + name=name, + required=_optional_bool(table, "required", section, default=True), + secret=_optional_bool(table, "secret", section, default=True), + description=_optional_string(table, "description", section), + ) + ) + return tuple(parsed) + + +def _parse_files(value: object) -> tuple[FileSpec, ...]: + items = _as_array(value, "manifest.files") + parsed: list[FileSpec] = [] + identities: set[str] = set() + for index, item in enumerate(items): + section = f"manifest.files[{index}]" + table = _as_table(item, section) + _reject_unknown(table, {"path", "required", "description"}, section) + raw_path = _required_string(table, "path", section) + if "\\" in raw_path: + raise ManifestError(f"{section}.path must use portable forward slashes") + portable_path = PurePosixPath(raw_path) + if portable_path.is_absolute() or ".." in portable_path.parts or raw_path == ".": + raise ManifestError(f"{section}.path must stay inside the manifest directory") + normalized = portable_path.as_posix() + identity = normalized.casefold() + if identity in identities: + raise ManifestError(f"{section}.path duplicates {raw_path!r}") + identities.add(identity) + parsed.append( + FileSpec( + path=normalized, + required=_optional_bool(table, "required", section, default=True), + description=_optional_string(table, "description", section), + ) + ) + return tuple(parsed) + + +def _as_table(value: object, section: str) -> dict[str, object]: + if not isinstance(value, dict) or not all(isinstance(key, str) for key in value): + raise ManifestError(f"{section} must be a TOML table") + return cast(dict[str, object], value) + + +def _as_array(value: object, section: str) -> list[object]: + if not isinstance(value, list): + raise ManifestError(f"{section} must be an array of tables") + return cast(list[object], value) + + +def _reject_unknown(table: dict[str, object], allowed: set[str], section: str) -> None: + unknown = sorted(set(table) - allowed) + if unknown: + joined = ", ".join(repr(key) for key in unknown) + raise ManifestError(f"{section} contains unknown key(s): {joined}") + + +def _required_string(table: dict[str, object], key: str, section: str) -> str: + value = table.get(key) + if not isinstance(value, str) or not value.strip(): + raise ManifestError(f"{section}.{key} must be a non-empty string") + _reject_control_characters(value, f"{section}.{key}") + return value.strip() + + +def _optional_string(table: dict[str, object], key: str, section: str) -> str | None: + value = table.get(key) + if value is None: + return None + if not isinstance(value, str) or not value.strip(): + raise ManifestError(f"{section}.{key} must be a non-empty string when provided") + _reject_control_characters(value, f"{section}.{key}") + return value.strip() + + +def _reject_control_characters(value: str, field: str) -> None: + if any(unicodedata.category(character) in {"Cc", "Cf"} for character in value): + raise ManifestError(f"{field} must not contain control or formatting characters") + + +def _optional_bool(table: dict[str, object], key: str, section: str, *, default: bool) -> bool: + value = table.get(key, default) + if not isinstance(value, bool): + raise ManifestError(f"{section}.{key} must be a boolean") + return value diff --git a/src/samsarix_platform/py.typed b/src/samsarix_platform/py.typed new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/samsarix_platform/py.typed @@ -0,0 +1 @@ + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..b700ae1 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +"""Samsarix Platform Doctor test suite.""" diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..55a6681 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,128 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +from __future__ import annotations + +import contextlib +import io +import json +import runpy +import sys +import tempfile +import unittest +from pathlib import Path +from unittest import mock + +from samsarix_platform.cli import main + + +class CliTests(unittest.TestCase): + temporary: tempfile.TemporaryDirectory[str] + root: Path + + def setUp(self) -> None: + self.temporary = tempfile.TemporaryDirectory() + self.addCleanup(self.temporary.cleanup) + self.root = Path(self.temporary.name) + + def invoke(self, arguments: list[str]) -> tuple[int, str, str]: + stdout = io.StringIO() + stderr = io.StringIO() + with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr): + exit_code = main(arguments) + return exit_code, stdout.getvalue(), stderr.getvalue() + + def test_init_creates_a_manifest_that_is_immediately_checkable(self) -> None: + manifest = self.root / "samsarix-stack.toml" + + init_code, init_output, init_error = self.invoke( + ["init", str(manifest), "--name", "Example Agent"] + ) + doctor_code, doctor_output, doctor_error = self.invoke(["doctor", str(manifest)]) + + self.assertEqual(init_code, 0) + self.assertIn("Created", init_output) + self.assertEqual(init_error, "") + self.assertEqual(doctor_code, 0) + self.assertIn("Result: READY", doctor_output) + self.assertEqual(doctor_error, "") + + def test_init_refuses_to_overwrite_existing_content(self) -> None: + manifest = self.root / "samsarix-stack.toml" + manifest.write_text("do not replace\n", encoding="utf-8") + + exit_code, _, error = self.invoke(["init", str(manifest)]) + + self.assertEqual(exit_code, 2) + self.assertIn("refusing to overwrite", error) + self.assertEqual(manifest.read_text(encoding="utf-8"), "do not replace\n") + + def test_init_refuses_a_dangling_symlink_without_creating_its_target(self) -> None: + target = self.root.parent / f"{self.root.name}-outside.toml" + self.addCleanup(target.unlink, missing_ok=True) + link = self.root / "samsarix-stack.toml" + try: + link.symlink_to(target) + except OSError as exc: + self.skipTest(f"symlinks unavailable: {exc}") + + exit_code, _, error = self.invoke(["init", str(link)]) + + self.assertEqual(exit_code, 2) + self.assertIn("refusing to overwrite", error) + self.assertFalse(target.exists()) + + def test_missing_manifest_is_a_distinct_input_error(self) -> None: + exit_code, output, error = self.invoke(["doctor", str(self.root / "missing.toml")]) + + self.assertEqual(exit_code, 2) + self.assertEqual(output, "") + self.assertIn("manifest not found", error) + + def test_invalid_manifest_json_is_machine_readable(self) -> None: + exit_code, output, error = self.invoke( + ["doctor", str(self.root / "missing.toml"), "--json"] + ) + + payload = json.loads(output) + self.assertEqual(exit_code, 2) + self.assertEqual(payload["status"], "invalid_manifest") + self.assertEqual(payload["exit_code"], 2) + self.assertEqual(error, "") + + def test_valid_doctor_json_is_machine_readable(self) -> None: + manifest = self.root / "samsarix-stack.toml" + self.invoke(["init", str(manifest), "--name", "JSON Example"]) + + exit_code, output, error = self.invoke(["doctor", str(manifest), "--json"]) + + payload = json.loads(output) + self.assertEqual(exit_code, 0) + self.assertEqual(payload["schema"], "samsarix-platform-doctor/v1") + self.assertEqual(payload["status"], "ready") + self.assertEqual(payload["project"], "JSON Example") + self.assertEqual(error, "") + + def test_init_reports_a_missing_destination_directory(self) -> None: + destination = self.root / "missing" / "samsarix-stack.toml" + + exit_code, _, error = self.invoke(["init", str(destination)]) + + self.assertEqual(exit_code, 2) + self.assertIn("directory does not exist", error) + + def test_module_entry_point_reports_version(self) -> None: + stdout = io.StringIO() + with ( + mock.patch.object(sys, "argv", ["samsarix-platform", "--version"]), + contextlib.redirect_stdout(stdout), + self.assertRaises(SystemExit) as raised, + ): + runpy.run_module("samsarix_platform", run_name="__main__") + + self.assertEqual(raised.exception.code, 0) + self.assertIn("samsarix-platform 0.1.0", stdout.getvalue()) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_doctor.py b/tests/test_doctor.py new file mode 100644 index 0000000..2413f8f --- /dev/null +++ b/tests/test_doctor.py @@ -0,0 +1,166 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +from __future__ import annotations + +import importlib.metadata +import json +import tempfile +import unittest +from pathlib import Path + +from samsarix_platform.doctor import run_checks +from samsarix_platform.manifest import load_manifest + + +class DoctorTests(unittest.TestCase): + temporary: tempfile.TemporaryDirectory[str] + root: Path + + def setUp(self) -> None: + self.temporary = tempfile.TemporaryDirectory() + self.addCleanup(self.temporary.cleanup) + self.root = Path(self.temporary.name) + (self.root / "required.txt").write_text("ready\n", encoding="utf-8") + + def manifest( + self, *, component_required: bool = True, environment_required: bool = True + ) -> Path: + path = self.root / "samsarix-stack.toml" + path.write_text( + f"""\ +schema_version = 1 + +[project] +name = "Example" +requires_python = ">=3.11" + +[[components]] +name = "Example package" +distribution = "example-package" +required = {str(component_required).lower()} + +[[environment]] +name = "EXAMPLE_SECRET" +required = {str(environment_required).lower()} +secret = true + +[[files]] +path = "required.txt" +required = true +""", + encoding="utf-8", + ) + return path + + @staticmethod + def installed_version(distribution: str) -> str: + if distribution == "example-package": + return "1.2.3" + raise importlib.metadata.PackageNotFoundError(distribution) + + @staticmethod + def missing_version(distribution: str) -> str: + raise importlib.metadata.PackageNotFoundError(distribution) + + def test_all_required_checks_pass(self) -> None: + manifest = load_manifest(self.manifest()) + + report = run_checks( + manifest, + environ={"EXAMPLE_SECRET": "super-secret-value"}, + python_version=(3, 11, 9), + version_lookup=self.installed_version, + ) + + self.assertEqual(report.exit_code(strict=False), 0) + self.assertEqual(report.status(strict=False), "ready") + self.assertEqual(report.counts(), {"pass": 4, "warn": 0, "fail": 0}) + + def test_required_failures_return_exit_one(self) -> None: + manifest = load_manifest(self.manifest()) + + report = run_checks( + manifest, + environ={}, + python_version=(3, 10, 14), + version_lookup=self.missing_version, + ) + + self.assertEqual(report.exit_code(strict=False), 1) + self.assertEqual(report.status(strict=False), "not_ready") + self.assertEqual(report.counts()["fail"], 3) + + def test_optional_missing_items_warn_and_strict_mode_fails(self) -> None: + manifest = load_manifest( + self.manifest(component_required=False, environment_required=False) + ) + + report = run_checks( + manifest, + environ={}, + python_version=(3, 11, 0), + version_lookup=self.missing_version, + ) + + self.assertEqual(report.exit_code(strict=False), 0) + self.assertEqual(report.status(strict=False), "ready_with_warnings") + self.assertEqual(report.exit_code(strict=True), 1) + + def test_json_report_never_contains_a_secret_value(self) -> None: + manifest = load_manifest(self.manifest()) + report = run_checks( + manifest, + environ={"EXAMPLE_SECRET": "super-secret-value"}, + version_lookup=self.installed_version, + ) + + encoded = json.dumps(report.to_dict(strict=False)) + + self.assertNotIn("super-secret-value", encoded) + self.assertIn("secret value is set", encoded) + + def test_resolved_symlink_escape_fails_safely(self) -> None: + outside = self.root.parent / f"{self.root.name}-outside.txt" + outside.write_text("outside\n", encoding="utf-8") + self.addCleanup(outside.unlink, missing_ok=True) + link = self.root / "required.txt" + link.unlink() + try: + link.symlink_to(outside) + except OSError as exc: + self.skipTest(f"symlinks unavailable: {exc}") + manifest = load_manifest(self.manifest()) + + report = run_checks( + manifest, + environ={"EXAMPLE_SECRET": "set"}, + version_lookup=self.installed_version, + ) + + file_check = next(check for check in report.checks if check.category == "file") + self.assertEqual(file_check.status, "fail") + self.assertIn("escapes", file_check.message) + + def test_symlink_loop_is_a_structured_file_failure(self) -> None: + link = self.root / "required.txt" + link.unlink() + try: + link.symlink_to(link) + except OSError as exc: + self.skipTest(f"symlinks unavailable: {exc}") + manifest = load_manifest(self.manifest()) + + report = run_checks( + manifest, + environ={"EXAMPLE_SECRET": "set"}, + version_lookup=self.installed_version, + ) + + file_check = next(check for check in report.checks if check.category == "file") + self.assertEqual(file_check.status, "fail") + self.assertIn("resolved safely", file_check.message) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_example.py b/tests/test_example.py new file mode 100644 index 0000000..aa616ae --- /dev/null +++ b/tests/test_example.py @@ -0,0 +1,30 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +from __future__ import annotations + +import importlib.metadata +import unittest +from pathlib import Path + +from samsarix_platform.doctor import run_checks +from samsarix_platform.manifest import load_manifest + + +class ExampleTests(unittest.TestCase): + def test_example_manifest_is_valid_and_non_strict_ready(self) -> None: + repository = Path(__file__).resolve().parents[1] + manifest = load_manifest(repository / "examples" / "agent-project" / "samsarix-stack.toml") + + def missing_optional(distribution: str) -> str: + raise importlib.metadata.PackageNotFoundError(distribution) + + report = run_checks(manifest, environ={}, version_lookup=missing_optional) + + self.assertEqual(report.exit_code(strict=False), 0) + self.assertEqual(report.exit_code(strict=True), 1) + self.assertEqual(report.counts()["warn"], 2) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_manifest.py b/tests/test_manifest.py new file mode 100644 index 0000000..0a6db5f --- /dev/null +++ b/tests/test_manifest.py @@ -0,0 +1,188 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +from __future__ import annotations + +import tempfile +import unittest +from pathlib import Path + +from samsarix_platform.manifest import MAX_MANIFEST_BYTES, ManifestError, load_manifest + +VALID_MANIFEST = """\ +schema_version = 1 + +[project] +name = "Example" +requires_python = ">=3.11" + +[[components]] +name = "Example package" +distribution = "example-package" +required = false + +[[environment]] +name = "EXAMPLE_TOKEN" +required = true +secret = true + +[[files]] +path = "README.md" +required = true +""" + + +class ManifestTests(unittest.TestCase): + temporary: tempfile.TemporaryDirectory[str] + root: Path + + def setUp(self) -> None: + self.temporary = tempfile.TemporaryDirectory() + self.addCleanup(self.temporary.cleanup) + self.root = Path(self.temporary.name) + + def write_manifest(self, content: str = VALID_MANIFEST) -> Path: + path = self.root / "samsarix-stack.toml" + path.write_text(content, encoding="utf-8") + return path + + def test_loads_a_valid_manifest(self) -> None: + path = self.write_manifest() + + manifest = load_manifest(path) + + self.assertEqual(manifest.schema_version, 1) + self.assertEqual(manifest.project.name, "Example") + self.assertEqual(manifest.project.minimum_python, (3, 11, 0)) + self.assertEqual(manifest.components[0].distribution, "example-package") + self.assertEqual(manifest.environment[0].name, "EXAMPLE_TOKEN") + self.assertEqual(manifest.files[0].path, "README.md") + + def test_reports_invalid_toml_with_context(self) -> None: + path = self.write_manifest("schema_version = [") + + with self.assertRaisesRegex(ManifestError, "invalid TOML"): + load_manifest(path) + + def test_reports_a_missing_manifest(self) -> None: + with self.assertRaisesRegex(ManifestError, "manifest not found"): + load_manifest(self.root / "missing.toml") + + def test_reports_a_manifest_symlink_loop(self) -> None: + path = self.root / "samsarix-stack.toml" + try: + path.symlink_to(path) + except OSError as exc: + self.skipTest(f"symlinks unavailable: {exc}") + + with self.assertRaisesRegex(ManifestError, "could not resolve manifest path"): + load_manifest(path) + + def test_reports_a_directory_instead_of_a_manifest(self) -> None: + with self.assertRaisesRegex(ManifestError, "path is a directory"): + load_manifest(self.root) + + def test_rejects_oversized_manifests_before_parsing(self) -> None: + path = self.root / "samsarix-stack.toml" + path.write_bytes(b"#" * (MAX_MANIFEST_BYTES + 1)) + + with self.assertRaisesRegex(ManifestError, "size limit"): + load_manifest(path) + + def test_rejects_non_utf8_manifests(self) -> None: + path = self.root / "samsarix-stack.toml" + path.write_bytes(b"schema_version = 1\n# \xff") + + with self.assertRaisesRegex(ManifestError, "valid UTF-8"): + load_manifest(path) + + def test_rejects_unknown_keys_instead_of_ignoring_typos(self) -> None: + path = self.write_manifest(VALID_MANIFEST.replace("required = false", "requred = false")) + + with self.assertRaisesRegex(ManifestError, "unknown key.*requred"): + load_manifest(path) + + def test_rejects_unsupported_schema_versions(self) -> None: + path = self.write_manifest( + VALID_MANIFEST.replace("schema_version = 1", "schema_version = 2") + ) + + with self.assertRaisesRegex(ManifestError, "unsupported"): + load_manifest(path) + + def test_rejects_non_integer_schema_versions(self) -> None: + path = self.write_manifest( + VALID_MANIFEST.replace("schema_version = 1", 'schema_version = "1"') + ) + + with self.assertRaisesRegex(ManifestError, "must be the integer 1"): + load_manifest(path) + + def test_rejects_non_array_component_sections(self) -> None: + path = self.write_manifest(VALID_MANIFEST.replace("[[components]]", "[components]", 1)) + + with self.assertRaisesRegex(ManifestError, "must be an array of tables"): + load_manifest(path) + + def test_rejects_duplicate_distribution_names_case_insensitively(self) -> None: + duplicate = """ +[[components]] +name = "Duplicate" +distribution = "EXAMPLE-PACKAGE" +""" + path = self.write_manifest(VALID_MANIFEST + duplicate) + + with self.assertRaisesRegex(ManifestError, "duplicates"): + load_manifest(path) + + def test_rejects_invalid_distribution_names(self) -> None: + path = self.write_manifest(VALID_MANIFEST.replace("example-package", "../package")) + + with self.assertRaisesRegex(ManifestError, "valid distribution name"): + load_manifest(path) + + def test_rejects_file_traversal(self) -> None: + path = self.write_manifest( + VALID_MANIFEST.replace('path = "README.md"', 'path = "../secret"') + ) + + with self.assertRaisesRegex(ManifestError, "must stay inside"): + load_manifest(path) + + def test_rejects_platform_specific_file_separators(self) -> None: + path = self.write_manifest( + VALID_MANIFEST.replace('path = "README.md"', 'path = "docs\\\\file.md"') + ) + + with self.assertRaisesRegex(ManifestError, "forward slashes"): + load_manifest(path) + + def test_requires_a_constrained_python_version(self) -> None: + path = self.write_manifest(VALID_MANIFEST.replace(">=3.11", "3.11")) + + with self.assertRaisesRegex(ManifestError, "form >=MAJOR.MINOR"): + load_manifest(path) + + def test_rejects_invalid_environment_names(self) -> None: + path = self.write_manifest(VALID_MANIFEST.replace("EXAMPLE_TOKEN", "BAD-NAME")) + + with self.assertRaisesRegex(ManifestError, "portable environment-variable"): + load_manifest(path) + + def test_rejects_non_boolean_required_values(self) -> None: + path = self.write_manifest(VALID_MANIFEST.replace("required = false", 'required = "no"')) + + with self.assertRaisesRegex(ManifestError, "required must be a boolean"): + load_manifest(path) + + def test_rejects_terminal_control_characters(self) -> None: + path = self.write_manifest( + VALID_MANIFEST.replace('name = "Example"', 'name = "Bad\\u001b"') + ) + + with self.assertRaisesRegex(ManifestError, "control or formatting"): + load_manifest(path) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_package.py b/tests/test_package.py new file mode 100644 index 0000000..c29565a --- /dev/null +++ b/tests/test_package.py @@ -0,0 +1,34 @@ +# Copyright (c) 2026 Samsarix LLC +# SPDX-License-Identifier: MPL-2.0 + +from __future__ import annotations + +import importlib.metadata +import unittest + +from samsarix_platform import __version__ + + +class InstalledPackageTests(unittest.TestCase): + def test_distribution_and_module_versions_match(self) -> None: + self.assertEqual(importlib.metadata.version("samsarix-platform"), __version__) + + def test_distribution_identifies_samsarix_and_mpl_license(self) -> None: + metadata = importlib.metadata.metadata("samsarix-platform") + + self.assertEqual(metadata["Name"], "samsarix-platform") + self.assertEqual(metadata["License-Expression"], "MPL-2.0") + self.assertIn("Samsarix LLC", metadata["Author-email"]) + self.assertIn("Samsarix LLC", metadata["Maintainer-email"]) + + def test_console_script_is_installed(self) -> None: + scripts = tuple( + importlib.metadata.entry_points(group="console_scripts", name="samsarix-platform") + ) + + self.assertEqual(len(scripts), 1) + self.assertEqual(scripts[0].value, "samsarix_platform.cli:main") + + +if __name__ == "__main__": + unittest.main()