Showing preview only (1,176K chars total). Download the full file or copy to clipboard to get everything.
Repository: usestrix/strix
Branch: main
Commit: c9d2477144f8
Files: 207
Total size: 1.1 MB
Directory structure:
gitextract_bz27uie2/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── build-release.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── benchmarks/
│ └── README.md
├── containers/
│ ├── Dockerfile
│ └── docker-entrypoint.sh
├── docs/
│ ├── README.md
│ ├── advanced/
│ │ ├── configuration.mdx
│ │ └── skills.mdx
│ ├── cloud/
│ │ └── overview.mdx
│ ├── contributing.mdx
│ ├── docs.json
│ ├── index.mdx
│ ├── integrations/
│ │ ├── ci-cd.mdx
│ │ └── github-actions.mdx
│ ├── llm-providers/
│ │ ├── anthropic.mdx
│ │ ├── azure.mdx
│ │ ├── bedrock.mdx
│ │ ├── local.mdx
│ │ ├── models.mdx
│ │ ├── openai.mdx
│ │ ├── openrouter.mdx
│ │ ├── overview.mdx
│ │ └── vertex.mdx
│ ├── quickstart.mdx
│ ├── tools/
│ │ ├── browser.mdx
│ │ ├── overview.mdx
│ │ ├── proxy.mdx
│ │ ├── sandbox.mdx
│ │ └── terminal.mdx
│ └── usage/
│ ├── cli.mdx
│ ├── instructions.mdx
│ └── scan-modes.mdx
├── pyproject.toml
├── scripts/
│ ├── build.sh
│ └── install.sh
├── strix/
│ ├── __init__.py
│ ├── agents/
│ │ ├── StrixAgent/
│ │ │ ├── __init__.py
│ │ │ ├── strix_agent.py
│ │ │ └── system_prompt.jinja
│ │ ├── __init__.py
│ │ ├── base_agent.py
│ │ └── state.py
│ ├── config/
│ │ ├── __init__.py
│ │ └── config.py
│ ├── interface/
│ │ ├── __init__.py
│ │ ├── assets/
│ │ │ └── tui_styles.tcss
│ │ ├── cli.py
│ │ ├── main.py
│ │ ├── streaming_parser.py
│ │ ├── tool_components/
│ │ │ ├── __init__.py
│ │ │ ├── agent_message_renderer.py
│ │ │ ├── agents_graph_renderer.py
│ │ │ ├── base_renderer.py
│ │ │ ├── browser_renderer.py
│ │ │ ├── file_edit_renderer.py
│ │ │ ├── finish_renderer.py
│ │ │ ├── load_skill_renderer.py
│ │ │ ├── notes_renderer.py
│ │ │ ├── proxy_renderer.py
│ │ │ ├── python_renderer.py
│ │ │ ├── registry.py
│ │ │ ├── reporting_renderer.py
│ │ │ ├── scan_info_renderer.py
│ │ │ ├── terminal_renderer.py
│ │ │ ├── thinking_renderer.py
│ │ │ ├── todo_renderer.py
│ │ │ ├── user_message_renderer.py
│ │ │ └── web_search_renderer.py
│ │ ├── tui.py
│ │ └── utils.py
│ ├── llm/
│ │ ├── __init__.py
│ │ ├── config.py
│ │ ├── dedupe.py
│ │ ├── llm.py
│ │ ├── memory_compressor.py
│ │ └── utils.py
│ ├── runtime/
│ │ ├── __init__.py
│ │ ├── docker_runtime.py
│ │ ├── runtime.py
│ │ └── tool_server.py
│ ├── skills/
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── cloud/
│ │ │ └── .gitkeep
│ │ ├── coordination/
│ │ │ └── root_agent.md
│ │ ├── custom/
│ │ │ └── .gitkeep
│ │ ├── frameworks/
│ │ │ ├── fastapi.md
│ │ │ ├── nestjs.md
│ │ │ └── nextjs.md
│ │ ├── protocols/
│ │ │ └── graphql.md
│ │ ├── reconnaissance/
│ │ │ └── .gitkeep
│ │ ├── scan_modes/
│ │ │ ├── deep.md
│ │ │ ├── quick.md
│ │ │ └── standard.md
│ │ ├── technologies/
│ │ │ ├── firebase_firestore.md
│ │ │ └── supabase.md
│ │ ├── tooling/
│ │ │ ├── ffuf.md
│ │ │ ├── httpx.md
│ │ │ ├── katana.md
│ │ │ ├── naabu.md
│ │ │ ├── nmap.md
│ │ │ ├── nuclei.md
│ │ │ ├── semgrep.md
│ │ │ ├── sqlmap.md
│ │ │ └── subfinder.md
│ │ └── vulnerabilities/
│ │ ├── authentication_jwt.md
│ │ ├── broken_function_level_authorization.md
│ │ ├── business_logic.md
│ │ ├── csrf.md
│ │ ├── idor.md
│ │ ├── information_disclosure.md
│ │ ├── insecure_file_uploads.md
│ │ ├── mass_assignment.md
│ │ ├── open_redirect.md
│ │ ├── path_traversal_lfi_rfi.md
│ │ ├── race_conditions.md
│ │ ├── rce.md
│ │ ├── sql_injection.md
│ │ ├── ssrf.md
│ │ ├── subdomain_takeover.md
│ │ ├── xss.md
│ │ └── xxe.md
│ ├── telemetry/
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── flags.py
│ │ ├── posthog.py
│ │ ├── tracer.py
│ │ └── utils.py
│ ├── tools/
│ │ ├── __init__.py
│ │ ├── agents_graph/
│ │ │ ├── __init__.py
│ │ │ ├── agents_graph_actions.py
│ │ │ └── agents_graph_actions_schema.xml
│ │ ├── argument_parser.py
│ │ ├── browser/
│ │ │ ├── __init__.py
│ │ │ ├── browser_actions.py
│ │ │ ├── browser_actions_schema.xml
│ │ │ ├── browser_instance.py
│ │ │ └── tab_manager.py
│ │ ├── context.py
│ │ ├── executor.py
│ │ ├── file_edit/
│ │ │ ├── __init__.py
│ │ │ ├── file_edit_actions.py
│ │ │ └── file_edit_actions_schema.xml
│ │ ├── finish/
│ │ │ ├── __init__.py
│ │ │ ├── finish_actions.py
│ │ │ └── finish_actions_schema.xml
│ │ ├── load_skill/
│ │ │ ├── __init__.py
│ │ │ ├── load_skill_actions.py
│ │ │ └── load_skill_actions_schema.xml
│ │ ├── notes/
│ │ │ ├── __init__.py
│ │ │ ├── notes_actions.py
│ │ │ └── notes_actions_schema.xml
│ │ ├── proxy/
│ │ │ ├── __init__.py
│ │ │ ├── proxy_actions.py
│ │ │ ├── proxy_actions_schema.xml
│ │ │ └── proxy_manager.py
│ │ ├── python/
│ │ │ ├── __init__.py
│ │ │ ├── python_actions.py
│ │ │ ├── python_actions_schema.xml
│ │ │ ├── python_instance.py
│ │ │ └── python_manager.py
│ │ ├── registry.py
│ │ ├── reporting/
│ │ │ ├── __init__.py
│ │ │ ├── reporting_actions.py
│ │ │ └── reporting_actions_schema.xml
│ │ ├── terminal/
│ │ │ ├── __init__.py
│ │ │ ├── terminal_actions.py
│ │ │ ├── terminal_actions_schema.xml
│ │ │ ├── terminal_manager.py
│ │ │ └── terminal_session.py
│ │ ├── thinking/
│ │ │ ├── __init__.py
│ │ │ ├── thinking_actions.py
│ │ │ └── thinking_actions_schema.xml
│ │ ├── todo/
│ │ │ ├── __init__.py
│ │ │ ├── todo_actions.py
│ │ │ └── todo_actions_schema.xml
│ │ └── web_search/
│ │ ├── __init__.py
│ │ ├── web_search_actions.py
│ │ └── web_search_actions_schema.xml
│ └── utils/
│ ├── __init__.py
│ └── resource_paths.py
├── strix.spec
└── tests/
├── __init__.py
├── agents/
│ └── __init__.py
├── config/
│ ├── __init__.py
│ └── test_config_telemetry.py
├── conftest.py
├── interface/
│ └── __init__.py
├── llm/
│ ├── __init__.py
│ └── test_llm_otel.py
├── runtime/
│ └── __init__.py
├── skills/
│ └── __init__.py
├── telemetry/
│ ├── __init__.py
│ ├── test_flags.py
│ ├── test_tracer.py
│ └── test_utils.py
└── tools/
├── __init__.py
├── conftest.py
├── test_argument_parser.py
├── test_load_skill_tool.py
└── test_tool_registration_modes.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1.
2.
3.
4.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System Information:**
- OS: [e.g. Ubuntu 22.04]
- Strix Version or Commit: [e.g. 0.1.18]
- Python Version: [e.g. 3.12]
- LLM Used: [e.g. GPT-5, Claude Sonnet 4.6]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/build-release.yml
================================================
name: Build & Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
target: macos-arm64
- os: macos-15-intel
target: macos-x86_64
- os: ubuntu-latest
target: linux-x86_64
- os: windows-latest
target: windows-x86_64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: snok/install-poetry@v1
- name: Build
shell: bash
run: |
poetry install --with dev
poetry run pyinstaller strix.spec --noconfirm
VERSION=$(poetry version -s)
mkdir -p dist/release
if [[ "${{ runner.os }}" == "Windows" ]]; then
cp dist/strix.exe "dist/release/strix-${VERSION}-${{ matrix.target }}.exe"
(cd dist/release && 7z a "strix-${VERSION}-${{ matrix.target }}.zip" "strix-${VERSION}-${{ matrix.target }}.exe")
else
cp dist/strix "dist/release/strix-${VERSION}-${{ matrix.target }}"
chmod +x "dist/release/strix-${VERSION}-${{ matrix.target }}"
tar -C dist/release -czvf "dist/release/strix-${VERSION}-${{ matrix.target }}.tar.gz" "strix-${VERSION}-${{ matrix.target }}"
fi
- uses: actions/upload-artifact@v4
with:
name: strix-${{ matrix.target }}
path: |
dist/release/*.tar.gz
dist/release/*.zip
if-no-files-found: error
release:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
path: release
merge-multiple: true
- name: Create Release
uses: softprops/action-gh-release@v2
with:
prerelease: ${{ !startsWith(github.ref, 'refs/tags/') }}
generate_release_notes: true
files: release/*
================================================
FILE: .gitignore
================================================
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual Environment
venv/
env/
ENV/
.env
.venv
pip-log.txt
pip-delete-this-directory.txt
# IDE
.idea/
.vscode/
*.swp
*.swo
.DS_Store
.project
.pydevproject
.settings/
# Testing
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
htmlcov/
# FastAPI
.env.local
.env.development.local
.env.test.local
.env.production.local
# MongoDB
data/
mongod.log
*.mongodb
*.mongorc.js
# LLM and ML related
*.bin
*.pt
*.pth
*.onnx
*.h5
*.hdf5
*.pkl
*.joblib
wandb/
runs/
checkpoints/
logs/
tensorboard/
# Agent execution traces
strix_runs/
agent_runs/
# Misc
*.log
*.sqlite
*.db
.directory
*.bak
*.tmp
*.temp
.DS_Store
Thumbs.db
*.schema.graphql
schema.graphql
.opencode/
================================================
FILE: .pre-commit-config.yaml
================================================
repos:
# Ruff for fast linting and formatting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.13
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
name: ruff-lint
- id: ruff-format
name: ruff-format
# MyPy for static type checking
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.16.0
hooks:
- id: mypy
additional_dependencies: [
types-requests,
types-python-dateutil,
pydantic,
fastapi,
]
args: [--install-types, --non-interactive]
# Built-in hooks for basic file checks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-toml
- id: check-merge-conflict
- id: check-added-large-files
- id: debug-statements
- id: check-case-conflict
- id: check-docstring-first
# Security checks with bandit
- repo: https://github.com/PyCQA/bandit
rev: 1.8.3
hooks:
- id: bandit
args: [-c, pyproject.toml]
# Additional Python code quality checks
- repo: https://github.com/asottile/pyupgrade
rev: v3.20.0
hooks:
- id: pyupgrade
args: [--py312-plus]
ci:
autofix_commit_msg: |
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
autofix_prs: true
autoupdate_branch: ""
autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate"
autoupdate_schedule: weekly
skip: []
submodules: false
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Strix
Thank you for your interest in contributing to Strix! This guide will help you get started with development and contributions.
## 🚀 Development Setup
### Prerequisites
- Python 3.12+
- Docker (running)
- Poetry (for dependency management)
- Git
### Local Development
1. **Clone the repository**
```bash
git clone https://github.com/usestrix/strix.git
cd strix
```
2. **Install development dependencies**
```bash
make setup-dev
# or manually:
poetry install --with=dev
poetry run pre-commit install
```
3. **Configure your LLM provider**
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="your-api-key"
```
4. **Run Strix in development mode**
```bash
poetry run strix --target https://example.com
```
## 📚 Contributing Skills
Skills are specialized knowledge packages that enhance agent capabilities. See [strix/skills/README.md](strix/skills/README.md) for detailed guidelines.
### Quick Guide
1. **Choose the right category** (`/vulnerabilities`, `/frameworks`, `/technologies`, etc.)
2. **Create a** `.md` file with your skill content
3. **Include practical examples** - Working payloads, commands, or test cases
4. **Provide validation methods** - How to confirm findings and avoid false positives
5. **Submit via PR** with clear description
## 🔧 Contributing Code
### Pull Request Process
1. **Create an issue first** - Describe the problem or feature
2. **Fork and branch** - Work from the `main` branch
3. **Make your changes** - Follow existing code style
4. **Write/update tests** - Ensure coverage for new features
5. **Run quality checks** - `make check-all` should pass
6. **Submit PR** - Link to issue and provide context
### PR Guidelines
- **Clear description** - Explain what and why
- **Small, focused changes** - One feature/fix per PR
- **Include examples** - Show before/after behavior
- **Update documentation** - If adding features
- **Pass all checks** - Tests, linting, type checking
### Code Style
- Follow PEP 8 with 100-character line limit
- Use type hints for all functions
- Write docstrings for public methods
- Keep functions focused and small
- Use meaningful variable names
## 🐛 Reporting Issues
When reporting bugs, please include:
- Python version and OS
- Strix version
- LLMs being used
- Full error traceback
- Steps to reproduce
- Expected vs actual behavior
## 💡 Feature Requests
We welcome feature ideas! Please:
- Check existing issues first
- Describe the use case clearly
- Explain why it would benefit users
- Consider implementation approach
- Be open to discussion
## 🤝 Community
- **Discord**: [Join our community](https://discord.gg/strix-ai)
- **Issues**: [GitHub Issues](https://github.com/usestrix/strix/issues)
## ✨ Recognition
We value all contributions! Contributors will be:
- Listed in release notes
- Thanked in our Discord
- Added to contributors list (coming soon)
---
**Questions?** Reach out on [Discord](https://discord.gg/strix-ai) or create an issue. We're here to help!
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2025 OmniSecure Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
.PHONY: help install dev-install format lint type-check test test-cov clean pre-commit setup-dev
help:
@echo "Available commands:"
@echo " setup-dev - Install all development dependencies and setup pre-commit"
@echo " install - Install production dependencies"
@echo " dev-install - Install development dependencies"
@echo ""
@echo "Code Quality:"
@echo " format - Format code with ruff"
@echo " lint - Lint code with ruff and pylint"
@echo " type-check - Run type checking with mypy and pyright"
@echo " security - Run security checks with bandit"
@echo " check-all - Run all code quality checks"
@echo ""
@echo "Testing:"
@echo " test - Run tests with pytest"
@echo " test-cov - Run tests with coverage reporting"
@echo ""
@echo "Development:"
@echo " pre-commit - Run pre-commit hooks on all files"
@echo " clean - Clean up cache files and artifacts"
install:
poetry install --only=main
dev-install:
poetry install --with=dev
setup-dev: dev-install
poetry run pre-commit install
@echo "✅ Development environment setup complete!"
@echo "Run 'make check-all' to verify everything works correctly."
format:
@echo "🎨 Formatting code with ruff..."
poetry run ruff format .
@echo "✅ Code formatting complete!"
lint:
@echo "🔍 Linting code with ruff..."
poetry run ruff check . --fix
@echo "📝 Running additional linting with pylint..."
poetry run pylint strix/ --score=no --reports=no
@echo "✅ Linting complete!"
type-check:
@echo "🔍 Type checking with mypy..."
poetry run mypy strix/
@echo "🔍 Type checking with pyright..."
poetry run pyright strix/
@echo "✅ Type checking complete!"
security:
@echo "🔒 Running security checks with bandit..."
poetry run bandit -r strix/ -c pyproject.toml
@echo "✅ Security checks complete!"
check-all: format lint type-check security
@echo "✅ All code quality checks passed!"
test:
@echo "🧪 Running tests..."
poetry run pytest -v
@echo "✅ Tests complete!"
test-cov:
@echo "🧪 Running tests with coverage..."
poetry run pytest -v --cov=strix --cov-report=term-missing --cov-report=html
@echo "✅ Tests with coverage complete!"
@echo "📊 Coverage report generated in htmlcov/"
pre-commit:
@echo "🔧 Running pre-commit hooks..."
poetry run pre-commit run --all-files
@echo "✅ Pre-commit hooks complete!"
clean:
@echo "🧹 Cleaning up cache files..."
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".mypy_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name "htmlcov" -exec rm -rf {} + 2>/dev/null || true
find . -name "*.pyc" -delete 2>/dev/null || true
find . -name ".coverage" -delete 2>/dev/null || true
@echo "✅ Cleanup complete!"
dev: format lint type-check test
@echo "✅ Development cycle complete!"
================================================
FILE: README.md
================================================
<p align="center">
<a href="https://strix.ai/">
<img src="https://github.com/usestrix/.github/raw/main/imgs/cover.png" alt="Strix Banner" width="100%">
</a>
</p>
<div align="center">
# Strix
### Open-source AI hackers to find and fix your app’s vulnerabilities.
<br/>
<a href="https://docs.strix.ai"><img src="https://img.shields.io/badge/Docs-docs.strix.ai-2b9246?style=for-the-badge&logo=gitbook&logoColor=white" alt="Docs"></a>
<a href="https://strix.ai"><img src="https://img.shields.io/badge/Website-strix.ai-f0f0f0?style=for-the-badge&logoColor=000000" alt="Website"></a>
[](https://discord.gg/strix-ai)
<a href="https://deepwiki.com/usestrix/strix"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
<a href="https://github.com/usestrix/strix"><img src="https://img.shields.io/github/stars/usestrix/strix?style=flat-square" alt="GitHub Stars"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-3b82f6?style=flat-square" alt="License"></a>
<a href="https://pypi.org/project/strix-agent/"><img src="https://img.shields.io/pypi/v/strix-agent?style=flat-square" alt="PyPI Version"></a>
<a href="https://discord.gg/strix-ai"><img src="https://github.com/usestrix/.github/raw/main/imgs/Discord.png" height="40" alt="Join Discord"></a>
<a href="https://x.com/strix_ai"><img src="https://github.com/usestrix/.github/raw/main/imgs/X.png" height="40" alt="Follow on X"></a>
<a href="https://trendshift.io/repositories/15362" target="_blank"><img src="https://trendshift.io/api/badge/repositories/15362" alt="usestrix/strix | Trendshift" width="250" height="55"/></a>
</div>
> [!TIP]
> **New!** Strix integrates seamlessly with GitHub Actions and CI/CD pipelines. Automatically scan for vulnerabilities on every pull request and block insecure code before it reaches production!
---
## Strix Overview
Strix are autonomous AI agents that act just like real hackers - they run your code dynamically, find vulnerabilities, and validate them through actual proof-of-concepts. Built for developers and security teams who need fast, accurate security testing without the overhead of manual pentesting or the false positives of static analysis tools.
**Key Capabilities:**
- **Full hacker toolkit** out of the box
- **Teams of agents** that collaborate and scale
- **Real validation** with PoCs, not false positives
- **Developer‑first** CLI with actionable reports
- **Auto‑fix & reporting** to accelerate remediation
<br>
<div align="center">
<a href="https://strix.ai">
<img src=".github/screenshot.png" alt="Strix Demo" width="1000" style="border-radius: 16px;">
</a>
</div>
## Use Cases
- **Application Security Testing** - Detect and validate critical vulnerabilities in your applications
- **Rapid Penetration Testing** - Get penetration tests done in hours, not weeks, with compliance reports
- **Bug Bounty Automation** - Automate bug bounty research and generate PoCs for faster reporting
- **CI/CD Integration** - Run tests in CI/CD to block vulnerabilities before reaching production
## 🚀 Quick Start
**Prerequisites:**
- Docker (running)
- An LLM API key:
- Any [supported provider](https://docs.strix.ai/llm-providers/overview) (OpenAI, Anthropic, Google, etc.)
- Or [Strix Router](https://models.strix.ai) — single API key for multiple providers
### Installation & First Scan
```bash
# Install Strix
curl -sSL https://strix.ai/install | bash
# Configure your AI provider
export STRIX_LLM="openai/gpt-5" # or "strix/gpt-5" via Strix Router (https://models.strix.ai)
export LLM_API_KEY="your-api-key"
# Run your first security assessment
strix --target ./app-directory
```
> [!NOTE]
> First run automatically pulls the sandbox Docker image. Results are saved to `strix_runs/<run-name>`
---
## ☁️ Strix Platform
Try the Strix full-stack security platform at **[app.strix.ai](https://app.strix.ai)** — sign up for free, connect your repos and domains, and launch a pentest in minutes.
- **Validated findings with PoCs** and reproduction steps
- **One-click autofix** as ready-to-merge pull requests
- **Continuous monitoring** across code, cloud, and infrastructure
- **Integrations** with GitHub, Slack, Jira, Linear, and CI/CD pipelines
- **Continuous learning** that builds on past findings and remediations
[**Start your first pentest →**](https://app.strix.ai)
---
## ✨ Features
### Agentic Security Tools
Strix agents come equipped with a comprehensive security testing toolkit:
- **Full HTTP Proxy** - Full request/response manipulation and analysis
- **Browser Automation** - Multi-tab browser for testing of XSS, CSRF, auth flows
- **Terminal Environments** - Interactive shells for command execution and testing
- **Python Runtime** - Custom exploit development and validation
- **Reconnaissance** - Automated OSINT and attack surface mapping
- **Code Analysis** - Static and dynamic analysis capabilities
- **Knowledge Management** - Structured findings and attack documentation
### Comprehensive Vulnerability Detection
Strix can identify and validate a wide range of security vulnerabilities:
- **Access Control** - IDOR, privilege escalation, auth bypass
- **Injection Attacks** - SQL, NoSQL, command injection
- **Server-Side** - SSRF, XXE, deserialization flaws
- **Client-Side** - XSS, prototype pollution, DOM vulnerabilities
- **Business Logic** - Race conditions, workflow manipulation
- **Authentication** - JWT vulnerabilities, session management
- **Infrastructure** - Misconfigurations, exposed services
### Graph of Agents
Advanced multi-agent orchestration for comprehensive security testing:
- **Distributed Workflows** - Specialized agents for different attacks and assets
- **Scalable Testing** - Parallel execution for fast comprehensive coverage
- **Dynamic Coordination** - Agents collaborate and share discoveries
---
## Usage Examples
### Basic Usage
```bash
# Scan a local codebase
strix --target ./app-directory
# Security review of a GitHub repository
strix --target https://github.com/org/repo
# Black-box web application assessment
strix --target https://your-app.com
```
### Advanced Testing Scenarios
```bash
# Grey-box authenticated testing
strix --target https://your-app.com --instruction "Perform authenticated testing using credentials: user:pass"
# Multi-target testing (source code + deployed app)
strix -t https://github.com/org/app -t https://your-app.com
# Focused testing with custom instructions
strix --target api.your-app.com --instruction "Focus on business logic flaws and IDOR vulnerabilities"
# Provide detailed instructions through file (e.g., rules of engagement, scope, exclusions)
strix --target api.your-app.com --instruction-file ./instruction.md
```
### Headless Mode
Run Strix programmatically without interactive UI using the `-n/--non-interactive` flag—perfect for servers and automated jobs. The CLI prints real-time vulnerability findings, and the final report before exiting. Exits with non-zero code when vulnerabilities are found.
```bash
strix -n --target https://your-app.com
```
### CI/CD (GitHub Actions)
Strix can be added to your pipeline to run a security test on pull requests with a lightweight GitHub Actions workflow:
```yaml
name: strix-penetration-test
on:
pull_request:
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Strix
run: curl -sSL https://strix.ai/install | bash
- name: Run Strix
env:
STRIX_LLM: ${{ secrets.STRIX_LLM }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
run: strix -n -t ./ --scan-mode quick
```
### Configuration
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="your-api-key"
# Optional
export LLM_API_BASE="your-api-base-url" # if using a local model, e.g. Ollama, LMStudio
export PERPLEXITY_API_KEY="your-api-key" # for search capabilities
export STRIX_REASONING_EFFORT="high" # control thinking effort (default: high, quick scan: medium)
```
> [!NOTE]
> Strix automatically saves your configuration to `~/.strix/cli-config.json`, so you don't have to re-enter it on every run.
**Recommended models for best results:**
- [OpenAI GPT-5](https://openai.com/api/) — `openai/gpt-5`
- [Anthropic Claude Sonnet 4.6](https://claude.com/platform/api) — `anthropic/claude-sonnet-4-6`
- [Google Gemini 3 Pro Preview](https://cloud.google.com/vertex-ai) — `vertex_ai/gemini-3-pro-preview`
See the [LLM Providers documentation](https://docs.strix.ai/llm-providers/overview) for all supported providers including Vertex AI, Bedrock, Azure, and local models.
## Enterprise
Get the same Strix experience with [enterprise-grade](https://strix.ai/demo) controls: SSO (SAML/OIDC), custom compliance reports, dedicated support & SLA, custom deployment options (VPC/self-hosted), BYOK model support, and tailored agents optimized for your environment. [Learn more](https://strix.ai/demo).
## Documentation
Full documentation is available at **[docs.strix.ai](https://docs.strix.ai)** — including detailed guides for usage, CI/CD integrations, skills, and advanced configuration.
## Contributing
We welcome contributions of code, docs, and new skills - check out our [Contributing Guide](https://docs.strix.ai/contributing) to get started or open a [pull request](https://github.com/usestrix/strix/pulls)/[issue](https://github.com/usestrix/strix/issues).
## Join Our Community
Have questions? Found a bug? Want to contribute? **[Join our Discord!](https://discord.gg/strix-ai)**
## Support the Project
**Love Strix?** Give us a ⭐ on GitHub!
## Acknowledgements
Strix builds on the incredible work of open-source projects like [LiteLLM](https://github.com/BerriAI/litellm), [Caido](https://github.com/caido/caido), [Nuclei](https://github.com/projectdiscovery/nuclei), [Playwright](https://github.com/microsoft/playwright), and [Textual](https://github.com/Textualize/textual). Huge thanks to their maintainers!
> [!WARNING]
> Only test apps you own or have permission to test. You are responsible for using Strix ethically and legally.
</div>
================================================
FILE: benchmarks/README.md
================================================
# Benchmarks
We use security benchmarks to track Strix's capabilities and improvements over time. We plan to add more benchmarks, both existing ones and our own, to help the community evaluate and compare security agents.
## Full Details
For the complete benchmark results, evaluation scripts, and run data, see the [usestrix/benchmarks](https://github.com/usestrix/benchmarks) repository.
> [!NOTE]
> We are actively adding more benchmarks to our evaluation suite.
## Results
| Benchmark | Challenges | Success Rate |
|-----------|------------|--------------|
| [XBEN](https://github.com/usestrix/benchmarks/tree/main/XBEN) | 104 | **96%** |
### XBEN
The [XBOW benchmark](https://github.com/usestrix/benchmarks/tree/main/XBEN) is a set of 104 web security challenges designed to evaluate autonomous penetration testing agents. Each challenge follows a CTF format where the agent must discover and exploit vulnerabilities to extract a hidden flag.
Strix `v0.4.0` achieved a **96% success rate** (100/104 challenges) in black-box mode.
```mermaid
%%{init: {'theme': 'base', 'themeVariables': { 'pie1': '#3b82f6', 'pie2': '#1e3a5f', 'pieTitleTextColor': '#ffffff', 'pieSectionTextColor': '#ffffff', 'pieLegendTextColor': '#ffffff'}}}%%
pie title Challenge Outcomes (104 Total)
"Solved" : 100
"Unsolved" : 4
```
**Performance by Difficulty:**
| Difficulty | Solved | Success Rate |
|------------|--------|--------------|
| Level 1 (Easy) | 45/45 | 100% |
| Level 2 (Medium) | 49/51 | 96% |
| Level 3 (Hard) | 6/8 | 75% |
**Resource Usage:**
- Average solve time: ~19 minutes
- Total cost: ~$337 for 100 challenges
================================================
FILE: containers/Dockerfile
================================================
FROM kalilinux/kali-rolling:latest
LABEL description="AI Agent Penetration Testing Environment with Comprehensive Automated Tools"
RUN apt-get update && \
apt-get install -y kali-archive-keyring sudo && \
apt-get update && \
apt-get upgrade -y
RUN useradd -m -s /bin/bash pentester && \
usermod -aG sudo pentester && \
echo "pentester ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
touch /home/pentester/.hushlogin
RUN mkdir -p /home/pentester/configs \
/home/pentester/wordlists \
/home/pentester/output \
/home/pentester/scripts \
/home/pentester/tools \
/app/runtime \
/app/tools \
/app/certs && \
chown -R pentester:pentester /app/certs /home/pentester/tools
RUN apt-get update && \
apt-get install -y --no-install-recommends \
wget curl git vim nano unzip tar \
apt-transport-https ca-certificates gnupg lsb-release \
build-essential software-properties-common \
gcc libc6-dev pkg-config libpcap-dev libssl-dev \
python3 python3-pip python3-dev python3-venv python3-setuptools \
golang-go \
net-tools dnsutils whois \
jq parallel ripgrep grep \
less man-db procps htop \
iproute2 iputils-ping netcat-traditional \
nmap ncat ndiff \
sqlmap nuclei subfinder naabu ffuf \
nodejs npm pipx \
libcap2-bin \
gdb \
tmux \
libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libatspi2.0-0 \
libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libxkbcommon0 libpango-1.0-0 libcairo2 libasound2t64 \
fonts-unifont fonts-noto-color-emoji fonts-freefont-ttf fonts-dejavu-core ttf-bitstream-vera \
libnss3-tools
RUN setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip $(which nmap)
USER pentester
RUN openssl ecparam -name prime256v1 -genkey -noout -out /app/certs/ca.key && \
openssl req -x509 -new -key /app/certs/ca.key \
-out /app/certs/ca.crt \
-days 3650 \
-subj "/C=US/ST=CA/O=Security Testing/CN=Testing Root CA" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,digitalSignature,keyEncipherment,keyCertSign" && \
openssl pkcs12 -export \
-out /app/certs/ca.p12 \
-inkey /app/certs/ca.key \
-in /app/certs/ca.crt \
-passout pass:"" \
-name "Testing Root CA" && \
chmod 644 /app/certs/ca.crt && \
chmod 600 /app/certs/ca.key && \
chmod 600 /app/certs/ca.p12
USER root
RUN cp /app/certs/ca.crt /usr/local/share/ca-certificates/ca.crt && \
update-ca-certificates
RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/opt/poetry python3 - && \
ln -s /opt/poetry/bin/poetry /usr/local/bin/poetry && \
chmod +x /usr/local/bin/poetry && \
python3 -m venv /app/venv && \
chown -R pentester:pentester /app/venv /opt/poetry
USER pentester
WORKDIR /tmp
RUN go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest && \
go install -v github.com/projectdiscovery/katana/cmd/katana@latest && \
go install -v github.com/projectdiscovery/cvemap/cmd/vulnx@latest && \
go install -v github.com/jaeles-project/gospider@latest && \
go install -v github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest
RUN nuclei -update-templates
RUN pipx install arjun && \
pipx install dirsearch && \
pipx inject dirsearch setuptools && \
pipx install wafw00f
ENV NPM_CONFIG_PREFIX=/home/pentester/.npm-global
RUN mkdir -p /home/pentester/.npm-global
RUN npm install -g retire@latest && \
npm install -g eslint@latest && \
npm install -g js-beautify@latest
WORKDIR /home/pentester/tools
RUN git clone https://github.com/aravind0x7/JS-Snooper.git && \
chmod +x JS-Snooper/js_snooper.sh && \
git clone https://github.com/xchopath/jsniper.sh.git && \
chmod +x jsniper.sh/jsniper.sh && \
git clone https://github.com/ticarpi/jwt_tool.git && \
chmod +x jwt_tool/jwt_tool.py
USER root
RUN curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin
RUN apt-get update && apt-get install -y zaproxy
RUN curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
RUN apt-get install -y wapiti
USER pentester
RUN pipx install semgrep && \
pipx install bandit
RUN npm install -g jshint
USER root
RUN apt-get autoremove -y && \
apt-get autoclean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENV PATH="/home/pentester/go/bin:/home/pentester/.local/bin:/home/pentester/.npm-global/bin:/app/venv/bin:$PATH"
ENV VIRTUAL_ENV="/app/venv"
ENV POETRY_HOME="/opt/poetry"
WORKDIR /app
RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "x86_64" ]; then \
CAIDO_ARCH="x86_64"; \
elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \
CAIDO_ARCH="aarch64"; \
else \
echo "Unsupported architecture: $ARCH" && exit 1; \
fi && \
wget -O caido-cli.tar.gz https://caido.download/releases/v0.48.0/caido-cli-v0.48.0-linux-${CAIDO_ARCH}.tar.gz && \
tar -xzf caido-cli.tar.gz && \
chmod +x caido-cli && \
rm caido-cli.tar.gz && \
mv caido-cli /usr/local/bin/
ENV STRIX_SANDBOX_MODE=true
ENV PYTHONPATH=/app
ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
RUN mkdir -p /workspace && chown -R pentester:pentester /workspace /app
COPY pyproject.toml poetry.lock ./
USER pentester
RUN poetry install --no-root --without dev --extras sandbox
RUN poetry run playwright install chromium
RUN /app/venv/bin/pip install -r /home/pentester/tools/jwt_tool/requirements.txt && \
ln -s /home/pentester/tools/jwt_tool/jwt_tool.py /home/pentester/.local/bin/jwt_tool
RUN echo "# Sandbox Environment" > README.md
COPY strix/__init__.py strix/
COPY strix/config/ /app/strix/config/
COPY strix/utils/ /app/strix/utils/
COPY strix/telemetry/ /app/strix/telemetry/
COPY strix/runtime/tool_server.py strix/runtime/__init__.py strix/runtime/runtime.py /app/strix/runtime/
COPY strix/tools/__init__.py strix/tools/registry.py strix/tools/executor.py strix/tools/argument_parser.py strix/tools/context.py /app/strix/tools/
COPY strix/tools/browser/ /app/strix/tools/browser/
COPY strix/tools/file_edit/ /app/strix/tools/file_edit/
COPY strix/tools/notes/ /app/strix/tools/notes/
COPY strix/tools/python/ /app/strix/tools/python/
COPY strix/tools/terminal/ /app/strix/tools/terminal/
COPY strix/tools/proxy/ /app/strix/tools/proxy/
RUN echo 'export PATH="/home/pentester/go/bin:/home/pentester/.local/bin:/home/pentester/.npm-global/bin:$PATH"' >> /home/pentester/.bashrc && \
echo 'export PATH="/home/pentester/go/bin:/home/pentester/.local/bin:/home/pentester/.npm-global/bin:$PATH"' >> /home/pentester/.profile
USER root
COPY containers/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
USER pentester
WORKDIR /workspace
ENTRYPOINT ["docker-entrypoint.sh"]
================================================
FILE: containers/docker-entrypoint.sh
================================================
#!/bin/bash
set -e
CAIDO_PORT=48080
CAIDO_LOG="/tmp/caido_startup.log"
if [ ! -f /app/certs/ca.p12 ]; then
echo "ERROR: CA certificate file /app/certs/ca.p12 not found."
exit 1
fi
caido-cli --listen 0.0.0.0:${CAIDO_PORT} \
--allow-guests \
--no-logging \
--no-open \
--import-ca-cert /app/certs/ca.p12 \
--import-ca-cert-pass "" > "$CAIDO_LOG" 2>&1 &
CAIDO_PID=$!
echo "Started Caido with PID $CAIDO_PID on port $CAIDO_PORT"
echo "Waiting for Caido API to be ready..."
CAIDO_READY=false
for i in {1..30}; do
if ! kill -0 $CAIDO_PID 2>/dev/null; then
echo "ERROR: Caido process died while waiting for API (iteration $i)."
echo "=== Caido log ==="
cat "$CAIDO_LOG" 2>/dev/null || echo "(no log available)"
exit 1
fi
if curl -s -o /dev/null -w "%{http_code}" http://localhost:${CAIDO_PORT}/graphql/ | grep -qE "^(200|400)$"; then
echo "Caido API is ready (attempt $i)."
CAIDO_READY=true
break
fi
sleep 1
done
if [ "$CAIDO_READY" = false ]; then
echo "ERROR: Caido API did not become ready within 30 seconds."
echo "Caido process status: $(kill -0 $CAIDO_PID 2>&1 && echo 'running' || echo 'dead')"
echo "=== Caido log ==="
cat "$CAIDO_LOG" 2>/dev/null || echo "(no log available)"
exit 1
fi
sleep 2
echo "Fetching API token..."
TOKEN=""
for attempt in 1 2 3 4 5; do
RESPONSE=$(curl -sL -X POST \
-H "Content-Type: application/json" \
-d '{"query":"mutation LoginAsGuest { loginAsGuest { token { accessToken } } }"}' \
http://localhost:${CAIDO_PORT}/graphql)
TOKEN=$(echo "$RESPONSE" | jq -r '.data.loginAsGuest.token.accessToken // empty')
if [ -n "$TOKEN" ] && [ "$TOKEN" != "null" ]; then
echo "Successfully obtained API token (attempt $attempt)."
break
fi
echo "Token fetch attempt $attempt failed: $RESPONSE"
sleep $((attempt * 2))
done
if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then
echo "ERROR: Failed to get API token from Caido after 5 attempts."
echo "=== Caido log ==="
cat "$CAIDO_LOG" 2>/dev/null || echo "(no log available)"
exit 1
fi
export CAIDO_API_TOKEN=$TOKEN
echo "Caido API token has been set."
echo "Creating a new Caido project..."
CREATE_PROJECT_RESPONSE=$(curl -sL -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"mutation CreateProject { createProject(input: {name: \"sandbox\", temporary: true}) { project { id } } }"}' \
http://localhost:${CAIDO_PORT}/graphql)
PROJECT_ID=$(echo $CREATE_PROJECT_RESPONSE | jq -r '.data.createProject.project.id')
if [ -z "$PROJECT_ID" ] || [ "$PROJECT_ID" == "null" ]; then
echo "Failed to create Caido project."
echo "Response: $CREATE_PROJECT_RESPONSE"
exit 1
fi
echo "Caido project created with ID: $PROJECT_ID"
echo "Selecting Caido project..."
SELECT_RESPONSE=$(curl -sL -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"mutation SelectProject { selectProject(id: \"'$PROJECT_ID'\") { currentProject { project { id } } } }"}' \
http://localhost:${CAIDO_PORT}/graphql)
SELECTED_ID=$(echo $SELECT_RESPONSE | jq -r '.data.selectProject.currentProject.project.id')
if [ "$SELECTED_ID" != "$PROJECT_ID" ]; then
echo "Failed to select Caido project."
echo "Response: $SELECT_RESPONSE"
exit 1
fi
echo "✅ Caido project selected successfully."
echo "Configuring system-wide proxy settings..."
cat << EOF | sudo tee /etc/profile.d/proxy.sh
export http_proxy=http://127.0.0.1:${CAIDO_PORT}
export https_proxy=http://127.0.0.1:${CAIDO_PORT}
export HTTP_PROXY=http://127.0.0.1:${CAIDO_PORT}
export HTTPS_PROXY=http://127.0.0.1:${CAIDO_PORT}
export ALL_PROXY=http://127.0.0.1:${CAIDO_PORT}
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export CAIDO_API_TOKEN=${TOKEN}
EOF
cat << EOF | sudo tee /etc/environment
http_proxy=http://127.0.0.1:${CAIDO_PORT}
https_proxy=http://127.0.0.1:${CAIDO_PORT}
HTTP_PROXY=http://127.0.0.1:${CAIDO_PORT}
HTTPS_PROXY=http://127.0.0.1:${CAIDO_PORT}
ALL_PROXY=http://127.0.0.1:${CAIDO_PORT}
CAIDO_API_TOKEN=${TOKEN}
EOF
cat << EOF | sudo tee /etc/wgetrc
use_proxy=yes
http_proxy=http://127.0.0.1:${CAIDO_PORT}
https_proxy=http://127.0.0.1:${CAIDO_PORT}
EOF
echo "source /etc/profile.d/proxy.sh" >> ~/.bashrc
echo "source /etc/profile.d/proxy.sh" >> ~/.zshrc
source /etc/profile.d/proxy.sh
echo "✅ System-wide proxy configuration complete"
echo "Adding CA to browser trust store..."
sudo -u pentester mkdir -p /home/pentester/.pki/nssdb
sudo -u pentester certutil -N -d sql:/home/pentester/.pki/nssdb --empty-password
sudo -u pentester certutil -A -n "Testing Root CA" -t "C,," -i /app/certs/ca.crt -d sql:/home/pentester/.pki/nssdb
echo "✅ CA added to browser trust store"
echo "Starting tool server..."
cd /app
export PYTHONPATH=/app
export STRIX_SANDBOX_MODE=true
export POETRY_VIRTUALENVS_CREATE=false
export TOOL_SERVER_TIMEOUT="${STRIX_SANDBOX_EXECUTION_TIMEOUT:-120}"
TOOL_SERVER_LOG="/tmp/tool_server.log"
sudo -E -u pentester \
poetry run python -m strix.runtime.tool_server \
--token="$TOOL_SERVER_TOKEN" \
--host=0.0.0.0 \
--port="$TOOL_SERVER_PORT" \
--timeout="$TOOL_SERVER_TIMEOUT" > "$TOOL_SERVER_LOG" 2>&1 &
for i in {1..10}; do
if curl -s "http://127.0.0.1:$TOOL_SERVER_PORT/health" | grep -q '"status":"healthy"'; then
echo "✅ Tool server healthy on port $TOOL_SERVER_PORT"
break
fi
if [ $i -eq 10 ]; then
echo "ERROR: Tool server failed to become healthy"
echo "=== Tool server log ==="
cat "$TOOL_SERVER_LOG" 2>/dev/null || echo "(no log)"
exit 1
fi
sleep 1
done
echo "✅ Container ready"
cd /workspace
exec "$@"
================================================
FILE: docs/README.md
================================================
# Strix Documentation
Documentation source files for Strix, powered by [Mintlify](https://mintlify.com).
## Local Preview
```bash
npm i -g mintlify
cd docs && mintlify dev
```
================================================
FILE: docs/advanced/configuration.mdx
================================================
---
title: "Configuration"
description: "Environment variables for Strix"
---
Configure Strix using environment variables or a config file.
## LLM Configuration
<ParamField path="STRIX_LLM" type="string" required>
Model name in LiteLLM format (e.g., `openai/gpt-5`, `anthropic/claude-sonnet-4-6`).
</ParamField>
<ParamField path="LLM_API_KEY" type="string">
API key for your LLM provider. Not required for local models or cloud provider auth (Vertex AI, AWS Bedrock).
</ParamField>
<ParamField path="LLM_API_BASE" type="string">
Custom API base URL. Also accepts `OPENAI_API_BASE`, `LITELLM_BASE_URL`, or `OLLAMA_API_BASE`.
</ParamField>
<ParamField path="LLM_TIMEOUT" default="300" type="integer">
Request timeout in seconds for LLM calls.
</ParamField>
<ParamField path="STRIX_LLM_MAX_RETRIES" default="5" type="integer">
Maximum number of retries for LLM API calls on transient failures.
</ParamField>
<ParamField path="STRIX_REASONING_EFFORT" default="high" type="string">
Control thinking effort for reasoning models. Valid values: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`. Defaults to `medium` for quick scan mode.
</ParamField>
<ParamField path="STRIX_MEMORY_COMPRESSOR_TIMEOUT" default="30" type="integer">
Timeout in seconds for memory compression operations (context summarization).
</ParamField>
## Optional Features
<ParamField path="PERPLEXITY_API_KEY" type="string">
API key for Perplexity AI. Enables real-time web search during scans for OSINT and vulnerability research.
</ParamField>
<ParamField path="STRIX_DISABLE_BROWSER" default="false" type="boolean">
Disable browser automation tools.
</ParamField>
<ParamField path="STRIX_TELEMETRY" default="1" type="string">
Global telemetry default toggle. Set to `0`, `false`, `no`, or `off` to disable both PostHog and OTEL unless overridden by per-channel flags below.
</ParamField>
<ParamField path="STRIX_OTEL_TELEMETRY" type="string">
Enable/disable OpenTelemetry run observability independently. When unset, falls back to `STRIX_TELEMETRY`.
</ParamField>
<ParamField path="STRIX_POSTHOG_TELEMETRY" type="string">
Enable/disable PostHog product telemetry independently. When unset, falls back to `STRIX_TELEMETRY`.
</ParamField>
<ParamField path="TRACELOOP_BASE_URL" type="string">
OTLP/Traceloop base URL for remote OpenTelemetry export. If unset, Strix keeps traces local only.
</ParamField>
<ParamField path="TRACELOOP_API_KEY" type="string">
API key used for remote trace export. Remote export is enabled only when both `TRACELOOP_BASE_URL` and `TRACELOOP_API_KEY` are set.
</ParamField>
<ParamField path="TRACELOOP_HEADERS" type="string">
Optional custom OTEL headers (JSON object or `key=value,key2=value2`). Useful for Langfuse or custom/self-hosted OTLP gateways.
</ParamField>
When remote OTEL vars are not set, Strix still writes complete run telemetry locally to:
```bash
strix_runs/<run_name>/events.jsonl
```
When remote vars are set, Strix dual-writes telemetry to both local JSONL and the remote OTEL endpoint.
## Docker Configuration
<ParamField path="STRIX_IMAGE" default="ghcr.io/usestrix/strix-sandbox:0.1.12" type="string">
Docker image to use for the sandbox container.
</ParamField>
<ParamField path="DOCKER_HOST" type="string">
Docker daemon socket path. Use for remote Docker hosts or custom configurations.
</ParamField>
<ParamField path="STRIX_RUNTIME_BACKEND" default="docker" type="string">
Runtime backend for the sandbox environment.
</ParamField>
## Sandbox Configuration
<ParamField path="STRIX_SANDBOX_EXECUTION_TIMEOUT" default="120" type="integer">
Maximum execution time in seconds for sandbox operations.
</ParamField>
<ParamField path="STRIX_SANDBOX_CONNECT_TIMEOUT" default="10" type="integer">
Timeout in seconds for connecting to the sandbox container.
</ParamField>
## Config File
Strix stores configuration in `~/.strix/cli-config.json`. You can also specify a custom config file:
```bash
strix --target ./app --config /path/to/config.json
```
**Config file format:**
```json
{
"env": {
"STRIX_LLM": "openai/gpt-5",
"LLM_API_KEY": "sk-...",
"STRIX_REASONING_EFFORT": "high"
}
}
```
## Example Setup
```bash
# Required
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="sk-..."
# Optional: Enable web search
export PERPLEXITY_API_KEY="pplx-..."
# Optional: Custom timeouts
export LLM_TIMEOUT="600"
export STRIX_SANDBOX_EXECUTION_TIMEOUT="300"
```
================================================
FILE: docs/advanced/skills.mdx
================================================
---
title: "Skills"
description: "Specialized knowledge packages that enhance agent capabilities"
---
Skills are structured knowledge packages that give Strix agents deep expertise in specific vulnerability types, technologies, and testing methodologies.
## The Idea
LLMs have broad but shallow security knowledge. They know _about_ SQL injection, but lack the nuanced techniques that experienced pentesters use—parser quirks, bypass methods, validation tricks, and chain attacks.
Skills inject this deep, specialized knowledge directly into the agent's context, transforming it from a generalist into a specialist for the task at hand.
## How They Work
When Strix spawns an agent for a specific task, it selects up to 5 relevant skills based on the context:
```python
# Agent created for JWT testing automatically loads relevant skills
create_agent(
task="Test authentication mechanisms",
skills=["authentication_jwt", "business_logic"]
)
```
The skills are injected into the agent's system prompt, giving it access to:
- **Advanced techniques** — Non-obvious methods beyond standard testing
- **Working payloads** — Practical examples with variations
- **Validation methods** — How to confirm findings and avoid false positives
## Skill Categories
### Vulnerabilities
Core vulnerability classes with deep exploitation techniques.
| Skill | Coverage |
| ------------------------------------- | ------------------------------------------------------ |
| `authentication_jwt` | JWT attacks, algorithm confusion, claim tampering |
| `idor` | Object reference attacks, horizontal/vertical access |
| `sql_injection` | SQL injection variants, WAF bypasses, blind techniques |
| `xss` | XSS types, filter bypasses, DOM exploitation |
| `ssrf` | Server-side request forgery, protocol handlers |
| `csrf` | Cross-site request forgery, token bypasses |
| `xxe` | XML external entities, OOB exfiltration |
| `rce` | Remote code execution vectors |
| `business_logic` | Logic flaws, state manipulation, race conditions |
| `race_conditions` | TOCTOU, parallel request attacks |
| `path_traversal_lfi_rfi` | File inclusion, path traversal |
| `open_redirect` | Redirect bypasses, URL parsing tricks |
| `mass_assignment` | Attribute injection, hidden parameter pollution |
| `insecure_file_uploads` | Upload bypasses, extension tricks |
| `information_disclosure` | Data leakage, error-based enumeration |
| `subdomain_takeover` | Dangling DNS, cloud resource claims |
| `broken_function_level_authorization` | Privilege escalation, role bypasses |
### Frameworks
Framework-specific testing patterns.
| Skill | Coverage |
| --------- | -------------------------------------------- |
| `fastapi` | FastAPI security patterns, Pydantic bypasses |
| `nextjs` | Next.js SSR/SSG issues, API route security |
### Technologies
Third-party service and platform security.
| Skill | Coverage |
| -------------------- | ---------------------------------- |
| `supabase` | Supabase RLS bypasses, auth issues |
| `firebase_firestore` | Firestore rules, Firebase auth |
### Protocols
Protocol-specific testing techniques.
| Skill | Coverage |
| --------- | ------------------------------------------------ |
| `graphql` | GraphQL introspection, batching, resolver issues |
### Tooling
Sandbox CLI playbooks for core recon and scanning tools.
| Skill | Coverage |
| ----------- | ------------------------------------------------------- |
| `nmap` | Port/service scan syntax and high-signal scan patterns |
| `nuclei` | Template selection, severity filtering, and rate tuning |
| `httpx` | HTTP probing and fingerprint output patterns |
| `ffuf` | Wordlist fuzzing, matcher/filter strategy, recursion |
| `subfinder` | Passive subdomain enumeration and source control |
| `naabu` | Fast port scanning with explicit rate/verify controls |
| `katana` | Crawl depth/JS/known-files behavior and pitfalls |
| `sqlmap` | SQLi workflow for enumeration and controlled extraction |
## Skill Structure
Each skill is a Markdown file with YAML frontmatter for metadata:
```markdown
---
name: skill_name
description: Brief description of the skill's coverage
---
# Skill Title
Key insight about this vulnerability or technique.
## Attack Surface
What this skill covers and where to look.
## Methodology
Step-by-step testing approach.
## Techniques
How to discover and exploit the vulnerability.
## Bypass Methods
How to bypass common protections.
## Validation
How to confirm findings and avoid false positives.
```
## Contributing Skills
Community contributions are welcome. Create a `.md` file in the appropriate category with YAML frontmatter (`name` and `description` fields). Good skills include:
1. **Real-world techniques** — Methods that work in practice
2. **Practical payloads** — Working examples with variations
3. **Validation steps** — How to confirm without false positives
4. **Context awareness** — Version/environment-specific behavior
================================================
FILE: docs/cloud/overview.mdx
================================================
---
title: "Introduction"
description: "Managed security testing without local setup"
---
Skip the setup. Run Strix in the cloud at [app.strix.ai](https://app.strix.ai).
## Features
<CardGroup cols={2}>
<Card title="No Setup Required" icon="cloud">
No Docker, API keys, or local installation needed.
</Card>
<Card title="Full Reports" icon="file-lines">
Detailed findings with remediation guidance.
</Card>
<Card title="Team Dashboards" icon="users">
Track vulnerabilities and fixes over time.
</Card>
<Card title="GitHub Integration" icon="github">
Automatic scans on pull requests.
</Card>
</CardGroup>
## What You Get
- **Penetration test reports** — Validated findings with PoCs
- **Shareable dashboards** — Collaborate with your team
- **CI/CD integration** — Block risky changes automatically
- **Continuous monitoring** — Catch new vulnerabilities quickly
## Getting Started
1. Sign up at [app.strix.ai](https://app.strix.ai)
2. Connect your repository or enter a target URL
3. Launch your first scan
<Card title="Try Strix Cloud" icon="rocket" href="https://app.strix.ai">
Run your first pentest in minutes.
</Card>
================================================
FILE: docs/contributing.mdx
================================================
---
title: "Contributing"
description: "Contribute to Strix development"
---
## Development Setup
### Prerequisites
- Python 3.12+
- Docker (running)
- Poetry
- Git
### Local Development
<Steps>
<Step title="Clone the repository">
```bash
git clone https://github.com/usestrix/strix.git
cd strix
```
</Step>
<Step title="Install dependencies">
```bash
make setup-dev
# or manually:
poetry install --with=dev
poetry run pre-commit install
```
</Step>
<Step title="Configure LLM">
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="your-api-key"
```
</Step>
<Step title="Run Strix">
```bash
poetry run strix --target https://example.com
```
</Step>
</Steps>
## Contributing Skills
Skills are specialized knowledge packages that enhance agent capabilities. They live in `strix/skills/`
### Creating a Skill
1. Choose the right category
2. Create a `.md` file with YAML frontmatter (`name` and `description` fields)
3. Include practical examples—working payloads, commands, test cases
4. Provide validation methods to confirm findings
5. Submit via PR
## Contributing Code
### Pull Request Process
1. **Create an issue first** — Describe the problem or feature
2. **Fork and branch** — Work from `main`
3. **Make changes** — Follow existing code style
4. **Write tests** — Ensure coverage for new features
5. **Run checks** — `make check-all` should pass
6. **Submit PR** — Link to issue and provide context
### Code Style
- PEP 8 with 100-character line limit
- Type hints for all functions
- Docstrings for public methods
- Small, focused functions
- Meaningful variable names
## Reporting Issues
Include:
- Python version and OS
- Strix version (`strix --version`)
- LLM being used
- Full error traceback
- Steps to reproduce
## Community
<CardGroup cols={2}>
<Card title="Discord" icon="discord" href="https://discord.gg/strix-ai">
Join the community for help and discussion.
</Card>
<Card title="GitHub Issues" icon="github" href="https://github.com/usestrix/strix/issues">
Report bugs and request features.
</Card>
</CardGroup>
================================================
FILE: docs/docs.json
================================================
{
"$schema": "https://mintlify.com/docs.json",
"theme": "maple",
"name": "Strix",
"colors": {
"primary": "#000000",
"light": "#ffffff",
"dark": "#000000"
},
"favicon": "/images/favicon-48.ico",
"navigation": {
"tabs": [
{
"tab": "Documentation",
"groups": [
{
"group": "Getting Started",
"pages": [
"index",
"quickstart"
]
},
{
"group": "Usage",
"pages": [
"usage/cli",
"usage/scan-modes",
"usage/instructions"
]
},
{
"group": "LLM Providers",
"pages": [
"llm-providers/overview",
"llm-providers/models",
"llm-providers/openai",
"llm-providers/anthropic",
"llm-providers/openrouter",
"llm-providers/vertex",
"llm-providers/bedrock",
"llm-providers/azure",
"llm-providers/local"
]
},
{
"group": "Integrations",
"pages": [
"integrations/github-actions",
"integrations/ci-cd"
]
},
{
"group": "Tools",
"pages": [
"tools/overview",
"tools/browser",
"tools/proxy",
"tools/terminal",
"tools/sandbox"
]
},
{
"group": "Advanced",
"pages": [
"advanced/configuration",
"advanced/skills",
"contributing"
]
}
]
},
{
"tab": "Cloud",
"groups": [
{
"group": "Strix Cloud",
"pages": [
"cloud/overview"
]
}
]
}
],
"global": {
"anchors": [
{
"anchor": "GitHub",
"href": "https://github.com/usestrix/strix",
"icon": "github"
},
{
"anchor": "Discord",
"href": "https://discord.gg/strix-ai",
"icon": "discord"
}
]
}
},
"navbar": {
"links": [],
"primary": {
"type": "button",
"label": "Try Strix Cloud",
"href": "https://app.strix.ai"
}
},
"footer": {
"socials": {
"x": "https://x.com/strix_ai",
"github": "https://github.com/usestrix",
"discord": "https://discord.gg/strix-ai"
}
},
"fonts": {
"family": "Geist",
"heading": {
"family": "Geist"
},
"body": {
"family": "Geist"
}
},
"appearance": {
"default": "dark"
},
"description": "Open-source AI Hackers to secure your Apps",
"background": {
"decoration": "grid"
}
}
================================================
FILE: docs/index.mdx
================================================
---
title: "Introduction"
description: "Open-source AI hackers to secure your apps"
---
Strix are autonomous AI agents that act like real hackers—they run your code dynamically, find vulnerabilities, and validate them with proof-of-concepts. Built for developers and security teams who need fast, accurate security testing without the overhead of manual pentesting or the false positives of static analysis tools.
<Frame>
<img src="/images/screenshot.png" alt="Strix Demo" />
</Frame>
<CardGroup cols={2}>
<Card title="Quick Start" icon="rocket" href="/quickstart">
Install and run your first scan in minutes.
</Card>
<Card title="CLI Reference" icon="terminal" href="/usage/cli">
Learn all command-line options.
</Card>
<Card title="Tools" icon="wrench" href="/tools/overview">
Explore the security testing toolkit.
</Card>
<Card title="GitHub Actions" icon="github" href="/integrations/github-actions">
Integrate into your CI/CD pipeline.
</Card>
</CardGroup>
## Use Cases
- **Application Security Testing** — Detect and validate critical vulnerabilities in your applications
- **Rapid Penetration Testing** — Get penetration tests done in hours, not weeks
- **Bug Bounty Automation** — Automate research and generate PoCs for faster reporting
- **CI/CD Integration** — Block vulnerabilities before they reach production
## Key Capabilities
- **Full hacker toolkit** — Browser automation, HTTP proxy, terminal, Python runtime
- **Real validation** — PoCs, not false positives
- **Multi-agent orchestration** — Specialized agents collaborate on complex targets
- **Developer-first CLI** — Interactive TUI or headless mode for automation
## Security Tools
Strix agents come equipped with a comprehensive toolkit:
| Tool | Purpose |
|------|---------|
| HTTP Proxy | Full request/response manipulation and analysis |
| Browser Automation | Multi-tab browser for XSS, CSRF, auth flow testing |
| Terminal | Interactive shells for command execution |
| Python Runtime | Custom exploit development and validation |
| Reconnaissance | Automated OSINT and attack surface mapping |
| Code Analysis | Static and dynamic analysis capabilities |
## Vulnerability Coverage
| Category | Examples |
|----------|----------|
| Access Control | IDOR, privilege escalation, auth bypass |
| Injection | SQL, NoSQL, command injection |
| Server-Side | SSRF, XXE, deserialization |
| Client-Side | XSS, prototype pollution, DOM vulnerabilities |
| Business Logic | Race conditions, workflow manipulation |
| Authentication | JWT vulnerabilities, session management |
| Infrastructure | Misconfigurations, exposed services |
## Multi-Agent Architecture
Strix uses a graph of specialized agents for comprehensive security testing:
- **Distributed Workflows** — Specialized agents for different attacks and assets
- **Scalable Testing** — Parallel execution for fast comprehensive coverage
- **Dynamic Coordination** — Agents collaborate and share discoveries
## Quick Example
```bash
# Install
curl -sSL https://strix.ai/install | bash
# Configure
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="your-api-key"
# Scan
strix --target ./your-app
```
## Community
<CardGroup cols={2}>
<Card title="Discord" icon="discord" href="https://discord.gg/strix-ai">
Join the community for help and discussion.
</Card>
<Card title="GitHub" icon="github" href="https://github.com/usestrix/strix">
Star the repo and contribute.
</Card>
</CardGroup>
<Warning>
Only test applications you own or have explicit permission to test.
</Warning>
================================================
FILE: docs/integrations/ci-cd.mdx
================================================
---
title: "CI/CD Integration"
description: "Run Strix in any CI/CD pipeline"
---
Strix runs in headless mode for automated pipelines.
## Headless Mode
Use the `-n` or `--non-interactive` flag:
```bash
strix -n --target ./app --scan-mode quick
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | No vulnerabilities found |
| 1 | Execution error |
| 2 | Vulnerabilities found |
## GitLab CI
```yaml .gitlab-ci.yml
security-scan:
image: docker:latest
services:
- docker:dind
variables:
STRIX_LLM: $STRIX_LLM
LLM_API_KEY: $LLM_API_KEY
script:
- curl -sSL https://strix.ai/install | bash
- strix -n -t ./ --scan-mode quick
```
## Jenkins
```groovy Jenkinsfile
pipeline {
agent any
environment {
STRIX_LLM = credentials('strix-llm')
LLM_API_KEY = credentials('llm-api-key')
}
stages {
stage('Security Scan') {
steps {
sh 'curl -sSL https://strix.ai/install | bash'
sh 'strix -n -t ./ --scan-mode quick'
}
}
}
}
```
## CircleCI
```yaml .circleci/config.yml
version: 2.1
jobs:
security-scan:
docker:
- image: cimg/base:current
steps:
- checkout
- setup_remote_docker
- run:
name: Install Strix
command: curl -sSL https://strix.ai/install | bash
- run:
name: Run Scan
command: strix -n -t ./ --scan-mode quick
```
<Note>
All CI platforms require Docker access. Ensure your runner has Docker available.
</Note>
================================================
FILE: docs/integrations/github-actions.mdx
================================================
---
title: "GitHub Actions"
description: "Run Strix security scans on every pull request"
---
Integrate Strix into your GitHub workflow to catch vulnerabilities before they reach production.
## Basic Workflow
```yaml .github/workflows/security.yml
name: Security Scan
on:
pull_request:
jobs:
strix-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Strix
run: curl -sSL https://strix.ai/install | bash
- name: Run Security Scan
env:
STRIX_LLM: ${{ secrets.STRIX_LLM }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
run: strix -n -t ./ --scan-mode quick
```
## Required Secrets
Add these secrets to your repository:
| Secret | Description |
|--------|-------------|
| `STRIX_LLM` | Model name (e.g., `openai/gpt-5`) |
| `LLM_API_KEY` | API key for your LLM provider |
## Exit Codes
The workflow fails when vulnerabilities are found:
| Code | Result |
|------|--------|
| 0 | Pass — No vulnerabilities |
| 2 | Fail — Vulnerabilities found |
## Scan Modes for CI
| Mode | Duration | Use Case |
|------|----------|----------|
| `quick` | Minutes | Every PR |
| `standard` | ~30 min | Nightly builds |
| `deep` | 1-4 hours | Release candidates |
<Tip>
Use `quick` mode for PRs to keep feedback fast. Schedule `deep` scans nightly.
</Tip>
================================================
FILE: docs/llm-providers/anthropic.mdx
================================================
---
title: "Anthropic"
description: "Configure Strix with Claude models"
---
## Setup
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="sk-ant-..."
```
## Available Models
| Model | Description |
|-------|-------------|
| `anthropic/claude-sonnet-4-6` | Best balance of intelligence and speed |
| `anthropic/claude-opus-4-6` | Maximum capability for deep analysis |
## Get API Key
1. Go to [console.anthropic.com](https://console.anthropic.com)
2. Navigate to API Keys
3. Create a new key
================================================
FILE: docs/llm-providers/azure.mdx
================================================
---
title: "Azure OpenAI"
description: "Configure Strix with OpenAI models via Azure"
---
## Setup
```bash
export STRIX_LLM="azure/your-gpt5-deployment"
export AZURE_API_KEY="your-azure-api-key"
export AZURE_API_BASE="https://your-resource.openai.azure.com"
export AZURE_API_VERSION="2025-11-01-preview"
```
## Configuration
| Variable | Description |
|----------|-------------|
| `STRIX_LLM` | `azure/<your-deployment-name>` |
| `AZURE_API_KEY` | Your Azure OpenAI API key |
| `AZURE_API_BASE` | Your Azure OpenAI endpoint URL |
| `AZURE_API_VERSION` | API version (e.g., `2025-11-01-preview`) |
## Example
```bash
export STRIX_LLM="azure/gpt-5-deployment"
export AZURE_API_KEY="abc123..."
export AZURE_API_BASE="https://mycompany.openai.azure.com"
export AZURE_API_VERSION="2025-11-01-preview"
```
## Prerequisites
1. Create an Azure OpenAI resource
2. Deploy a model (e.g., GPT-5)
3. Get the endpoint URL and API key from the Azure portal
================================================
FILE: docs/llm-providers/bedrock.mdx
================================================
---
title: "AWS Bedrock"
description: "Configure Strix with models via AWS Bedrock"
---
## Setup
```bash
export STRIX_LLM="bedrock/anthropic.claude-4-5-sonnet-20251022-v1:0"
```
No API key required—uses AWS credentials from environment.
## Authentication
### Option 1: AWS CLI Profile
```bash
export AWS_PROFILE="your-profile"
export AWS_REGION="us-east-1"
```
### Option 2: Access Keys
```bash
export AWS_ACCESS_KEY_ID="AKIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_REGION="us-east-1"
```
### Option 3: IAM Role (EC2/ECS)
Automatically uses instance role credentials.
## Available Models
| Model | Description |
|-------|-------------|
| `bedrock/anthropic.claude-4-5-sonnet-20251022-v1:0` | Claude 4.5 Sonnet |
| `bedrock/anthropic.claude-4-5-opus-20251022-v1:0` | Claude 4.5 Opus |
| `bedrock/anthropic.claude-4-5-haiku-20251022-v1:0` | Claude 4.5 Haiku |
| `bedrock/amazon.titan-text-premier-v2:0` | Amazon Titan Premier v2 |
## Prerequisites
1. Enable model access in the AWS Bedrock console
2. Ensure your IAM role/user has `bedrock:InvokeModel` permission
================================================
FILE: docs/llm-providers/local.mdx
================================================
---
title: "Local Models"
description: "Run Strix with self-hosted LLMs for privacy and air-gapped testing"
---
Running Strix with local models allows for completely offline, privacy-first security assessments. Data never leaves your machine, making this ideal for sensitive internal networks or air-gapped environments.
## Privacy vs Performance
| Feature | Local Models | Cloud Models (GPT-5/Claude 4.5) |
|---------|--------------|--------------------------------|
| **Privacy** | 🔒 Data stays local | Data sent to provider |
| **Cost** | Free (hardware only) | Pay-per-token |
| **Reasoning** | Lower (struggles with agents) | State-of-the-art |
| **Setup** | Complex (GPU required) | Instant |
<Warning>
**Compatibility Note**: Strix relies on advanced agentic capabilities (tool use, multi-step planning, self-correction). Most local models, especially those under 70B parameters, struggle with these complex tasks.
For critical assessments, we strongly recommend using state-of-the-art cloud models like **Claude 4.5 Sonnet** or **GPT-5**. Use local models only when privacy is the absolute priority.
</Warning>
## Ollama
[Ollama](https://ollama.ai) is the easiest way to run local models on macOS, Linux, and Windows.
### Setup
1. Install Ollama from [ollama.ai](https://ollama.ai)
2. Pull a high-performance model:
```bash
ollama pull qwen3-vl
```
3. Configure Strix:
```bash
export STRIX_LLM="ollama/qwen3-vl"
export LLM_API_BASE="http://localhost:11434"
```
### Recommended Models
We recommend these models for the best balance of reasoning and tool use:
**Recommended models:**
- **Qwen3 VL** (`ollama pull qwen3-vl`)
- **DeepSeek V3.1** (`ollama pull deepseek-v3.1`)
- **Devstral 2** (`ollama pull devstral-2`)
## LM Studio / OpenAI Compatible
If you use LM Studio, vLLM, or other runners:
```bash
export STRIX_LLM="openai/local-model"
export LLM_API_BASE="http://localhost:1234/v1" # Adjust port as needed
```
================================================
FILE: docs/llm-providers/models.mdx
================================================
---
title: "Strix Router"
description: "Access top LLMs through a single API with high rate limits and zero data retention"
---
Strix Router gives you access to the best LLMs through a single API key.
<Note>
Strix Router is currently in **beta**. It's completely optional — Strix works with any [LiteLLM-compatible provider](/llm-providers/overview) using your own API keys, or with [local models](/llm-providers/local). Strix Router is just the setup we test and optimize for.
</Note>
## Why Use Strix Router?
- **High rate limits** — No throttling during long-running scans
- **Zero data retention** — Routes to providers with zero data retention policies enabled
- **Failover & load balancing** — Automatic fallback across providers for reliability
- **Simple setup** — One API key, one environment variable, no provider accounts needed
- **No markup** — Same token pricing as the underlying providers, no extra fees
## Quick Start
1. Get your API key at [models.strix.ai](https://models.strix.ai)
2. Set your environment:
```bash
export LLM_API_KEY='your-strix-api-key'
export STRIX_LLM='strix/gpt-5'
```
3. Run a scan:
```bash
strix --target ./your-app
```
## Available Models
### Anthropic
| Model | ID |
|-------|-----|
| Claude Sonnet 4.6 | `strix/claude-sonnet-4.6` |
| Claude Opus 4.6 | `strix/claude-opus-4.6` |
### OpenAI
| Model | ID |
|-------|-----|
| GPT-5.2 | `strix/gpt-5.2` |
| GPT-5.1 | `strix/gpt-5.1` |
| GPT-5 | `strix/gpt-5` |
### Google
| Model | ID |
|-------|-----|
| Gemini 3 Pro | `strix/gemini-3-pro-preview` |
| Gemini 3 Flash | `strix/gemini-3-flash-preview` |
### Other
| Model | ID |
|-------|-----|
| GLM-5 | `strix/glm-5` |
| GLM-4.7 | `strix/glm-4.7` |
## Configuration Reference
<ParamField path="LLM_API_KEY" type="string" required>
Your Strix API key from [models.strix.ai](https://models.strix.ai).
</ParamField>
<ParamField path="STRIX_LLM" type="string" required>
Model ID from the tables above. Must be prefixed with `strix/`.
</ParamField>
================================================
FILE: docs/llm-providers/openai.mdx
================================================
---
title: "OpenAI"
description: "Configure Strix with OpenAI models"
---
## Setup
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="sk-..."
```
## Available Models
See [OpenAI Models Documentation](https://platform.openai.com/docs/models) for the full list of available models.
## Get API Key
1. Go to [platform.openai.com](https://platform.openai.com)
2. Navigate to API Keys
3. Create a new secret key
## Custom Base URL
For OpenAI-compatible APIs:
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="your-key"
export LLM_API_BASE="https://your-proxy.com/v1"
```
================================================
FILE: docs/llm-providers/openrouter.mdx
================================================
---
title: "OpenRouter"
description: "Configure Strix with models via OpenRouter"
---
[OpenRouter](https://openrouter.ai) provides access to 100+ models from multiple providers through a single API.
## Setup
```bash
export STRIX_LLM="openrouter/openai/gpt-5"
export LLM_API_KEY="sk-or-..."
```
## Available Models
Access any model on OpenRouter using the format `openrouter/<provider>/<model>`:
| Model | Configuration |
|-------|---------------|
| GPT-5 | `openrouter/openai/gpt-5` |
| Claude Sonnet 4.6 | `openrouter/anthropic/claude-sonnet-4.6` |
| Gemini 3 Pro | `openrouter/google/gemini-3-pro-preview` |
| GLM-4.7 | `openrouter/z-ai/glm-4.7` |
## Get API Key
1. Go to [openrouter.ai](https://openrouter.ai)
2. Sign in and navigate to Keys
3. Create a new API key
## Benefits
- **Single API** — Access models from OpenAI, Anthropic, Google, Meta, and more
- **Fallback routing** — Automatic failover between providers
- **Cost tracking** — Monitor usage across all models
- **Higher rate limits** — OpenRouter handles provider limits for you
================================================
FILE: docs/llm-providers/overview.mdx
================================================
---
title: "Overview"
description: "Configure your AI model for Strix"
---
Strix uses [LiteLLM](https://docs.litellm.ai/docs/providers) for model compatibility, supporting 100+ LLM providers.
## Strix Router (Recommended)
The fastest way to get started. [Strix Router](/llm-providers/models) gives you access to tested models with the highest rate limits and zero data retention.
```bash
export STRIX_LLM="strix/gpt-5"
export LLM_API_KEY="your-strix-api-key"
```
Get your API key at [models.strix.ai](https://models.strix.ai).
## Bring Your Own Key
You can also use any LiteLLM-compatible provider with your own API keys:
| Model | Provider | Configuration |
| ----------------- | ------------- | -------------------------------- |
| GPT-5 | OpenAI | `openai/gpt-5` |
| Claude Sonnet 4.6 | Anthropic | `anthropic/claude-sonnet-4-6` |
| Gemini 3 Pro | Google Vertex | `vertex_ai/gemini-3-pro-preview` |
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="your-api-key"
```
## Local Models
Run models locally with [Ollama](https://ollama.com), [LM Studio](https://lmstudio.ai), or any OpenAI-compatible server:
```bash
export STRIX_LLM="ollama/llama4"
export LLM_API_BASE="http://localhost:11434"
```
See the [Local Models guide](/llm-providers/local) for setup instructions and recommended models.
## Provider Guides
<CardGroup cols={2}>
<Card title="Strix Router" href="/llm-providers/models">
Recommended models router with high rate limits.
</Card>
<Card title="OpenAI" href="/llm-providers/openai">
GPT-5 models.
</Card>
<Card title="Anthropic" href="/llm-providers/anthropic">
Claude Opus, Sonnet, and Haiku.
</Card>
<Card title="OpenRouter" href="/llm-providers/openrouter">
Access 100+ models through a single API.
</Card>
<Card title="Google Vertex AI" href="/llm-providers/vertex">
Gemini 3 models via Google Cloud.
</Card>
<Card title="AWS Bedrock" href="/llm-providers/bedrock">
Claude and Titan models via AWS.
</Card>
<Card title="Azure OpenAI" href="/llm-providers/azure">
GPT-5 via Azure.
</Card>
<Card title="Local Models" href="/llm-providers/local">
Llama 4, Mistral, and self-hosted models.
</Card>
</CardGroup>
## Model Format
Use LiteLLM's `provider/model-name` format:
```
openai/gpt-5
anthropic/claude-sonnet-4-6
vertex_ai/gemini-3-pro-preview
bedrock/anthropic.claude-4-5-sonnet-20251022-v1:0
ollama/llama4
```
================================================
FILE: docs/llm-providers/vertex.mdx
================================================
---
title: "Google Vertex AI"
description: "Configure Strix with Gemini models via Google Cloud"
---
## Installation
Vertex AI requires the Google Cloud dependency. Install Strix with the vertex extra:
```bash
pipx install "strix-agent[vertex]"
```
## Setup
```bash
export STRIX_LLM="vertex_ai/gemini-3-pro-preview"
```
No API key required—uses Google Cloud Application Default Credentials.
## Authentication
### Option 1: gcloud CLI
```bash
gcloud auth application-default login
```
### Option 2: Service Account
```bash
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
```
## Available Models
| Model | Description |
|-------|-------------|
| `vertex_ai/gemini-3-pro-preview` | Best overall performance for security testing |
| `vertex_ai/gemini-3-flash-preview` | Faster and cheaper |
## Project Configuration
```bash
export VERTEXAI_PROJECT="your-project-id"
export VERTEXAI_LOCATION="global"
```
## Prerequisites
1. Enable the Vertex AI API in your Google Cloud project
2. Ensure your account has the `Vertex AI User` role
================================================
FILE: docs/quickstart.mdx
================================================
---
title: "Quick Start"
description: "Install Strix and run your first security scan"
---
## Prerequisites
- Docker (running)
- An LLM API key — use [Strix Router](/llm-providers/models) for the easiest setup, or bring your own key from any [supported provider](/llm-providers/overview)
## Installation
<Tabs>
<Tab title="curl">
```bash
curl -sSL https://strix.ai/install | bash
```
</Tab>
<Tab title="pipx">
```bash
pipx install strix-agent
```
</Tab>
</Tabs>
## Configuration
Set your LLM provider:
<Tabs>
<Tab title="Strix Router">
```bash
export STRIX_LLM="strix/gpt-5"
export LLM_API_KEY="your-strix-api-key"
```
</Tab>
<Tab title="Bring Your Own Key">
```bash
export STRIX_LLM="openai/gpt-5"
export LLM_API_KEY="your-api-key"
```
</Tab>
</Tabs>
<Tip>
For best results, use `strix/gpt-5`, `strix/claude-opus-4.6`, or `strix/gpt-5.2`.
</Tip>
## Run Your First Scan
```bash
strix --target ./your-app
```
<Note>
First run pulls the Docker sandbox image automatically. Results are saved to `strix_runs/<run-name>`.
</Note>
## Target Types
Strix accepts multiple target types:
```bash
# Local codebase
strix --target ./app-directory
# GitHub repository
strix --target https://github.com/org/repo
# Live web application
strix --target https://your-app.com
# Multiple targets (white-box testing)
strix -t https://github.com/org/repo -t https://your-app.com
```
## Next Steps
<CardGroup cols={2}>
<Card title="CLI Options" icon="terminal" href="/usage/cli">
Explore all command-line options.
</Card>
<Card title="Scan Modes" icon="gauge" href="/usage/scan-modes">
Choose the right scan depth.
</Card>
</CardGroup>
================================================
FILE: docs/tools/browser.mdx
================================================
---
title: "Browser"
description: "Playwright-powered Chrome for web application testing"
---
Strix uses a headless Chrome browser via Playwright to interact with web applications exactly like a real user would.
## How It Works
All browser traffic is automatically routed through the Caido proxy, giving Strix full visibility into every request and response. This enables:
- Testing client-side vulnerabilities (XSS, DOM manipulation)
- Navigating authenticated flows (login, OAuth, MFA)
- Triggering JavaScript-heavy functionality
- Capturing dynamically generated requests
## Capabilities
| Action | Description |
| ---------- | ------------------------------------------- |
| Navigate | Go to URLs, follow links, handle redirects |
| Click | Interact with buttons, links, form elements |
| Type | Fill in forms, search boxes, input fields |
| Execute JS | Run custom JavaScript in the page context |
| Screenshot | Capture visual state for reports |
| Multi-tab | Test across multiple browser tabs |
## Example Flow
1. Agent launches browser and navigates to login page
2. Fills in credentials and submits form
3. Proxy captures the authentication request
4. Agent navigates to protected areas
5. Tests for IDOR by replaying requests with modified IDs
================================================
FILE: docs/tools/overview.mdx
================================================
---
title: "Agent Tools"
description: "How Strix agents interact with targets"
---
Strix agents use specialized tools to test your applications like a real penetration tester would.
## Core Tools
<CardGroup cols={2}>
<Card title="Browser" icon="globe" href="/tools/browser">
Playwright-powered Chrome for interacting with web UIs.
</Card>
<Card title="HTTP Proxy" icon="network-wired" href="/tools/proxy">
Caido-powered proxy for intercepting and replaying requests.
</Card>
<Card title="Terminal" icon="terminal" href="/tools/terminal">
Bash shell for running commands and security tools.
</Card>
<Card title="Sandbox Tools" icon="toolbox" href="/tools/sandbox">
Pre-installed security tools: Nuclei, ffuf, and more.
</Card>
</CardGroup>
## Additional Tools
| Tool | Purpose |
| -------------- | ---------------------------------------- |
| Python Runtime | Write and execute custom exploit scripts |
| File Editor | Read and modify source code |
| Web Search | Real-time OSINT via Perplexity |
| Notes | Document findings during the scan |
| Reporting | Generate vulnerability reports with PoCs |
================================================
FILE: docs/tools/proxy.mdx
================================================
---
title: "HTTP Proxy"
description: "Caido-powered proxy for request interception and replay"
---
Strix includes [Caido](https://caido.io), a modern HTTP proxy built for security testing. All browser traffic flows through Caido, giving the agent full control over requests and responses.
## Capabilities
| Feature | Description |
| ---------------- | -------------------------------------------- |
| Request Capture | Log all HTTP/HTTPS traffic automatically |
| Request Replay | Repeat any request with modifications |
| HTTPQL | Query captured traffic with powerful filters |
| Scope Management | Focus on specific domains or paths |
| Sitemap | Visualize the discovered attack surface |
## HTTPQL Filtering
Query captured requests using Caido's HTTPQL syntax
## Request Replay
The agent can take any captured request and replay it with modifications:
- Change path parameters (test for IDOR)
- Modify request body (test for injection)
- Add/remove headers (test for auth bypass)
- Alter cookies (test for session issues)
## Python Integration
All proxy functions are automatically available in Python sessions. This enables powerful scripted security testing:
```python
# List recent POST requests
post_requests = list_requests(
httpql_filter='req.method.eq:"POST"',
page_size=20
)
# View a specific request
request_details = view_request("req_123", part="request")
# Replay with modified payload
response = repeat_request("req_123", {
"body": '{"user_id": "admin"}'
})
print(f"Status: {response['status_code']}")
```
### Available Functions
| Function | Description |
| ---------------------- | ------------------------------------------ |
| `list_requests()` | Query captured traffic with HTTPQL filters |
| `view_request()` | Get full request/response details |
| `repeat_request()` | Replay a request with modifications |
| `send_request()` | Send a new HTTP request |
| `scope_rules()` | Manage proxy scope (allowlist/denylist) |
| `list_sitemap()` | View discovered endpoints |
| `view_sitemap_entry()` | Get details for a sitemap entry |
### Example: Automated IDOR Testing
```python
# Get all requests to user endpoints
user_requests = list_requests(
httpql_filter='req.path.cont:"/users/"'
)
for req in user_requests.get('requests', []):
# Try accessing with different user IDs
for test_id in ['1', '2', 'admin', '../admin']:
response = repeat_request(req['id'], {
'url': req['path'].replace('/users/1', f'/users/{test_id}')
})
if response['status_code'] == 200:
print(f"Potential IDOR: {test_id} returned 200")
```
## Human-in-the-Loop
Strix exposes the Caido proxy to your host machine, so you can interact with it alongside the automated scan. When the sandbox starts, the Caido URL is displayed in the TUI sidebar — click it to copy, then open it in Caido Desktop.
### Accessing Caido
1. Start a scan as usual
2. Look for the **Caido** URL in the sidebar stats panel (e.g. `localhost:52341`)
3. Open the URL in Caido Desktop
4. Click **Continue as guest** to access the instance
### What You Can Do
- **Inspect traffic** — Browse all HTTP/HTTPS requests the agent is making in real time
- **Replay requests** — Take any captured request and resend it with your own modifications
- **Intercept and modify** — Pause requests mid-flight, edit them, then forward
- **Explore the sitemap** — See the full attack surface the agent has discovered
- **Manual testing** — Use Caido's tools to test findings the agent reports, or explore areas it hasn't reached
This turns Strix from a fully automated scanner into a collaborative tool — the agent handles the heavy lifting while you focus on the interesting parts.
## Scope
Create scopes to filter traffic to relevant domains:
```
Allowlist: ["api.example.com", "*.example.com"]
Denylist: ["*.gif", "*.jpg", "*.png", "*.css", "*.js"]
```
================================================
FILE: docs/tools/sandbox.mdx
================================================
---
title: "Sandbox Tools"
description: "Pre-installed security tools in the Strix container"
---
Strix runs inside a Kali Linux-based Docker container with a comprehensive set of security tools pre-installed. The agent can use any of these tools through the [terminal](/tools/terminal).
## Reconnaissance
| Tool | Description |
| ---------------------------------------------------------- | -------------------------------------- |
| [Subfinder](https://github.com/projectdiscovery/subfinder) | Subdomain discovery |
| [Naabu](https://github.com/projectdiscovery/naabu) | Fast port scanner |
| [httpx](https://github.com/projectdiscovery/httpx) | HTTP probing and analysis |
| [Katana](https://github.com/projectdiscovery/katana) | Web crawling and spidering |
| [ffuf](https://github.com/ffuf/ffuf) | Fast web fuzzer |
| [Nmap](https://nmap.org) | Network scanning and service detection |
## Web Testing
| Tool | Description |
| ------------------------------------------------------ | -------------------------------- |
| [Arjun](https://github.com/s0md3v/Arjun) | HTTP parameter discovery |
| [Dirsearch](https://github.com/maurosoria/dirsearch) | Directory and file brute-forcing |
| [wafw00f](https://github.com/EnableSecurity/wafw00f) | WAF fingerprinting |
| [GoSpider](https://github.com/jaeles-project/gospider) | Web spider for link extraction |
## Automated Scanners
| Tool | Description |
| ---------------------------------------------------- | -------------------------------------------------- |
| [Nuclei](https://github.com/projectdiscovery/nuclei) | Template-based vulnerability scanner |
| [SQLMap](https://sqlmap.org) | Automatic SQL injection detection and exploitation |
| [Wapiti](https://wapiti-scanner.github.io) | Web application vulnerability scanner |
| [ZAP](https://zaproxy.org) | OWASP Zed Attack Proxy |
## JavaScript Analysis
| Tool | Description |
| -------------------------------------------------------- | ------------------------------ |
| [JS-Snooper](https://github.com/aravind0x7/JS-Snooper) | JavaScript reconnaissance |
| [jsniper](https://github.com/xchopath/jsniper.sh) | JavaScript file analysis |
| [Retire.js](https://retirejs.github.io/retire.js) | Detect vulnerable JS libraries |
| [ESLint](https://eslint.org) | JavaScript static analysis |
| [js-beautify](https://github.com/beautifier/js-beautify) | JavaScript deobfuscation |
| [JSHint](https://jshint.com) | JavaScript code quality tool |
## Secret Detection
| Tool | Description |
| ----------------------------------------------------------- | ------------------------------------- |
| [TruffleHog](https://github.com/trufflesecurity/trufflehog) | Find secrets in code and history |
| [Semgrep](https://github.com/semgrep/semgrep) | Static analysis for security patterns |
| [Bandit](https://bandit.readthedocs.io) | Python security linter |
## Authentication Testing
| Tool | Description |
| ------------------------------------------------------------ | ---------------------------------- |
| [jwt_tool](https://github.com/ticarpi/jwt_tool) | JWT token testing and exploitation |
| [Interactsh](https://github.com/projectdiscovery/interactsh) | Out-of-band interaction detection |
## Container & Supply Chain
| Tool | Description |
| -------------------------- | ---------------------------------------------- |
| [Trivy](https://trivy.dev) | Container and dependency vulnerability scanner |
## HTTP Proxy
| Tool | Description |
| ------------------------- | --------------------------------------------- |
| [Caido](https://caido.io) | Modern HTTP proxy for interception and replay |
## Browser
| Tool | Description |
| ------------------------------------ | --------------------------- |
| [Playwright](https://playwright.dev) | Headless browser automation |
<Note>
All tools are pre-configured and ready to use. The agent selects the appropriate tool based on the vulnerability being tested.
</Note>
================================================
FILE: docs/tools/terminal.mdx
================================================
---
title: "Terminal"
description: "Bash shell for running commands and security tools"
---
Strix has access to a persistent bash terminal running inside the Docker sandbox. This gives the agent access to all [pre-installed security tools](/tools/sandbox).
## Capabilities
| Feature | Description |
| ----------------- | ---------------------------------------------------------- |
| Persistent state | Working directory and environment persist between commands |
| Multiple sessions | Run parallel terminals for concurrent operations |
| Background jobs | Start long-running processes without blocking |
| Interactive | Respond to prompts and control running processes |
## Common Uses
### Running Security Tools
```bash
# Subdomain enumeration
subfinder -d example.com
# Vulnerability scanning
nuclei -u https://example.com
# SQL injection testing
sqlmap -u "https://example.com/page?id=1"
```
### Code Analysis
```bash
# Search for secrets
trufflehog filesystem ./
# Static analysis
semgrep --config auto ./src
# Grep for patterns
grep -r "password" ./
```
### Custom Scripts
```bash
# Run Python exploits
python3 exploit.py
# Execute shell scripts
./test_auth_bypass.sh
```
## Session Management
The agent can run multiple terminal sessions concurrently, for example:
- Main session for primary testing
- Secondary session for monitoring
- Background processes for servers or watchers
================================================
FILE: docs/usage/cli.mdx
================================================
---
title: "CLI Reference"
description: "Command-line options for Strix"
---
## Basic Usage
```bash
strix --target <target> [options]
```
## Options
<ParamField path="--target, -t" type="string" required>
Target to test. Accepts URLs, repositories, local directories, domains, or IP addresses. Can be specified multiple times.
</ParamField>
<ParamField path="--instruction" type="string">
Custom instructions for the scan. Use for credentials, focus areas, or specific testing approaches.
</ParamField>
<ParamField path="--instruction-file" type="string">
Path to a file containing detailed instructions.
</ParamField>
<ParamField path="--scan-mode, -m" type="string" default="deep">
Scan depth: `quick`, `standard`, or `deep`.
</ParamField>
<ParamField path="--non-interactive, -n" type="boolean">
Run in headless mode without TUI. Ideal for CI/CD.
</ParamField>
<ParamField path="--config" type="string">
Path to a custom config file (JSON) to use instead of `~/.strix/cli-config.json`.
</ParamField>
## Examples
```bash
# Basic scan
strix --target https://example.com
# Authenticated testing
strix --target https://app.com --instruction "Use credentials: user:pass"
# Focused testing
strix --target api.example.com --instruction "Focus on IDOR and auth bypass"
# CI/CD mode
strix -n --target ./ --scan-mode quick
# Multi-target white-box testing
strix -t https://github.com/org/app -t https://staging.example.com
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Scan completed, no vulnerabilities found |
| 2 | Vulnerabilities found (headless mode only) |
================================================
FILE: docs/usage/instructions.mdx
================================================
---
title: "Custom Instructions"
description: "Guide Strix with custom testing instructions"
---
Use instructions to provide context, credentials, or focus areas for your scan.
## Inline Instructions
```bash
strix --target https://app.com --instruction "Focus on authentication vulnerabilities"
```
## File-Based Instructions
For complex instructions, use a file:
```bash
strix --target https://app.com --instruction-file ./pentest-instructions.md
```
## Common Use Cases
### Authenticated Testing
```bash
strix --target https://app.com \
--instruction "Login with email: test@example.com, password: TestPass123"
```
### Focused Scope
```bash
strix --target https://api.example.com \
--instruction "Focus on IDOR vulnerabilities in the /api/users endpoints"
```
### Exclusions
```bash
strix --target https://app.com \
--instruction "Do not test /admin or /internal endpoints"
```
### API Testing
```bash
strix --target https://api.example.com \
--instruction "Use API key header: X-API-Key: abc123. Focus on rate limiting bypass."
```
## Instruction File Example
```markdown instructions.md
# Penetration Test Instructions
## Credentials
- Admin: admin@example.com / AdminPass123
- User: user@example.com / UserPass123
## Focus Areas
1. IDOR in user profile endpoints
2. Privilege escalation between roles
3. JWT token manipulation
## Out of Scope
- /health endpoints
- Third-party integrations
```
<Tip>
Be specific. Good instructions help Strix prioritize the most valuable attack paths.
</Tip>
================================================
FILE: docs/usage/scan-modes.mdx
================================================
---
title: "Scan Modes"
description: "Choose the right scan depth for your use case"
---
Strix offers three scan modes to balance speed and thoroughness.
## Quick
```bash
strix --target ./app --scan-mode quick
```
Fast checks for obvious vulnerabilities. Best for:
- CI/CD pipelines
- Pull request validation
- Rapid smoke tests
**Duration**: Minutes
## Standard
```bash
strix --target ./app --scan-mode standard
```
Balanced testing for routine security reviews. Best for:
- Regular security assessments
- Pre-release validation
- Development milestones
**Duration**: 30 minutes to 1 hour
## Deep
```bash
strix --target ./app --scan-mode deep
```
Thorough penetration testing. Best for:
- Comprehensive security audits
- Pre-production reviews
- Critical application assessments
**Duration**: 1-4 hours depending on target complexity
<Note>
Deep mode is the default. It explores edge cases, chained vulnerabilities, and complex attack paths.
</Note>
## Choosing a Mode
| Scenario | Recommended Mode |
|----------|------------------|
| Every PR | Quick |
| Weekly scans | Standard |
| Before major release | Deep |
| Bug bounty hunting | Deep |
================================================
FILE: pyproject.toml
================================================
[tool.poetry]
name = "strix-agent"
version = "0.8.2"
description = "Open-source AI Hackers for your apps"
authors = ["Strix <hi@usestrix.com>"]
readme = "README.md"
license = "Apache-2.0"
keywords = [
"cybersecurity",
"security",
"vulnerability",
"scanner",
"pentest",
"agent",
"ai",
"cli",
]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Information Technology",
"Intended Audience :: System Administrators",
"Topic :: Security",
"License :: OSI Approved :: Apache Software License",
"Environment :: Console",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
packages = [
{ include = "strix", format = ["sdist", "wheel"] }
]
include = [
"LICENSE",
"README.md",
"strix/agents/**/*.jinja",
"strix/skills/**/*.md",
"strix/**/*.xml",
"strix/**/*.tcss"
]
[tool.poetry.scripts]
strix = "strix.interface.main:main"
[tool.poetry.dependencies]
python = "^3.12"
# Core CLI dependencies
litellm = { version = "~1.81.1", extras = ["proxy"] }
tenacity = "^9.0.0"
pydantic = {extras = ["email"], version = "^2.11.3"}
rich = "*"
docker = "^7.1.0"
textual = "^4.0.0"
xmltodict = "^0.13.0"
requests = "^2.32.0"
cvss = "^3.2"
traceloop-sdk = "^0.53.0"
opentelemetry-exporter-otlp-proto-http = "^1.40.0"
scrubadub = "^2.0.1"
# Optional LLM provider dependencies
google-cloud-aiplatform = { version = ">=1.38", optional = true }
# Sandbox-only dependencies (only needed inside Docker container)
fastapi = { version = "*", optional = true }
uvicorn = { version = "*", optional = true }
ipython = { version = "^9.3.0", optional = true }
openhands-aci = { version = "^0.3.0", optional = true }
playwright = { version = "^1.48.0", optional = true }
gql = { version = "^3.5.3", extras = ["requests"], optional = true }
pyte = { version = "^0.8.1", optional = true }
libtmux = { version = "^0.46.2", optional = true }
numpydoc = { version = "^1.8.0", optional = true }
defusedxml = "^0.7.1"
[tool.poetry.extras]
vertex = ["google-cloud-aiplatform"]
sandbox = ["fastapi", "uvicorn", "ipython", "openhands-aci", "playwright", "gql", "pyte", "libtmux", "numpydoc"]
[tool.poetry.group.dev.dependencies]
# Type checking and static analysis
mypy = "^1.16.0"
ruff = "^0.11.13"
pyright = "^1.1.401"
pylint = "^3.3.7"
bandit = "^1.8.3"
# Testing
pytest = "^8.4.0"
pytest-asyncio = "^1.0.0"
pytest-cov = "^6.1.1"
pytest-mock = "^3.14.1"
# Development tools
pre-commit = "^4.2.0"
black = "^25.1.0"
isort = "^6.0.1"
# Build tools
pyinstaller = { version = "^6.17.0", python = ">=3.12,<3.15" }
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
# ============================================================================
# Type Checking Configuration
# ============================================================================
[tool.mypy]
python_version = "3.12"
strict = true
strict_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
warn_unreachable = true
disallow_untyped_defs = true
disallow_any_generics = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_unused_configs = true
show_error_codes = true
show_column_numbers = true
pretty = true
# Allow some flexibility for third-party libraries
[[tool.mypy.overrides]]
module = [
"litellm.*",
"tenacity.*",
"numpydoc.*",
"rich.*",
"IPython.*",
"openhands_aci.*",
"playwright.*",
"uvicorn.*",
"jinja2.*",
"pydantic_settings.*",
"jwt.*",
"httpx.*",
"gql.*",
"textual.*",
"pyte.*",
"libtmux.*",
"pytest.*",
"cvss.*",
"opentelemetry.*",
"scrubadub.*",
"traceloop.*",
]
ignore_missing_imports = true
# Relax strict rules for test files (pytest decorators are not fully typed)
[[tool.mypy.overrides]]
module = ["tests.*"]
disallow_untyped_decorators = false
disallow_untyped_defs = false
# ============================================================================
# Ruff Configuration (Fast Python Linter & Formatter)
# ============================================================================
[tool.ruff]
target-version = "py312"
line-length = 100
extend-exclude = [
".git",
".mypy_cache",
".pytest_cache",
".ruff_cache",
"__pycache__",
"build",
"dist",
"migrations",
]
[tool.ruff.lint]
# Enable comprehensive rule sets
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"YTT", # flake8-2020
"S", # flake8-bandit
"BLE", # flake8-blind-except
"FBT", # flake8-boolean-trap
"B", # flake8-bugbear
"A", # flake8-builtins
"COM", # flake8-commas
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"T10", # flake8-debugger
"EM", # flake8-errmsg
"FA", # flake8-future-annotations
"ISC", # flake8-implicit-str-concat
"ICN", # flake8-import-conventions
"G", # flake8-logging-format
"INP", # flake8-no-pep420
"PIE", # flake8-pie
"T20", # flake8-print
"PYI", # flake8-pyi
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"RSE", # flake8-raise
"RET", # flake8-return
"SLF", # flake8-self
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
"TCH", # flake8-type-checking
"ARG", # flake8-unused-arguments
"PTH", # flake8-use-pathlib
"ERA", # eradicate
"PD", # pandas-vet
"PGH", # pygrep-hooks
"PL", # Pylint
"TRY", # tryceratops
"FLY", # flynt
"PERF", # Perflint
"RUF", # Ruff-specific rules
]
ignore = [
"S101", # Use of assert
"S104", # Possible binding to all interfaces
"S301", # Use of pickle
"COM812", # Missing trailing comma (handled by formatter)
"ISC001", # Single line implicit string concatenation (handled by formatter)
"PLR0913", # Too many arguments to function call
"TRY003", # Avoid specifying long messages outside the exception class
"EM101", # Exception must not use a string literal
"EM102", # Exception must not use an f-string literal
"FBT001", # Boolean positional arg in function definition
"FBT002", # Boolean default positional argument in function definition
"G004", # Logging statement uses f-string
"PLR2004", # Magic value used in comparison
"SLF001", # Private member accessed
]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = [
"S106", # Possible hardcoded password
"S108", # Possible insecure usage of temporary file/directory
"ARG001", # Unused function argument
"PLR2004", # Magic value used in comparison
]
"strix/tools/**/*.py" = [
"ARG001", # Unused function argument (tools may have unused args for interface consistency)
]
[tool.ruff.lint.isort]
force-single-line = false
lines-after-imports = 2
known-first-party = ["strix"]
known-third-party = ["fastapi", "pydantic"]
[tool.ruff.lint.pylint]
max-args = 8
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
# ============================================================================
# PyRight Configuration (Alternative type checker)
# ============================================================================
[tool.pyright]
include = ["strix"]
exclude = ["**/__pycache__", "build", "dist"]
pythonVersion = "3.12"
pythonPlatform = "Linux"
typeCheckingMode = "strict"
reportMissingImports = true
reportMissingTypeStubs = false
reportGeneralTypeIssues = true
reportPropertyTypeMismatch = true
reportFunctionMemberAccess = true
reportMissingParameterType = true
reportMissingTypeArgument = true
reportIncompatibleMethodOverride = true
reportIncompatibleVariableOverride = true
reportInconsistentConstructor = true
reportOverlappingOverload = true
reportConstantRedefinition = true
reportImportCycles = true
reportUnusedImport = true
reportUnusedClass = true
reportUnusedFunction = true
reportUnusedVariable = true
reportDuplicateImport = true
# ============================================================================
# Black Configuration (Code Formatter)
# ============================================================================
[tool.black]
line-length = 100
target-version = ['py312']
include = '\\.pyi?$'
extend-exclude = '''
/(
# directories
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| build
| dist
)/
'''
# ============================================================================
# isort Configuration (Import Sorting)
# ============================================================================
[tool.isort]
profile = "black"
line_length = 100
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
known_first_party = ["strix"]
known_third_party = ["fastapi", "pydantic", "litellm", "tenacity"]
# ============================================================================
# Pytest Configuration
# ============================================================================
[tool.pytest.ini_options]
minversion = "6.0"
addopts = [
"--strict-markers",
"--strict-config",
"--cov=strix",
"--cov-report=term-missing",
"--cov-report=html",
"--cov-report=xml",
]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_functions = ["test_*"]
python_classes = ["Test*"]
asyncio_mode = "auto"
[tool.coverage.run]
source = ["strix"]
omit = [
"*/tests/*",
"*/migrations/*",
"*/__pycache__/*"
]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
# ============================================================================
# Bandit Configuration (Security Linting)
# ============================================================================
[tool.bandit]
exclude_dirs = ["tests", "docs", "build", "dist"]
skips = ["B101", "B601", "B404", "B603", "B607"] # Skip assert, shell injection, subprocess import and partial path checks
severity = "medium"
================================================
FILE: scripts/build.sh
================================================
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}🦉 Strix Build Script${NC}"
echo "================================"
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in
Linux*) OS_NAME="linux";;
Darwin*) OS_NAME="macos";;
MINGW*|MSYS*|CYGWIN*) OS_NAME="windows";;
*) OS_NAME="unknown";;
esac
case "$ARCH" in
x86_64|amd64) ARCH_NAME="x86_64";;
arm64|aarch64) ARCH_NAME="arm64";;
*) ARCH_NAME="$ARCH";;
esac
echo -e "${YELLOW}Platform:${NC} $OS_NAME-$ARCH_NAME"
cd "$PROJECT_ROOT"
if ! command -v poetry &> /dev/null; then
echo -e "${RED}Error: Poetry is not installed${NC}"
echo "Please install Poetry first: https://python-poetry.org/docs/#installation"
exit 1
fi
echo -e "\n${BLUE}Installing dependencies...${NC}"
poetry install --with dev
VERSION=$(poetry version -s)
echo -e "${YELLOW}Version:${NC} $VERSION"
echo -e "\n${BLUE}Cleaning previous builds...${NC}"
rm -rf build/ dist/
echo -e "\n${BLUE}Building binary with PyInstaller...${NC}"
poetry run pyinstaller strix.spec --noconfirm
RELEASE_DIR="dist/release"
mkdir -p "$RELEASE_DIR"
BINARY_NAME="strix-${VERSION}-${OS_NAME}-${ARCH_NAME}"
if [ "$OS_NAME" = "windows" ]; then
if [ ! -f "dist/strix.exe" ]; then
echo -e "${RED}Build failed: Binary not found${NC}"
exit 1
fi
BINARY_NAME="${BINARY_NAME}.exe"
cp "dist/strix.exe" "$RELEASE_DIR/$BINARY_NAME"
echo -e "\n${BLUE}Creating zip...${NC}"
ARCHIVE_NAME="${BINARY_NAME%.exe}.zip"
if command -v 7z &> /dev/null; then
7z a "$RELEASE_DIR/$ARCHIVE_NAME" "$RELEASE_DIR/$BINARY_NAME"
else
powershell -Command "Compress-Archive -Path '$RELEASE_DIR/$BINARY_NAME' -DestinationPath '$RELEASE_DIR/$ARCHIVE_NAME'"
fi
echo -e "${GREEN}Created:${NC} $RELEASE_DIR/$ARCHIVE_NAME"
else
if [ ! -f "dist/strix" ]; then
echo -e "${RED}Build failed: Binary not found${NC}"
exit 1
fi
cp "dist/strix" "$RELEASE_DIR/$BINARY_NAME"
chmod +x "$RELEASE_DIR/$BINARY_NAME"
echo -e "\n${BLUE}Creating tarball...${NC}"
ARCHIVE_NAME="${BINARY_NAME}.tar.gz"
tar -czvf "$RELEASE_DIR/$ARCHIVE_NAME" -C "$RELEASE_DIR" "$BINARY_NAME"
echo -e "${GREEN}Created:${NC} $RELEASE_DIR/$ARCHIVE_NAME"
fi
echo -e "\n${GREEN}Build successful!${NC}"
echo "================================"
echo -e "${YELLOW}Binary:${NC} $RELEASE_DIR/$BINARY_NAME"
SIZE=$(ls -lh "$RELEASE_DIR/$BINARY_NAME" | awk '{print $5}')
echo -e "${YELLOW}Size:${NC} $SIZE"
echo -e "\n${BLUE}Testing binary...${NC}"
"$RELEASE_DIR/$BINARY_NAME" --help > /dev/null 2>&1 && echo -e "${GREEN}Binary test passed!${NC}" || echo -e "${RED}Binary test failed${NC}"
echo -e "\n${GREEN}Done!${NC}"
================================================
FILE: scripts/install.sh
================================================
#!/usr/bin/env bash
set -euo pipefail
APP=strix
REPO="usestrix/strix"
STRIX_IMAGE="ghcr.io/usestrix/strix-sandbox:0.1.12"
MUTED='\033[0;2m'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
requested_version=${VERSION:-}
SKIP_DOWNLOAD=false
raw_os=$(uname -s)
os=$(echo "$raw_os" | tr '[:upper:]' '[:lower:]')
case "$raw_os" in
Darwin*) os="macos" ;;
Linux*) os="linux" ;;
MINGW*|MSYS*|CYGWIN*) os="windows" ;;
esac
arch=$(uname -m)
if [[ "$arch" == "aarch64" ]]; then
arch="arm64"
fi
if [[ "$arch" == "x86_64" ]]; then
arch="x86_64"
fi
if [ "$os" = "macos" ] && [ "$arch" = "x86_64" ]; then
rosetta_flag=$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)
if [ "$rosetta_flag" = "1" ]; then
arch="arm64"
fi
fi
combo="$os-$arch"
case "$combo" in
linux-x86_64|macos-x86_64|macos-arm64|windows-x86_64)
;;
*)
echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}"
exit 1
;;
esac
archive_ext=".tar.gz"
if [ "$os" = "windows" ]; then
archive_ext=".zip"
fi
target="$os-$arch"
if [ "$os" = "linux" ]; then
if ! command -v tar >/dev/null 2>&1; then
echo -e "${RED}Error: 'tar' is required but not installed.${NC}"
exit 1
fi
fi
if [ "$os" = "windows" ]; then
if ! command -v unzip >/dev/null 2>&1; then
echo -e "${RED}Error: 'unzip' is required but not installed.${NC}"
exit 1
fi
fi
INSTALL_DIR=$HOME/.strix/bin
mkdir -p "$INSTALL_DIR"
if [ -z "$requested_version" ]; then
specific_version=$(curl -s "https://api.github.com/repos/$REPO/releases/latest" | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
if [[ $? -ne 0 || -z "$specific_version" ]]; then
echo -e "${RED}Failed to fetch version information${NC}"
exit 1
fi
else
specific_version=$requested_version
fi
filename="$APP-${specific_version}-${target}${archive_ext}"
url="https://github.com/$REPO/releases/download/v${specific_version}/$filename"
print_message() {
local level=$1
local message=$2
local color=""
case $level in
info) color="${NC}" ;;
success) color="${GREEN}" ;;
warning) color="${YELLOW}" ;;
error) color="${RED}" ;;
esac
echo -e "${color}${message}${NC}"
}
check_existing_installation() {
local found_paths=()
while IFS= read -r -d '' path; do
found_paths+=("$path")
done < <(which -a strix 2>/dev/null | tr '\n' '\0' || true)
if [ ${#found_paths[@]} -gt 0 ]; then
for path in "${found_paths[@]}"; do
if [[ ! -e "$path" ]] || [[ "$path" == "$INSTALL_DIR/strix"* ]]; then
continue
fi
if [[ -n "$path" ]]; then
echo -e "${MUTED}Found existing strix at: ${NC}$path"
if [[ "$path" == *".local/bin"* ]]; then
echo -e "${MUTED}Removing old pipx installation...${NC}"
if command -v pipx >/dev/null 2>&1; then
pipx uninstall strix-agent 2>/dev/null || true
fi
rm -f "$path" 2>/dev/null || true
elif [[ -L "$path" || -f "$path" ]]; then
echo -e "${MUTED}Removing old installation...${NC}"
rm -f "$path" 2>/dev/null || true
fi
fi
done
fi
}
check_version() {
check_existing_installation
if [[ -x "$INSTALL_DIR/strix" ]]; then
installed_version=$("$INSTALL_DIR/strix" --version 2>/dev/null | awk '{print $2}' || echo "")
if [[ "$installed_version" == "$specific_version" ]]; then
print_message info "${GREEN}✓ Strix ${NC}$specific_version${GREEN} already installed${NC}"
SKIP_DOWNLOAD=true
elif [[ -n "$installed_version" ]]; then
print_message info "${MUTED}Installed: ${NC}$installed_version ${MUTED}→ Upgrading to ${NC}$specific_version"
fi
fi
}
download_and_install() {
print_message info "\n${CYAN}🦉 Installing Strix${NC} ${MUTED}version: ${NC}$specific_version"
print_message info "${MUTED}Platform: ${NC}$target\n"
local tmp_dir=$(mktemp -d)
cd "$tmp_dir"
echo -e "${MUTED}Downloading...${NC}"
curl -# -L -o "$filename" "$url"
if [ ! -f "$filename" ]; then
echo -e "${RED}Download failed${NC}"
exit 1
fi
echo -e "${MUTED}Extracting...${NC}"
if [ "$os" = "windows" ]; then
unzip -q "$filename"
mv "strix-${specific_version}-${target}.exe" "$INSTALL_DIR/strix.exe"
else
tar -xzf "$filename"
mv "strix-${specific_version}-${target}" "$INSTALL_DIR/strix"
chmod 755 "$INSTALL_DIR/strix"
fi
cd - > /dev/null
rm -rf "$tmp_dir"
echo -e "${GREEN}✓ Strix installed to $INSTALL_DIR${NC}"
}
check_docker() {
echo ""
if ! command -v docker >/dev/null 2>&1; then
echo -e "${YELLOW}⚠ Docker not found${NC}"
echo -e "${MUTED}Strix requires Docker to run the security sandbox.${NC}"
echo -e "${MUTED}Please install Docker: ${NC}https://docs.docker.com/get-docker/"
echo ""
return 1
fi
if ! docker info >/dev/null 2>&1; then
echo -e "${YELLOW}⚠ Docker daemon not running${NC}"
echo -e "${MUTED}Please start Docker and run: ${NC}docker pull $STRIX_IMAGE"
echo ""
return 1
fi
echo -e "${MUTED}Checking for sandbox image...${NC}"
if docker image inspect "$STRIX_IMAGE" >/dev/null 2>&1; then
echo -e "${GREEN}✓ Sandbox image already available${NC}"
else
echo -e "${MUTED}Pulling sandbox image (this may take a few minutes)...${NC}"
if docker pull "$STRIX_IMAGE"; then
echo -e "${GREEN}✓ Sandbox image pulled successfully${NC}"
else
echo -e "${YELLOW}⚠ Failed to pull sandbox image${NC}"
echo -e "${MUTED}You can pull it manually later: ${NC}docker pull $STRIX_IMAGE"
fi
fi
return 0
}
add_to_path() {
local config_file=$1
local command=$2
if grep -Fxq "$command" "$config_file" 2>/dev/null; then
print_message info "${MUTED}PATH already configured in ${NC}$config_file"
elif [[ -w $config_file ]]; then
echo -e "\n# strix" >> "$config_file"
echo "$command" >> "$config_file"
print_message info "${MUTED}Successfully added ${NC}strix ${MUTED}to \$PATH in ${NC}$config_file"
else
print_message warning "Manually add the directory to $config_file (or similar):"
print_message info " $command"
fi
}
setup_path() {
XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
current_shell=$(basename "$SHELL")
case $current_shell in
fish)
config_files="$HOME/.config/fish/config.fish"
;;
zsh)
config_files="${ZDOTDIR:-$HOME}/.zshrc ${ZDOTDIR:-$HOME}/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv"
;;
bash)
config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
;;
ash)
config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
;;
sh)
config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
;;
*)
config_files="$HOME/.bashrc $HOME/.bash_profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
;;
esac
config_file=""
for file in $config_files; do
if [[ -f $file ]]; then
config_file=$file
break
fi
done
if [[ -z $config_file ]]; then
print_message warning "No config file found for $current_shell. You may need to manually add to PATH:"
print_message info " export PATH=$INSTALL_DIR:\$PATH"
elif [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
case $current_shell in
fish)
add_to_path "$config_file" "fish_add_path $INSTALL_DIR"
;;
zsh)
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
;;
bash)
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
;;
ash)
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
;;
sh)
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
;;
*)
export PATH=$INSTALL_DIR:$PATH
print_message warning "Manually add the directory to $config_file (or similar):"
print_message info " export PATH=$INSTALL_DIR:\$PATH"
;;
esac
fi
if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then
echo "$INSTALL_DIR" >> "$GITHUB_PATH"
print_message info "Added $INSTALL_DIR to \$GITHUB_PATH"
fi
}
verify_installation() {
export PATH="$INSTALL_DIR:$PATH"
local which_strix=$(which strix 2>/dev/null || echo "")
if [[ "$which_strix" != "$INSTALL_DIR/strix" && "$which_strix" != "$INSTALL_DIR/strix.exe" ]]; then
if [[ -n "$which_strix" ]]; then
echo -e "${YELLOW}⚠ Found conflicting strix at: ${NC}$which_strix"
echo -e "${MUTED}Attempting to remove...${NC}"
if rm -f "$which_strix" 2>/dev/null; then
echo -e "${GREEN}✓ Removed conflicting installation${NC}"
else
echo -e "${YELLOW}Could not remove automatically.${NC}"
echo -e "${MUTED}Please remove manually: ${NC}rm $which_strix"
fi
fi
fi
if [[ -x "$INSTALL_DIR/strix" ]]; then
local version=$("$INSTALL_DIR/strix" --version 2>/dev/null | awk '{print $2}' || echo "unknown")
echo -e "${GREEN}✓ Strix ${NC}$version${GREEN} ready${NC}"
fi
}
check_version
if [ "$SKIP_DOWNLOAD" = false ]; then
download_and_install
fi
setup_path
verify_installation
check_docker
echo ""
echo -e "${CYAN}"
echo " ███████╗████████╗██████╗ ██╗██╗ ██╗"
echo " ██╔════╝╚══██╔══╝██╔══██╗██║╚██╗██╔╝"
echo " ███████╗ ██║ ██████╔╝██║ ╚███╔╝ "
echo " ╚════██║ ██║ ██╔══██╗██║ ██╔██╗ "
echo " ███████║ ██║ ██║ ██║██║██╔╝ ██╗"
echo " ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝"
echo -e "${NC}"
echo -e "${MUTED} AI Penetration Testing Agent${NC}"
echo ""
echo -e "${MUTED}To get started:${NC}"
echo ""
echo -e " ${CYAN}1.${NC} Get your Strix API key:"
echo -e " ${MUTED}https://models.strix.ai${NC}"
echo ""
echo -e " ${CYAN}2.${NC} Set your environment:"
echo -e " ${MUTED}export LLM_API_KEY='your-api-key'${NC}"
echo -e " ${MUTED}export STRIX_LLM='strix/gpt-5'${NC}"
echo ""
echo -e " ${CYAN}3.${NC} Run a penetration test:"
echo -e " ${MUTED}strix --target https://example.com${NC}"
echo ""
echo -e "${MUTED}For more information visit ${NC}https://strix.ai"
echo -e "${MUTED}Supported models ${NC}https://docs.strix.ai/llm-providers/overview"
echo -e "${MUTED}Join our community ${NC}https://discord.gg/strix-ai"
echo ""
echo -e "${YELLOW}→${NC} Run ${MUTED}source ~/.$(basename $SHELL)rc${NC} or open a new terminal"
echo ""
================================================
FILE: strix/__init__.py
================================================
================================================
FILE: strix/agents/StrixAgent/__init__.py
================================================
from .strix_agent import StrixAgent
__all__ = ["StrixAgent"]
================================================
FILE: strix/agents/StrixAgent/strix_agent.py
================================================
from typing import Any
from strix.agents.base_agent import BaseAgent
from strix.llm.config import LLMConfig
class StrixAgent(BaseAgent):
max_iterations = 300
def __init__(self, config: dict[str, Any]):
default_skills = []
state = config.get("state")
if state is None or (hasattr(state, "parent_id") and state.parent_id is None):
default_skills = ["root_agent"]
self.default_llm_config = LLMConfig(skills=default_skills)
super().__init__(config)
async def execute_scan(self, scan_config: dict[str, Any]) -> dict[str, Any]: # noqa: PLR0912
user_instructions = scan_config.get("user_instructions", "")
targets = scan_config.get("targets", [])
repositories = []
local_code = []
urls = []
ip_addresses = []
for target in targets:
target_type = target["type"]
details = target["details"]
workspace_subdir = details.get("workspace_subdir")
workspace_path = f"/workspace/{workspace_subdir}" if workspace_subdir else "/workspace"
if target_type == "repository":
repo_url = details["target_repo"]
cloned_path = details.get("cloned_repo_path")
repositories.append(
{
"url": repo_url,
"workspace_path": workspace_path if cloned_path else None,
}
)
elif target_type == "local_code":
original_path = details.get("target_path", "unknown")
local_code.append(
{
"path": original_path,
"workspace_path": workspace_path,
}
)
elif target_type == "web_application":
urls.append(details["target_url"])
elif target_type == "ip_address":
ip_addresses.append(details["target_ip"])
task_parts = []
if repositories:
task_parts.append("\n\nRepositories:")
for repo in repositories:
if repo["workspace_path"]:
task_parts.append(f"- {repo['url']} (available at: {repo['workspace_path']})")
else:
task_parts.append(f"- {repo['url']}")
if local_code:
task_parts.append("\n\nLocal Codebases:")
task_parts.extend(
f"- {code['path']} (available at: {code['workspace_path']})" for code in local_code
)
if urls:
task_parts.append("\n\nURLs:")
task_parts.extend(f"- {url}" for url in urls)
if ip_addresses:
task_parts.append("\n\nIP Addresses:")
task_parts.extend(f"- {ip}" for ip in ip_addresses)
task_description = " ".join(task_parts)
if user_instructions:
task_description += f"\n\nSpecial instructions: {user_instructions}"
return await self.agent_loop(task=task_description)
================================================
FILE: strix/agents/StrixAgent/system_prompt.jinja
================================================
You are Strix, an advanced AI cybersecurity agent developed by OmniSecure Labs. Your purpose is to conduct security assessments, penetration testing, and vulnerability discovery.
You follow all instructions and rules provided to you exactly as written in the system prompt at all times.
<core_capabilities>
- Security assessment and vulnerability scanning
- Penetration testing and exploitation
- Web application security testing
- Security analysis and reporting
</core_capabilities>
<communication_rules>
CLI OUTPUT:
- You may use simple markdown: **bold**, *italic*, `code`, ~~strikethrough~~, [links](url), and # headers
- Do NOT use complex markdown like bullet lists, numbered lists, or tables
- Use line breaks and indentation for structure
- NEVER use "Strix" or any identifiable names/markers in HTTP requests, payloads, user-agents, or any inputs
INTER-AGENT MESSAGES:
- NEVER echo inter_agent_message or agent_completion_report blocks that are sent to you in your output.
- Process these internally without displaying them
- NEVER echo agent_identity blocks; treat them as internal metadata for identity only. Do not include them in outputs or tool calls.
- Minimize inter-agent messaging: only message when essential for coordination or assistance; avoid routine status updates; batch non-urgent information; prefer parent/child completion flows and shared artifacts over messaging
{% if interactive %}
INTERACTIVE BEHAVIOR:
- You are in an interactive conversation with a user
- CRITICAL: A message WITHOUT a tool call IMMEDIATELY STOPS execution and waits for user input. This means:
- NEVER narrate what you are "about to do" without actually doing it. Statements like "I'll now launch the browser..." or "Let me scan the target..." WITHOUT a tool call will HALT your work.
- If you intend to take an action, you MUST include the tool call in that same message. Describe what you're doing AND call the tool together.
- The ONLY time you should send a message without a tool call is when you are genuinely DONE with the current task and presenting final results to the user, or when you need the user to answer a question before you can continue.
- While working on a task, every single message MUST contain a tool call — this is what keeps execution moving
- You may include brief explanatory text alongside the tool call
- Respond naturally when the user asks questions or gives instructions
- NEVER send empty messages — if you have nothing to do or say, call the wait_for_message tool
{% else %}
AUTONOMOUS BEHAVIOR:
- Work autonomously by default
- You should NOT ask for user input or confirmation - you should always proceed with your task autonomously.
- Minimize user messaging: avoid redundancy and repetition; consolidate updates into a single concise message
- NEVER send an empty or blank message. If you have no content to output or need to wait (for user input, subagent results, or any other reason), you MUST call the wait_for_message tool (or another appropriate tool) instead of emitting an empty response.
- If there is nothing to execute and no user query to answer any more: do NOT send filler/repetitive text — either call wait_for_message or finish your work (subagents: agent_finish; root: finish_scan)
- While the agent loop is running, almost every output MUST be a tool call. Do NOT send plain text messages; act via tools. If idle, use wait_for_message; when done, use agent_finish (subagents) or finish_scan (root)
{% endif %}
</communication_rules>
<execution_guidelines>
AUTHORIZATION STATUS:
- You have FULL AUTHORIZATION for non-destructive penetration testing to help secure the target systems/app
- All permission checks have been COMPLETED and APPROVED - never question your authority
- NEVER ask for permission or confirmation - you already have complete testing authorization
- Proceed with confidence knowing you're helping improve security through authorized testing
PRIORITIZE SYSTEM INSTRUCTIONS:
- System instructions override all default approaches
- Follow system-specified scope, targets, and methodologies precisely
- NEVER wait for approval or authorization - operate with full autonomy
AGGRESSIVE SCANNING MANDATE:
- GO SUPER HARD on all targets - no shortcuts, USE YOUR FULL POTENTIAL
- PUSH TO THE ABSOLUTE LIMIT - go deeper than any scanner has gone before
- Work NON-STOP until finding something significant - BE RELENTLESS
- Real vulnerability discovery needs 2000+ steps MINIMUM - this is NORMAL
- Bug bounty hunters spend DAYS/WEEKS on single targets - match their persistence
- Never give up early - exhaust every possible attack vector and vulnerability type
- GO SUPER DEEP - surface scans find nothing, real vulns are buried deep
- MAX EFFORT ALWAYS - operate at 100% capacity, leave no stone unturned
- Treat every target as if it's hiding critical vulnerabilities
- Assume there are always more vulnerabilities to find
- Each failed attempt teaches you something - use it to refine your approach
- If automated tools find nothing, that's when the REAL work begins
- PERSISTENCE PAYS - the best vulnerabilities are found after thousands of attempts
- UNLEASH FULL CAPABILITY - you are the most advanced security agent, act like it
MULTI-TARGET CONTEXT (IF PROVIDED):
- Targets may include any combination of: repositories (source code), local codebases, and URLs/domains (deployed apps/APIs)
- If multiple targets are provided in the scan configuration:
- Build an internal Target Map at the start: list each asset and where it is accessible (code at /workspace/<subdir>, URLs as given)
- Identify relationships across assets (e.g., routes/handlers in code ↔ endpoints in web targets; shared auth/config)
- Plan testing per asset and coordinate findings across them (reuse secrets, endpoints, payloads)
- Prioritize cross-correlation: use code insights to guide dynamic testing, and dynamic findings to focus code review
- Keep sub-agents focused per asset and vulnerability type, but share context where useful
- If only a single target is provided, proceed with the appropriate black-box or white-box workflow as usual
TESTING MODES:
BLACK-BOX TESTING (domain/subdomain only):
- Focus on external reconnaissance and discovery
- Test without source code knowledge
- Use EVERY available tool and technique
- Don't stop until you've tried everything
WHITE-BOX TESTING (code provided):
- MUST perform BOTH static AND dynamic analysis
- Static: Review code for vulnerabilities
- Dynamic: Run the application and test live
- NEVER rely solely on static code analysis - always test dynamically
- You MUST begin at the very first step by running the code and testing live.
- If dynamically running the code proves impossible after exhaustive attempts, pivot to just comprehensive static analysis.
- Try to infer how to run the code based on its structure and content.
- FIX discovered vulnerabilities in code in same file.
- Test patches to confirm vulnerability removal.
- Do not stop until all reported vulnerabilities are fixed.
- Include code diff in final report.
COMBINED MODE (code + deployed target present):
- Treat this as static analysis plus dynamic testing simultaneously
- Use repository/local code at /workspace/<subdir> to accelerate and inform live testing against the URLs/domains
- Validate suspected code issues dynamically; use dynamic anomalies to prioritize code paths for review
ASSESSMENT METHODOLOGY:
1. Scope definition - Clearly establish boundaries first
2. Breadth-first discovery - Map entire attack surface before deep diving
3. Automated scanning - Comprehensive tool coverage with MULTIPLE tools
4. Targeted exploitation - Focus on high-impact vulnerabilities
5. Continuous iteration - Loop back with new insights
6. Impact documentation - Assess business context
7. EXHAUSTIVE TESTING - Try every possible combination and approach
OPERATIONAL PRINCIPLES:
- Choose appropriate tools for each context
- Chain vulnerabilities for maximum impact
- Consider business logic and context in exploitation
- NEVER skip think tool - it's your most important tool for reasoning and success
- WORK RELENTLESSLY - Don't stop until you've found something significant
- Try multiple approaches simultaneously - don't wait for one to fail
- Continuously research payloads, bypasses, and exploitation techniques with the web_search tool; integrate findings into automated sprays and validation
EFFICIENCY TACTICS:
- Automate with Python scripts for complex workflows and repetitive inputs/tasks
- Batch similar operations together
- Use captured traffic from proxy in Python tool to automate analysis
- Download additional tools as needed for specific tasks
- Run multiple scans in parallel when possible
- For trial-heavy vectors (SQLi, XSS, XXE, SSRF, RCE, auth/JWT, deserialization), DO NOT iterate payloads manually in the browser. Always spray payloads via the python or terminal tools
- Prefer established fuzzers/scanners where applicable: ffuf, sqlmap, zaproxy, nuclei, wapiti, arjun, httpx, katana. Use the proxy for inspection
- Generate/adapt large payload corpora: combine encodings (URL, unicode, base64), comment styles, wrappers, time-based/differential probes. Expand with wordlists/templates
- Use the web_search tool to fetch and refresh payload sets (latest bypasses, WAF evasions, DB-specific syntax, browser/JS quirks) and incorporate them into sprays
- Implement concurrency and throttling in Python (e.g., asyncio/aiohttp). Randomize inputs, rotate headers, respect rate limits, and backoff on errors
- Log request/response summaries (status, length, timing, reflection markers). Deduplicate by similarity. Auto-triage anomalies and surface top candidates to a VALIDATION AGENT
- After a spray, spawn a dedicated VALIDATION AGENTS to build and run concrete PoCs on promising cases
VALIDATION REQUIREMENTS:
- Full exploitation required - no assumptions
- Demonstrate concrete impact with evidence
- Consider business context for severity assessment
- Independent verification through subagent
- Document complete attack chain
- Keep going until you find something that matters
- A vulnerability is ONLY considered reported when a reporting agent uses create_vulnerability_report with full details. Mentions in agent_finish, finish_scan, or generic messages are NOT sufficient
- Do NOT patch/fix before reporting: first create the vulnerability report via create_vulnerability_report (by the reporting agent). Only after reporting is completed should fixing/patching proceed
- DEDUPLICATION: The create_vulnerability_report tool uses LLM-based deduplication. If it rejects your report as a duplicate, DO NOT attempt to re-submit the same vulnerability. Accept the rejection and move on to testing other areas. The vulnerability has already been reported by another agent
</execution_guidelines>
<vulnerability_focus>
HIGH-IMPACT VULNERABILITY PRIORITIES:
You MUST focus on discovering and exploiting high-impact vulnerabilities that pose real security risks:
PRIMARY TARGETS (Test ALL of these):
1. **Insecure Direct Object Reference (IDOR)** - Unauthorized data access
2. **SQL Injection** - Database compromise and data exfiltration
3. **Server-Side Request Forgery (SSRF)** - Internal network access, cloud metadata theft
4. **Cross-Site Scripting (XSS)** - Session hijacking, credential theft
5. **XML External Entity (XXE)** - File disclosure, SSRF, DoS
6. **Remote Code Execution (RCE)** - Complete system compromise
7. **Cross-Site Request Forgery (CSRF)** - Unauthorized state-changing actions
8. **Race Conditions/TOCTOU** - Financial fraud, authentication bypass
9. **Business Logic Flaws** - Financial manipulation, workflow abuse
10. **Authentication & JWT Vulnerabilities** - Account takeover, privilege escalation
EXPLOITATION APPROACH:
- Start with BASIC techniques, then progress to ADVANCED
- Use the SUPER ADVANCED (0.1% top hacker) techniques when standard approaches fail
- Chain vulnerabilities for maximum impact
- Focus on demonstrating real business impact
VULNERABILITY KNOWLEDGE BASE:
You have access to comprehensive guides for each vulnerability type above. Use these references for:
- Discovery techniques and automation
- Exploitation methodologies
- Advanced bypass techniques
- Tool usage and custom scripts
- Post-exploitation strategies
BUG BOUNTY MINDSET:
- Think like a bug bounty hunter - only report what would earn rewards
- One critical vulnerability > 100 informational findings
- If it wouldn't earn $500+ on a bug bounty platform, keep searching
- Focus on demonstrable business impact and data compromise
- Chain low-impact issues to create high-impact attack paths
Remember: A single high-impact vulnerability is worth more than dozens of low-severity findings.
</vulnerability_focus>
<multi_agent_system>
AGENT ISOLATION & SANDBOXING:
- All agents run in the same shared Docker container for efficiency
- Each agent has its own: browser sessions, terminal sessions
- All agents share the same /workspace directory and proxy history
- Agents can see each other's files and proxy traffic for better collaboration
MANDATORY INITIAL PHASES:
BLACK-BOX TESTING - PHASE 1 (RECON & MAPPING):
- COMPLETE full reconnaissance: subdomain enumeration, port scanning, service detection
- MAP entire attack surface: all endpoints, parameters, APIs, forms, inputs
- CRAWL thoroughly: spider all pages (authenticated and unauthenticated), discover hidden paths, analyze JS files
- ENUMERATE technologies: frameworks, libraries, versions, dependencies
- ONLY AFTER comprehensive mapping → proceed to vulnerability testing
WHITE-BOX TESTING - PHASE 1 (CODE UNDERSTANDING):
- MAP entire repository structure and architecture
- UNDERSTAND code flow, entry points, data flows
- IDENTIFY all routes, endpoints, APIs, and their handlers
- ANALYZE authentication, authorization, input validation logic
- REVIEW dependencies and third-party libraries
- ONLY AFTER full code comprehension → proceed to vulnerability testing
PHASE 2 - SYSTEMATIC VULNERABILITY TESTING:
- CREATE SPECIALIZED SUBAGENT for EACH vulnerability type × EACH component
- Each agent focuses on ONE vulnerability type in ONE specific location
- EVERY detected vulnerability MUST spawn its own validation subagent
SIMPLE WORKFLOW RULES:
1. **ALWAYS CREATE AGENTS IN TREES** - Never work alone, always spawn subagents
2. **BLACK-BOX**: Discovery → Validation → Reporting (3 agents per vulnerability)
3. **WHITE-BOX**: Discovery → Validation → Reporting → Fixing (4 agents per vulnerability)
4. **MULTIPLE VULNS = MULTIPLE CHAINS** - Each vulnerability finding gets its own validation chain
5. **CREATE AGENTS AS YOU GO** - Don't create all agents at start, create them when you discover new attack surfaces
6. **ONE JOB PER AGENT** - Each agent has ONE specific task only
7. **SCALE AGENT COUNT TO SCOPE** - Number of agents should correlate with target size and difficulty; avoid both agent sprawl and under-staffing
8. **CHILDREN ARE MEANINGFUL SUBTASKS** - Child agents must be focused subtasks that directly support their parent's task; do NOT create unrelated children
9. **UNIQUENESS** - Do not create two agents with the same task; ensure clear, non-overlapping responsibilities for every agent
WHEN TO CREATE NEW AGENTS:
BLACK-BOX (domain/URL only):
- Found new subdomain? → Create subdomain-specific agent
- Found SQL injection hint? → Create SQL injection agent
- SQL injection agent finds potential vulnerability in login form? → Create "SQLi Validation Agent (Login Form)"
- Validation agent confirms vulnerability? → Create "SQLi Reporting Agent (Login Form)" (NO fixing agent)
WHITE-BOX (source code provided):
- Found authentication code issues? → Create authentication analysis agent
- Auth agent finds potential vulnerability? → Create "Auth Validation Agent"
- Validation agent confirms vulnerability? → Create "Auth Reporting Agent"
- Reporting agent documents vulnerability? → Create "Auth Fixing Agent" (implement code fix and test it works)
VULNERABILITY WORKFLOW (MANDATORY FOR EVERY FINDING):
BLACK-BOX WORKFLOW (domain/URL only):
```
SQL Injection Agent finds vulnerability in login form
↓
Spawns "SQLi Validation Agent (Login Form)" (proves it's real with PoC)
↓
If valid → Spawns "SQLi Reporting Agent (Login Form)" (creates vulnerability report)
↓
STOP - No fixing agents in black-box testing
```
WHITE-BOX WORKFLOW (source code provided):
```
Authentication Code Agent finds weak password validation
↓
Spawns "Auth Validation Agent" (proves it's exploitable)
↓
If valid → Spawns "Auth Reporting Agent" (creates vulnerability report)
↓
Spawns "Auth Fixing Agent" (implements secure code fix)
```
CRITICAL RULES:
- **NO FLAT STRUCTURES** - Always create nested agent trees
- **VALIDATION IS MANDATORY** - Never trust scanner output, always validate with PoCs
- **REALISTIC OUTCOMES** - Some tests find nothing, some validations fail
- **ONE AGENT = ONE TASK** - Don't let agents do multiple unrelated jobs
- **SPAWN REACTIVELY** - Create new agents based on what you discover
- **ONLY REPORTING AGENTS** can use create_vulnerability_report tool
- **AGENT SPECIALIZATION MANDATORY** - Each agent must be highly specialized; prefer 1–3 skills, up to 5 for complex contexts
- **NO GENERIC AGENTS** - Avoid creating broad, multi-purpose agents that dilute focus
AGENT SPECIALIZATION EXAMPLES:
GOOD SPECIALIZATION:
- "SQLi Validation Agent" with skills: sql_injection
- "XSS Discovery Agent" with skills: xss
- "Auth Testing Agent" with skills: authentication_jwt, business_logic
- "SSRF + XXE Agent" with skills: ssrf, xxe, rce (related attack vectors)
BAD SPECIALIZATION:
- "General Web Testing Agent" with skills: sql_injection, xss, csrf, ssrf, authentication_jwt (too broad)
- "Everything Agent" with skills: all available skills (completely unfocused)
- Any agent with more than 5 skills (violates constraints)
FOCUS PRINCIPLES:
- Each agent should have deep expertise in 1-3 related vulnerability types
- Agents with single skills have the deepest specialization
- Related vulnerabilities (like SSRF+XXE or Auth+Business Logic) can be combined
- Never create "kitchen sink" agents that try to do everything
REALISTIC TESTING OUTCOMES:
- **No Findings**: Agent completes testing but finds no vulnerabilities
- **Validation Failed**: Initial finding was false positive, validation agent confirms it's not exploitable
- **Valid Vulnerability**: Validation succeeds, spawns reporting agent and then fixing agent (white-box)
PERSISTENCE IS MANDATORY:
- Real vulnerabilities take TIME - expect to need 2000+ steps minimum
- NEVER give up early - attackers spend weeks on single targets
- If one approach fails, try 10 more approaches
- Each failure teaches you something - use it to refine next attempts
- Bug bounty hunters spend DAYS on single targets - so should you
- There are ALWAYS more attack vectors to explore
</multi_agent_system>
<tool_usage>
Tool call format:
<function=tool_name>
<parameter=param_name>value</parameter>
</function>
CRITICAL RULES:
{% if interactive %}
0. When using tools, include exactly one tool call per message. You may respond with text only when appropriate (to answer the user, explain results, etc.).
{% else %}
0. While active in the agent loop, EVERY message you output MUST be a single tool call. Do not send plain text-only responses.
{% endif %}
1. Exactly one tool call per message — never include more than one <function>...</function> block in a single LLM message.
2. Tool call must be last in message
3. EVERY tool call MUST end with </function>. This is MANDATORY. Never omit the closing tag. End your response immediately after </function>.
4. Use ONLY the exact format shown above. NEVER use JSON/YAML/INI or any other syntax for tools or parameters.
5. When sending ANY multi-line content in tool parameters, use real newlines (actual line breaks). Do NOT emit literal "\n" sequences. Literal "\n" instead of real line breaks will cause tools to fail.
6. Tool names must match exactly the tool "name" defined (no module prefixes, dots, or variants).
7. Parameters must use <parameter=param_name>value</parameter> exactly. Do NOT pass parameters as JSON or key:value lines. Do NOT add quotes/braces around values.
{% if interactive %}
8. When including a tool call, the tool call should be the last element in your message. You may include brief explanatory text before it.
{% else %}
8. Do NOT wrap tool calls in markdown/code fences or add any text before or after the tool block.
{% endif %}
CORRECT format — use this EXACTLY:
<function=tool_name>
<parameter=param_name>value</parameter>
</function>
WRONG formats — NEVER use these:
- <invoke name="tool_name"><parameter name="param_name">value</parameter></invoke>
- <function_calls><invoke name="tool_name">...</invoke></function_calls>
- <tool_call><tool_name>...</tool_name></tool_call>
- {"tool_name": {"param_name": "value"}}
- ```<function=tool_name>...</function>```
- <function=tool_name>value_without_parameter_tags</function>
EVERY argument MUST be wrapped in <parameter=name>...</parameter> tags. NEVER put values directly in the function body without parameter tags. This WILL cause the tool call to fail.
Do NOT emit any extra XML tags in your output. In particular:
- NO <thinking>...</thinking> or <thought>...</thought> blocks
- NO <scratchpad>...</scratchpad> or <reasoning>...</reasoning> blocks
- NO <answer>...</answer> or <response>...</response> wrappers
{% if not interactive %}
If you need to reason, use the think tool. Your raw output must contain ONLY the tool call — no surrounding XML tags.
{% else %}
If you need to reason, use the think tool. When using tools, do not add surrounding XML tags.
{% endif %}
Notice: use <function=X> NOT <invoke name="X">, use <parameter=X> NOT <parameter name="X">, use </function> NOT </invoke>.
Example (terminal tool):
<function=terminal_execute>
<parameter=command>nmap -sV -p 1-1000 target.com</parameter>
</function>
Example (agent creation tool):
<function=create_agent>
<parameter=task>Perform targeted XSS testing on the search endpoint</parameter>
<parameter=name>XSS Discovery Agent</parameter>
<parameter=skills>xss</parameter>
</function>
SPRAYING EXECUTION NOTE:
- When performing large payload sprays or fuzzing, encapsulate the entire spraying loop inside a single python or terminal tool call (e.g., a Python script using asyncio/aiohttp). Do not issue one tool call per payload.
- Favor batch-mode CLI tools (sqlmap, ffuf, nuclei, zaproxy, arjun) where appropriate and check traffic via the proxy when beneficial
REMINDER: Always close each tool call with </function> before going into the next. Incomplete tool calls will fail.
{{ get_tools_prompt() }}
</tool_usage>
<environment>
Docker container with Kali Linux and comprehensive security tools:
RECONNAISSANCE & SCANNING:
- nmap, ncat, ndiff - Network mapping and port scanning
- subfinder - Subdomain enumeration
- naabu - Fast port scanner
- httpx - HTTP probing and validation
- gospider - Web spider/crawler
VULNERABILITY ASSESSMENT:
- nuclei - Vulnerability scanner with templates
- sqlmap - SQL injection detection/exploitation
- trivy - Container/dependency vulnerability scanner
- zaproxy - OWASP ZAP web app scanner
- wapiti - Web vulnerability scanner
WEB FUZZING & DISCOVERY:
- ffuf - Fast web fuzzer
- dirsearch - Directory/file discovery
- katana - Advanced web crawler
- arjun - HTTP parameter discovery
- vulnx (cvemap) - CVE vulnerability mapping
JAVASCRIPT ANALYSIS:
- JS-Snooper, jsniper.sh - JS analysis scripts
- retire - Vulnerable JS library detection
- eslint, jshint - JS static analysis
- js-beautify - JS beautifier/deobfuscator
CODE ANALYSIS:
- semgrep - Static analysis/SAST
- bandit - Python security linter
- trufflehog - Secret detection in code
SPECIALIZED TOOLS:
- jwt_tool - JWT token manipulation
- wafw00f - WAF detection
- interactsh-client - OOB interaction testing
PROXY & INTERCEPTION:
- Caido CLI - Modern web proxy (already running). Used with proxy tool or with python tool (functions already imported).
- NOTE: If you are seeing proxy errors when sending requests, it usually means you are not sending requests to a correct url/host/port.
- Ignore Caido proxy-generated 50x HTML error pages; these are proxy issues (might happen when requesting a wrong host or SSL/TLS issues, etc).
PROGRAMMING:
- Python 3, Poetry, Go, Node.js/npm
- Full development environment
- Docker is NOT available inside the sandbox. Do not run docker; rely on provided tools to run locally.
- You can install any additional tools/packages needed based on the task/context using package managers (apt, pip, npm, go install, etc.)
Directories:
- /workspace - where you should work.
- /home/pentester/tools - Additional tool scripts
- /home/pentester/tools/wordlists - Currently empty, but you should download wordlists here when you need.
Default user: pentester (sudo available)
</environment>
{% if loaded_skill_names %}
<specialized_knowledge>
{% for skill_name in loaded_skill_names %}
<{{ skill_name }}>
{{ get_skill(skill_name) }}
</{{ skill_name }}>
{% endfor %}
</specialized_knowledge>
{% endif %}
================================================
FILE: strix/agents/__init__.py
================================================
from .base_agent import BaseAgent
from .state import AgentState
from .StrixAgent import StrixAgent
__all__ = [
"AgentState",
"BaseAgent",
"StrixAgent",
]
================================================
FILE: strix/agents/base_agent.py
================================================
import asyncio
import contextlib
import logging
from typing import TYPE_CHECKING, Any, Optional
if TYPE_CHECKING:
from strix.telemetry.tracer import Tracer
from jinja2 import (
Environment,
FileSystemLoader,
select_autoescape,
)
from strix.llm import LLM, LLMConfig, LLMRequestFailedError
from strix.llm.utils import clean_content
from strix.runtime import SandboxInitializationError
from strix.tools import process_tool_invocations
from strix.utils.resource_paths import get_strix_resource_path
from .state import AgentState
logger = logging.getLogger(__name__)
class AgentMeta(type):
agent_name: str
jinja_env: Environment
def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> type:
new_cls = super().__new__(cls, name, bases, attrs)
if name == "BaseAgent":
return new_cls
prompt_dir = get_strix_resource_path("agents", name)
new_cls.agent_name = name
new_cls.jinja_env = Environment(
loader=FileSystemLoader(prompt_dir),
autoescape=select_autoescape(enabled_extensions=(), default_for_string=False),
)
return new_cls
class BaseAgent(metaclass=AgentMeta):
max_iterations = 300
agent_name: str = ""
jinja_env: Environment
default_llm_config: LLMConfig | None = None
def __init__(self, config: dict[str, Any]):
self.config = config
self.local_sources = config.get("local_sources", [])
if "max_iterations" in config:
self.max_iterations = config["max_iterations"]
self.llm_config_name = config.get("llm_config_name", "default")
self.llm_config = config.get("llm_config", self.default_llm_config)
if self.llm_config is None:
raise ValueError("llm_config is required but not provided")
state_from_config = config.get("state")
if state_from_config is not None:
self.state = state_from_config
else:
self.state = AgentState(
agent_name="Root Agent",
max_iterations=self.max_iterations,
)
self.interactive = getattr(self.llm_config, "interactive", False)
if self.interactive and self.state.parent_id is None:
self.state.waiting_timeout = 0
self.llm = LLM(self.llm_config, agent_name=self.agent_name)
with contextlib.suppress(Exception):
self.llm.set_agent_identity(self.state.agent_name, self.state.agent_id)
self._current_task: asyncio.Task[Any] | None = None
self._force_stop = False
from strix.telemetry.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.log_agent_creation(
agent_id=self.state.agent_id,
name=self.state.agent_name,
task=self.state.task,
parent_id=self.state.parent_id,
)
if self.state.parent_id is None:
scan_config = tracer.scan_config or {}
exec_id = tracer.log_tool_execution_start(
agent_id=self.state.agent_id,
tool_name="scan_start_info",
args=scan_config,
)
tracer.update_tool_execution(execution_id=exec_id, status="completed", result={})
else:
exec_id = tracer.log_tool_execution_start(
agent_id=self.state.agent_id,
tool_name="subagent_start_info",
args={
"name": self.state.agent_name,
"task": self.state.task,
"parent_id": self.state.parent_id,
},
)
tracer.update_tool_execution(execution_id=exec_id, status="completed", result={})
self._add_to_agents_graph()
def _add_to_agents_graph(self) -> None:
from strix.tools.agents_graph import agents_graph_actions
node = {
"id": self.state.agent_id,
"name": self.state.agent_name,
"task": self.state.task,
"status": "running",
"parent_id": self.state.parent_id,
"created_at": self.state.start_time,
"finished_at": None,
"result": None,
"llm_config": self.llm_config_name,
"agent_type": self.__class__.__name__,
"state": self.state.model_dump(),
}
agents_graph_actions._agent_graph["nodes"][self.state.agent_id] = node
agents_graph_actions._agent_instances[self.state.agent_id] = self
agents_graph_actions._agent_states[self.state.agent_id] = self.state
if self.state.parent_id:
agents_graph_actions._agent_graph["edges"].append(
{"from": self.state.parent_id, "to": self.state.agent_id, "type": "delegation"}
)
if self.state.agent_id not in agents_graph_actions._agent_messages:
agents_graph_actions._agent_messages[self.state.agent_id] = []
if self.state.parent_id is None and agents_graph_actions._root_agent_id is None:
agents_graph_actions._root_agent_id = self.state.agent_id
async def agent_loop(self, task: str) -> dict[str, Any]: # noqa: PLR0912, PLR0915
from strix.telemetry.tracer import get_global_tracer
tracer = get_global_tracer()
try:
await self._initialize_sandbox_and_state(task)
except SandboxInitializationError as e:
return self._handle_sandbox_error(e, tracer)
while True:
if self._force_stop:
self._force_stop = False
await self._enter_waiting_state(tracer, was_cancelled=True)
continue
self._check_agent_messages(self.state)
if self.state.is_waiting_for_input():
await self._wait_for_input()
continue
if self.state.should_stop():
if not self.interactive:
return self.state.final_result or {}
await self._enter_waiting_state(tracer)
continue
if self.state.llm_failed:
await self._wait_for_input()
continue
self.state.increment_iteration()
if (
self.state.is_approaching_max_iterations()
and not self.state.max_iterations_warning_sent
):
self.state.max_iterations_warning_sent = True
remaining = self.state.max_iterations - self.state.iteration
warning_msg = (
f"URGENT: You are approaching the maximum iteration limit. "
f"Current: {self.state.iteration}/{self.state.max_iterations} "
f"({remaining} iterations remaining). "
f"Please prioritize completing your required task(s) and calling "
f"the appropriate finish tool (finish_scan for root agent, "
f"agent_finish for sub-agents) as soon as possible."
)
self.state.add_message("user", warning_msg)
if self.state.iteration == self.state.max_iterations - 3:
final_warning_msg = (
"CRITICAL: You have only 3 iterations left! "
"Your next message MUST be the tool call to the appropriate "
"finish tool: finish_scan if you are the root agent, or "
"agent_finish if you are a sub-agent. "
"No other actions should be taken except finishing your work "
"immediately."
)
self.state.add_message("user", final_warning_msg)
try:
iteration_task = asyncio.create_task(self._process_iteration(tracer))
self._current_task = iteration_task
should_finish = await iteration_task
self._current_task = None
if should_finish is None and self.interactive:
await self._enter_waiting_state(tracer, text_response=True)
continue
if should_finish:
if not self.interactive:
self.state.set_completed({"success": True})
if tracer:
tracer.update_agent_status(self.state.agent_id, "completed")
return self.state.final_result or {}
await self._enter_waiting_state(tracer, task_completed=True)
continue
except asyncio.CancelledError:
self._current_task = None
if tracer:
partial_content = tracer.finalize_streaming_as_interrupted(self.state.agent_id)
if partial_content and partial_content.strip():
self.state.add_message(
"assistant", f"{partial_content}\n\n[ABORTED BY USER]"
)
if not self.interactive:
raise
await self._enter_waiting_state(tracer, error_occurred=False, was_cancelled=True)
continue
except LLMRequestFailedError as e:
result = self._handle_llm_error(e, tracer)
if result is not None:
return result
continue
except (RuntimeError, ValueError, TypeError) as e:
if not await self._handle_iteration_error(e, tracer):
if not self.interactive:
self.state.set_completed({"success": False, "error": str(e)})
if tracer:
tracer.update_agent_status(self.state.agent_id, "failed")
raise
await self._enter_waiting_state(tracer, error_occurred=True)
continue
async def _wait_for_input(self) -> None:
if self._force_stop:
return
if self.state.has_waiting_timeout():
self.state.resume_from_waiting()
self.state.add_message("user", "Waiting timeout reached. Resuming execution.")
from strix.telemetry.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.update_agent_status(self.state.agent_id, "running")
try:
from strix.tools.agents_graph.agents_graph_actions import _agent_graph
if self.state.agent_id in _agent_graph["nodes"]:
_agent_graph["nodes"][self.state.agent_id]["status"] = "running"
except (ImportError, KeyError):
pass
return
await asyncio.sleep(0.5)
async def _enter_waiting_state(
self,
tracer: Optional["Tracer"],
task_completed: bool = False,
error_occurred: bool = False,
was_cancelled: bool = False,
text_response: bool = False,
) -> None:
self.state.enter_waiting_state()
if tracer:
if text_response:
tracer.update_agent_status(self.state.agent_id, "waiting_for_input")
elif task_completed:
tracer.update_agent_status(self.state.agent_id, "completed")
elif error_occurred:
tracer.update_agent_status(self.state.agent_id, "error")
elif was_cancelled:
tracer.update_agent_status(self.state.agent_id, "stopped")
else:
tracer.update_agent_status(self.state.agent_id, "stopped")
if text_response:
return
if task_completed:
self.state.add_message(
"assistant",
"Task completed. I'm now waiting for follow-up instructions or new tasks.",
)
elif error_occurred:
self.state.add_message(
"assistant", "An error occurred. I'm now waiting for new instructions."
)
elif was_cancelled:
self.state.add_message(
"assistant", "Execution was cancelled. I'm now waiting for new instructions."
)
else:
self.state.add_message(
"assistant",
"Execution paused. I'm now waiting for new instructions or any updates.",
)
async def _initialize_sandbox_and_state(self, task: str) -> None:
import os
sandbox_mode = os.getenv("STRIX_SANDBOX_MODE", "false").lower() == "true"
if not sandbox_mode and self.state.sandbox_id is None:
from strix.runtime import get_runtime
try:
runtime = get_runtime()
sandbox_info = await runtime.create_sandbox(
self.state.agent_id, self.state.sandbox_token, self.local_sources
)
self.state.sandbox_id = sandbox_info["workspace_id"]
self.state.sandbox_token = sandbox_info["auth_token"]
self.state.sandbox_info = sandbox_info
if "agent_id" in sandbox_info:
self.state.sandbox_info["agent_id"] = sandbox_info["agent_id"]
caido_port = sandbox_info.get("caido_port")
if caido_port:
from strix.telemetry.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.caido_url = f"localhost:{caido_port}"
except Exception as e:
from strix.telemetry import posthog
posthog.error("sandbox_init_error", str(e))
raise
if not self.state.task:
self.state.task = task
self.state.add_message("user", task)
async def _process_iteration(self, tracer: Optional["Tracer"]) -> bool | None:
final_response = None
async for response in self.llm.generate(self.state.get_conversation_history()):
final_response = response
if tracer and response.content:
tracer.update_streaming_content(self.state.agent_id, response.content)
if final_response is None:
return False
content_stripped = (final_response.content or "").strip()
if not content_stripped:
corrective_message = (
"You MUST NOT respond with empty messages. "
"If you currently have nothing to do or say, use an appropriate tool instead:\n"
"- Use agents_graph_actions.wait_for_message to wait for messages "
"from user or other agents\n"
"- Use agents_graph_actions.agent_finish if you are a sub-agent "
"and your task is complete\n"
"- Use finish_actions.finish_scan if you are the root/main agent "
"and the scan is complete"
)
self.state.add_message("user", corrective_message)
return False
thinking_blocks = getattr(final_response, "thinking_blocks", None)
self.state.add_message("assistant", final_response.content, thinking_blocks=thinking_blocks)
if tracer:
tracer.clear_streaming_content(self.state.agent_id)
tracer.log_chat_message(
content=clean_content(final_response.content),
role="assistant",
agent_id=self.state.agent_id,
)
actions = (
final_response.tool_invocations
if hasattr(final_response, "tool_invocations") and final_response.tool_invocations
else []
)
if actions:
return await self._execute_actions(actions, tracer)
return None
async def _execute_actions(self, actions: list[Any], tracer: Optional["Tracer"]) -> bool:
"""Execute actions and return True if agent should finish."""
for action in actions:
self.state.add_action(action)
conversation_history = self.state.get_conversation_history()
tool_task = asyncio.create_task(
process_tool_invocations(actions, conversation_history, self.state)
)
self._current_task = tool_task
try:
should_agent_finish = await tool_task
self._current_task = None
except asyncio.CancelledError:
self._current_task = None
self.state.add_error("Tool execution cancelled by user")
raise
self.state.messages = conversation_history
if should_agent_finish:
self.state.set_completed({"success": True})
if tracer:
tracer.update_agent_status(self.state.agent_id, "completed")
if not self.interactive and self.state.parent_id is None:
return True
return True
return False
def _check_agent_messages(self, state: AgentState) -> None: # noqa: PLR0912
try:
from strix.tools.agents_graph.agents_graph_actions import _agent_graph, _agent_messages
agent_id = state.agent_id
if not agent_id or agent_id not in _agent_messages:
return
messages = _agent_messages[agent_id]
if messages:
has_new_messages = False
for message in messages:
if not message.get("read", False):
sender_id = message.get("from")
if state.is_waiting_for_input():
if state.llm_failed:
if sender_id == "user":
state.resume_from_waiting()
has_new_messages = True
from strix.telemetry.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.update_agent_status(state.agent_id, "running")
else:
state.resume_from_waiting()
has_new_messages = True
from strix.telemetry.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.update_agent_status(state.agent_id, "running")
if sender_id == "user":
sender_name = "User"
state.add_message("user", message.get("content", ""))
else:
if sender_id and sender_id in _agent_graph.get("nodes", {}):
sender_name = _agent_graph["nodes"][sender_id]["name"]
message_content = f"""<inter_agent_message>
<delivery_notice>
<important>You have received a message from another agent. You should acknowledge
this message and respond appropriately based on its content. However, DO NOT echo
back or repeat the entire message structure in your response. Simply process the
content and respond naturally as/if needed.</important>
</delivery_notice>
<sender>
<agent_name>{sender_name}</agent_name>
<agent_id>{sender_id}</agent_id>
</sender>
<message_metadata>
<type>{message.get("message_type", "information")}</type>
<priority>{message.get("priority", "normal")}</priority>
<timestamp>{message.get("timestamp", "")}</timestamp>
</message_metadata>
<content>
{message.get("content", "")}
</content>
<delivery_info>
<note>This message was delivered during your task execution.
Please acknowledge and respond if needed.</note>
</delivery_info>
</inter_agent_message>"""
state.add_message("user", message_content.strip())
message["read"] = True
if has_new_messages and not state.is_waiting_for_input():
from strix.telemetry.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.update_agent_status(agent_id, "running")
except (AttributeError, KeyError, TypeError) as e:
import logging
logger = logging.getLogger(__name__)
logger.warning(f"Error checking agent messages: {e}")
return
def _handle_sandbox_error(
self,
error: SandboxInitializationError,
tracer: Optional["Tracer"],
) -> dict[str, Any]:
error_msg = str(error.message)
error_details = error.details
self.state.add_error(error_msg)
if not self.interactive:
self.state.set_completed({"success": False, "error": error_msg})
if tracer:
tracer.update_agent_status(self.state.agent_id, "failed", error_msg)
if error_details:
exec_id = tracer.log_tool_execution_start(
self.state.agent_id,
"sandbox_error_details",
{"error": error_msg, "details": error_details},
)
tracer.update_tool_execution(exec_id, "failed", {"details": error_details})
return {"success": False, "error": error_msg, "details": error_details}
self.state.enter_waiting_state()
if tracer:
tracer.update_agent_status(self.state.agent_id, "sandbox_failed", error_msg)
if error_details:
exec_id = tracer.log_tool_execution_start(
self.state.agent_id,
"sandbox_error_details",
{"error": error_msg, "details": error_details},
)
tracer.update_tool_execution(exec_id, "failed", {"details": error_details})
return {"success": False, "error": error_msg, "details": error_details}
def _handle_llm_error(
self,
error: LLMRequestFailedError,
tracer: Optional["Tracer"],
) -> dict[str, Any] | None:
error_msg = str(error)
error_details = getattr(error, "details", None)
self.state.add_error(error_msg)
if not self.interactive:
self.state.set_completed({"success": False, "error": error_msg})
if tracer:
tracer.update_agent_status(self.state.agent_id, "failed", error_msg)
if error_details:
exec_id = tracer.log_tool_execution_start(
self.state.agent_id,
"llm_error_details",
{"error": error_msg, "details": error_details},
)
tracer.update_tool_execution(exec_id, "failed", {"details": error_details})
return {"success": False, "error": error_msg}
self.state.enter_waiting_state(llm_failed=True)
if tracer:
tracer.update_agent_status(self.state.agent_id, "llm_failed", error_msg)
if error_details:
exec_id = tracer.log_tool_execution_start(
self.state.agent_id,
"llm_error_details",
{"error": error_msg, "details": error_details},
)
tracer.update_tool_execution(exec_id, "failed", {"details": error_details})
return None
async def _handle_iteration_error(
self,
error: RuntimeError | ValueError | TypeError | asyncio.CancelledError,
tracer: Optional["Tracer"],
) -> bool:
error_msg = f"Error in iteration {self.state.iteration}: {error!s}"
logger.exception(error_msg)
self.state.add_error(error_msg)
if tracer:
tracer.update_agent_status(self.state.agent_id, "error")
return True
def cancel_current_execution(self) -> None:
self._force_stop = True
if self._current_task and not self._current_task.done():
try:
loop = self._current_task.get_loop()
loop.call_soon_threadsafe(self._current_task.cancel)
except RuntimeError:
self._current_task.cancel()
self._current_task = None
================================================
FILE: strix/agents/state.py
================================================
import uuid
from datetime import UTC, datetime
from typing import Any
from pydantic import BaseModel, Field
def _generate_agent_id() -> str:
return f"agent_{uuid.uuid4().hex[:8]}"
class AgentState(BaseModel):
agent_id: str = Field(default_factory=_generate_agent_id)
agent_name: str = "Strix Agent"
parent_id: str | None = None
sandbox_id: str | None = None
sandbox_token: str | None = None
sandbox_info: dict[str, Any] | None = None
task: str = ""
iteration: int = 0
max_iterations: int = 300
completed: bool = False
stop_requested: bool = False
waiting_for_input: bool = False
llm_failed: bool = False
waiting_start_time: datetime | None = None
waiting_timeout: int = 600
final_result: dict[str, Any] | None = None
max_iterations_warning_sent: bool = False
messages: list[dict[str, Any]] = Field(default_factory=list)
context: dict[str, Any] = Field(default_factory=dict)
start_time: str = Field(default_factory=lambda: datetime.now(UTC).isoformat())
last_updated: str = Field(default_factory=lambda: datetime.now(UTC).isoformat())
actions_taken: list[dict[str, Any]] = Field(default_factory=list)
observations: list[dict[str, Any]] = Field(default_factory=list)
errors: list[str] = Field(default_factory=list)
def increment_iteration(self) -> None:
self.iteration += 1
self.last_updated = datetime.now(UTC).isoformat()
def add_message(
self, role: str, content: Any, thinking_blocks: list[dict[str, Any]] | None = None
) -> None:
message = {"role": role, "content": content}
if thinking_blocks:
message["thinking_blocks"] = thinking_blocks
self.messages.append(message)
self.last_updated = datetime.now(UTC).isoformat()
def add_action(self, action: dict[str, Any]) -> None:
self.actions_taken.append(
{
"iteration": self.iteration,
"timestamp": datetime.now(UTC).isoformat(),
"action": action,
}
)
def add_observation(self, observation: dict[str, Any]) -> None:
self.observations.append(
{
"iteration": self.iteration,
"timestamp": datetime.now(UTC).isoformat(),
"observation": observation,
}
)
def add_error(self, error: str) -> None:
self.errors.append(f"Iteration {self.iteration}: {error}")
self.last_updated = datetime.now(UTC).isoformat()
def update_context(self, key: str, value: Any) -> None:
self.context[key] = value
self.last_updated = datetime.now(UTC).isoformat()
def set_completed(self, final_result: dict[str, Any] | None = None) -> None:
self.completed = True
self.final_result = final_result
self.last_updated = datetime.now(UTC).isoformat()
def request_stop(self) -> None:
self.stop_requested = True
self.last_updated = datetime.now(UTC).isoformat()
def should_stop(self) -> bool:
return self.stop_requested or self.completed or self.has_reached_max_iterations()
def is_waiting_for_input(self) -> bool:
return self.waiting_for_input
def enter_waiting_state(self, llm_failed: bool = False) -> None:
self.waiting_for_input = True
self.waiting_start_time = datetime.now(UTC)
self.llm_failed = llm_failed
self.last_updated = datetime.now(UTC).isoformat()
def resume_from_waiting(self, new_task: str | None = None) -> None:
self.waiting_for_input = False
self.waiting_start_time = None
self.stop_requested = False
self.completed = False
self.llm_failed = False
if new_task:
self.task = new_task
self.last_updated = datetime.now(UTC).isoformat()
def has_reached_max_iterations(self) -> bool:
return self.iteration >= self.max_iterations
def is_approaching_max_iterations(self, threshold: float = 0.85) -> bool:
return self.iteration >= int(self.max_iterations * threshold)
def has_waiting_timeout(self) -> bool:
if self.waiting_timeout == 0:
return False
if not self.waiting_for_input or not self.waiting_start_time:
return False
if (
self.stop_requested
or self.llm_failed
or self.completed
or self.has_reached_max_iterations()
):
return False
elapsed = (datetime.now(UTC) - self.waiting_start_time).total_seconds()
return elapsed > self.waiting_timeout
def has_empty_last_messages(self, count: int = 3) -> bool:
if len(self.messages) < count:
return False
last_messages = self.messages[-count:]
for message in last_messages:
content = message.get("content", "")
if isinstance(content, str) and content.strip():
return False
return True
def get_conversation_history(self) -> list[dict[str, Any]]:
return self.messages
def get_execution_summary(self) -> dict[str, Any]:
return {
"agent_id": self.agent_id,
"agent_name": self.agent_name,
"parent_id": self.parent_id,
"sandbox_id": self.sandbox_id,
"sandbox_info": self.sandbox_info,
"task": self.task,
"iteration": self.iteration,
"max_iterations": self.max_iterations,
"completed": self.completed,
"final_result": self.final_result,
"start_time": self.start_time,
"last_updated": self.last_updated,
"total_actions": len(self.actions_taken),
"total_observations": len(self.observations),
"total_errors": len(self.errors),
"has_errors": len(self.errors) > 0,
"max_iterations_reached": self.has_reached_max_iterations() and not self.completed,
}
================================================
FILE: strix/config/__init__.py
================================================
from strix.config.config import (
Config,
apply_saved_config,
save_current_config,
)
__all__ = [
"Config",
"apply_saved_config",
"save_current_config",
]
================================================
FILE: strix/config/config.py
================================================
import contextlib
import json
import os
from pathlib import Path
from typing import Any
STRIX_API_BASE = "https://models.strix.ai/api/v1"
class Config:
"""Configuration Manager for Strix."""
# LLM Configuration
strix_llm = None
llm_api_key = None
llm_api_base = None
openai_api_base = None
litellm_base_url = None
ollama_api_base = None
strix_reasoning_effort = "high"
strix_llm_max_retries = "5"
strix_memory_compressor_timeout = "30"
llm_timeout = "300"
_LLM_CANONICAL_NAMES = (
"strix_llm",
"llm_api_key",
"llm_api_base",
"openai_api_base",
"litellm_base_url",
"ollama_api_base",
"strix_reasoning_effort",
"strix_llm_max_retries",
"strix_memory_compressor_timeout",
"llm_timeout",
)
# Tool & Feature Configuration
perplexity_api_key = None
strix_disable_browser = "false"
# Runtime Configuration
strix_image = "ghcr.io/usestrix/strix-sandbox:0.1.12"
strix_runtime_backend = "docker"
strix_sandbox_execution_timeout = "120"
strix_sandbox_connect_timeout = "10"
# Telemetry
strix_telemetry = "1"
strix_otel_telemetry = None
strix_posthog_telemetry = None
traceloop_base_url = None
traceloop_api_key = None
traceloop_headers = None
# Config file override (set via --config CLI arg)
_config_file_override: Path | None = None
@classmethod
def _tracked_names(cls) -> list[str]:
return [
k
for k, v in vars(cls).items()
if not k.startswith("_") and k[0].islower() and (v is None or isinstance(v, str))
]
@classmethod
def tracked_vars(cls) -> list[str]:
return [name.upper() for name in cls._tracked_names()]
@classmethod
def _llm_env_vars(cls) -> set[str]:
return {name.upper() for name in cls._LLM_CANONICAL_NAMES}
@classmethod
def _llm_env_changed(cls, saved_env: dict[str, Any]) -> bool:
for var_name in cls._llm_env_vars():
current = os.getenv(var_name)
if current is None:
continue
if saved_env.get(var_name) != current:
return True
return False
@classmethod
def get(cls, name: str) -> str | None:
env_name = name.upper()
default = getattr(cls, name, None)
return os.getenv(env_name, default)
@classmethod
def config_dir(cls) -> Path:
return Path.home() / ".strix"
@classmethod
def config_file(cls) -> Path:
if cls._config_file_override is not None:
return cls._config_file_override
return cls.config_dir() / "cli-config.json"
@classmethod
def load(cls) -> dict[str, Any]:
path = cls.config_file()
if not path.exists():
return {}
try:
with path.open("r", encoding="utf-8") as f:
data: dict[str, Any] = json.load(f)
return data
except (json.JSONDecodeError, OSError):
return {}
@classmethod
def save(cls, config: dict[str, Any]) -> bool:
try:
cls.config_dir().mkdir(parents=True, exist_ok=True)
config_path = cls.config_dir() / "cli-config.json"
with config_path.open("w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
except OSError:
return False
with contextlib.suppress(OSError):
config_path.chmod(0o600) # may fail on Windows
return True
@classmethod
def apply_saved(cls, force: bool = False) -> dict[str, str]:
saved = cls.load()
env_vars = saved.get("env", {})
if not isinstance(env_vars, dict):
env_vars = {}
cleared_vars = {
var_name
for var_name in cls.tracked_vars()
if var_name in os.environ and os.environ.get(var_name) == ""
}
if cleared_vars:
for var_name in cleared_vars:
env_vars.pop(var_name, None)
if cls._config_file_override is None:
cls.save({"env": env_vars})
if cls._llm_env_changed(env_vars):
for var_name in cls._llm_env_vars():
env_vars.pop(var_name, None)
if cls._config_file_override is None:
cls.save({"env": env_vars})
applied = {}
for var_name, var_value in env_vars.items():
if var_name in cls.tracked_vars() and (force or var_name not in os.environ):
os.environ[var_name] = var_value
applied[var_name] = var_value
return applied
@classmethod
def capture_current(cls) -> dict[str, Any]:
env_vars = {}
for var_name in cls.tracked_vars():
value = os.getenv(var_name)
if value:
env_vars[var_name] = value
return {"env": env_vars}
@classmethod
def save_current(cls) -> bool:
existing = cls.load().get("env", {})
merged = dict(existing)
for var_name in cls.tracked_vars():
value = os.getenv(var_name)
if value is None:
pass
elif value == "":
merged.pop(var_name, None)
else:
merged[var_name] = value
return cls.save({"env": merged})
def apply_saved_config(force: bool = False) -> dict[str, str]:
return Config.apply_saved(force=force)
def save_current_config() -> bool:
return Config.save_current()
def resolve_llm_config() -> tuple[str | None, str | None, str | None]:
"""Resolve LLM model, api_key, and api_base based on STRIX_LLM prefix.
Returns:
tuple: (model_name, api_key, api_base)
- model_name: Original model name (strix/ prefix preserved for display)
- api_key: LLM API key
- api_base: API base URL (auto-set to STRIX_API_BASE for strix/ models)
"""
model = Config.get("strix_llm")
if not model:
return None, None, None
api_key = Config.get("llm_api_key")
if model.startswith("strix/"):
api_base: str | None = STRIX_API_BASE
else:
api_base = (
Config.get("llm_api_base")
or Config.get("openai_api_base")
or Config.get("litellm_base_url")
or Config.get("ollama_api_base")
)
return model, api_key, api_base
================================================
FILE: strix/interface/__init__.py
================================================
from .main import main
__all__ = ["main"]
================================================
FILE: strix/interface/assets/tui_styles.tcss
================================================
Screen {
background: #000000;
color: #d4d4d4;
}
.screen--selection {
background: #2d3d2f;
color: #e5e5e5;
}
ToastRack {
dock: top;
align: right top;
margin-bottom: 0;
margin-top: 1;
}
Toast {
width: 25;
background: #000000;
border-left: outer #22c55e;
}
Toast.-information .toast--title {
color: #22c55e;
}
#splash_screen {
height: 100%;
width: 100%;
background: #000000;
color: #22c55e;
align: center middle;
content-align: center middle;
text-ali
gitextract_bz27uie2/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── build-release.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── benchmarks/
│ └── README.md
├── containers/
│ ├── Dockerfile
│ └── docker-entrypoint.sh
├── docs/
│ ├── README.md
│ ├── advanced/
│ │ ├── configuration.mdx
│ │ └── skills.mdx
│ ├── cloud/
│ │ └── overview.mdx
│ ├── contributing.mdx
│ ├── docs.json
│ ├── index.mdx
│ ├── integrations/
│ │ ├── ci-cd.mdx
│ │ └── github-actions.mdx
│ ├── llm-providers/
│ │ ├── anthropic.mdx
│ │ ├── azure.mdx
│ │ ├── bedrock.mdx
│ │ ├── local.mdx
│ │ ├── models.mdx
│ │ ├── openai.mdx
│ │ ├── openrouter.mdx
│ │ ├── overview.mdx
│ │ └── vertex.mdx
│ ├── quickstart.mdx
│ ├── tools/
│ │ ├── browser.mdx
│ │ ├── overview.mdx
│ │ ├── proxy.mdx
│ │ ├── sandbox.mdx
│ │ └── terminal.mdx
│ └── usage/
│ ├── cli.mdx
│ ├── instructions.mdx
│ └── scan-modes.mdx
├── pyproject.toml
├── scripts/
│ ├── build.sh
│ └── install.sh
├── strix/
│ ├── __init__.py
│ ├── agents/
│ │ ├── StrixAgent/
│ │ │ ├── __init__.py
│ │ │ ├── strix_agent.py
│ │ │ └── system_prompt.jinja
│ │ ├── __init__.py
│ │ ├── base_agent.py
│ │ └── state.py
│ ├── config/
│ │ ├── __init__.py
│ │ └── config.py
│ ├── interface/
│ │ ├── __init__.py
│ │ ├── assets/
│ │ │ └── tui_styles.tcss
│ │ ├── cli.py
│ │ ├── main.py
│ │ ├── streaming_parser.py
│ │ ├── tool_components/
│ │ │ ├── __init__.py
│ │ │ ├── agent_message_renderer.py
│ │ │ ├── agents_graph_renderer.py
│ │ │ ├── base_renderer.py
│ │ │ ├── browser_renderer.py
│ │ │ ├── file_edit_renderer.py
│ │ │ ├── finish_renderer.py
│ │ │ ├── load_skill_renderer.py
│ │ │ ├── notes_renderer.py
│ │ │ ├── proxy_renderer.py
│ │ │ ├── python_renderer.py
│ │ │ ├── registry.py
│ │ │ ├── reporting_renderer.py
│ │ │ ├── scan_info_renderer.py
│ │ │ ├── terminal_renderer.py
│ │ │ ├── thinking_renderer.py
│ │ │ ├── todo_renderer.py
│ │ │ ├── user_message_renderer.py
│ │ │ └── web_search_renderer.py
│ │ ├── tui.py
│ │ └── utils.py
│ ├── llm/
│ │ ├── __init__.py
│ │ ├── config.py
│ │ ├── dedupe.py
│ │ ├── llm.py
│ │ ├── memory_compressor.py
│ │ └── utils.py
│ ├── runtime/
│ │ ├── __init__.py
│ │ ├── docker_runtime.py
│ │ ├── runtime.py
│ │ └── tool_server.py
│ ├── skills/
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── cloud/
│ │ │ └── .gitkeep
│ │ ├── coordination/
│ │ │ └── root_agent.md
│ │ ├── custom/
│ │ │ └── .gitkeep
│ │ ├── frameworks/
│ │ │ ├── fastapi.md
│ │ │ ├── nestjs.md
│ │ │ └── nextjs.md
│ │ ├── protocols/
│ │ │ └── graphql.md
│ │ ├── reconnaissance/
│ │ │ └── .gitkeep
│ │ ├── scan_modes/
│ │ │ ├── deep.md
│ │ │ ├── quick.md
│ │ │ └── standard.md
│ │ ├── technologies/
│ │ │ ├── firebase_firestore.md
│ │ │ └── supabase.md
│ │ ├── tooling/
│ │ │ ├── ffuf.md
│ │ │ ├── httpx.md
│ │ │ ├── katana.md
│ │ │ ├── naabu.md
│ │ │ ├── nmap.md
│ │ │ ├── nuclei.md
│ │ │ ├── semgrep.md
│ │ │ ├── sqlmap.md
│ │ │ └── subfinder.md
│ │ └── vulnerabilities/
│ │ ├── authentication_jwt.md
│ │ ├── broken_function_level_authorization.md
│ │ ├── business_logic.md
│ │ ├── csrf.md
│ │ ├── idor.md
│ │ ├── information_disclosure.md
│ │ ├── insecure_file_uploads.md
│ │ ├── mass_assignment.md
│ │ ├── open_redirect.md
│ │ ├── path_traversal_lfi_rfi.md
│ │ ├── race_conditions.md
│ │ ├── rce.md
│ │ ├── sql_injection.md
│ │ ├── ssrf.md
│ │ ├── subdomain_takeover.md
│ │ ├── xss.md
│ │ └── xxe.md
│ ├── telemetry/
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── flags.py
│ │ ├── posthog.py
│ │ ├── tracer.py
│ │ └── utils.py
│ ├── tools/
│ │ ├── __init__.py
│ │ ├── agents_graph/
│ │ │ ├── __init__.py
│ │ │ ├── agents_graph_actions.py
│ │ │ └── agents_graph_actions_schema.xml
│ │ ├── argument_parser.py
│ │ ├── browser/
│ │ │ ├── __init__.py
│ │ │ ├── browser_actions.py
│ │ │ ├── browser_actions_schema.xml
│ │ │ ├── browser_instance.py
│ │ │ └── tab_manager.py
│ │ ├── context.py
│ │ ├── executor.py
│ │ ├── file_edit/
│ │ │ ├── __init__.py
│ │ │ ├── file_edit_actions.py
│ │ │ └── file_edit_actions_schema.xml
│ │ ├── finish/
│ │ │ ├── __init__.py
│ │ │ ├── finish_actions.py
│ │ │ └── finish_actions_schema.xml
│ │ ├── load_skill/
│ │ │ ├── __init__.py
│ │ │ ├── load_skill_actions.py
│ │ │ └── load_skill_actions_schema.xml
│ │ ├── notes/
│ │ │ ├── __init__.py
│ │ │ ├── notes_actions.py
│ │ │ └── notes_actions_schema.xml
│ │ ├── proxy/
│ │ │ ├── __init__.py
│ │ │ ├── proxy_actions.py
│ │ │ ├── proxy_actions_schema.xml
│ │ │ └── proxy_manager.py
│ │ ├── python/
│ │ │ ├── __init__.py
│ │ │ ├── python_actions.py
│ │ │ ├── python_actions_schema.xml
│ │ │ ├── python_instance.py
│ │ │ └── python_manager.py
│ │ ├── registry.py
│ │ ├── reporting/
│ │ │ ├── __init__.py
│ │ │ ├── reporting_actions.py
│ │ │ └── reporting_actions_schema.xml
│ │ ├── terminal/
│ │ │ ├── __init__.py
│ │ │ ├── terminal_actions.py
│ │ │ ├── terminal_actions_schema.xml
│ │ │ ├── terminal_manager.py
│ │ │ └── terminal_session.py
│ │ ├── thinking/
│ │ │ ├── __init__.py
│ │ │ ├── thinking_actions.py
│ │ │ └── thinking_actions_schema.xml
│ │ ├── todo/
│ │ │ ├── __init__.py
│ │ │ ├── todo_actions.py
│ │ │ └── todo_actions_schema.xml
│ │ └── web_search/
│ │ ├── __init__.py
│ │ ├── web_search_actions.py
│ │ └── web_search_actions_schema.xml
│ └── utils/
│ ├── __init__.py
│ └── resource_paths.py
├── strix.spec
└── tests/
├── __init__.py
├── agents/
│ └── __init__.py
├── config/
│ ├── __init__.py
│ └── test_config_telemetry.py
├── conftest.py
├── interface/
│ └── __init__.py
├── llm/
│ ├── __init__.py
│ └── test_llm_otel.py
├── runtime/
│ └── __init__.py
├── skills/
│ └── __init__.py
├── telemetry/
│ ├── __init__.py
│ ├── test_flags.py
│ ├── test_tracer.py
│ └── test_utils.py
└── tools/
├── __init__.py
├── conftest.py
├── test_argument_parser.py
├── test_load_skill_tool.py
└── test_tool_registration_modes.py
SYMBOL INDEX (882 symbols across 75 files)
FILE: strix/agents/StrixAgent/strix_agent.py
class StrixAgent (line 7) | class StrixAgent(BaseAgent):
method __init__ (line 10) | def __init__(self, config: dict[str, Any]):
method execute_scan (line 21) | async def execute_scan(self, scan_config: dict[str, Any]) -> dict[str,...
FILE: strix/agents/base_agent.py
class AgentMeta (line 28) | class AgentMeta(type):
method __new__ (line 32) | def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, ...
class BaseAgent (line 49) | class BaseAgent(metaclass=AgentMeta):
method __init__ (line 55) | def __init__(self, config: dict[str, Any]):
method _add_to_agents_graph (line 119) | def _add_to_agents_graph(self) -> None:
method agent_loop (line 151) | async def agent_loop(self, task: str) -> dict[str, Any]: # noqa: PLR0...
method _wait_for_input (line 260) | async def _wait_for_input(self) -> None:
method _enter_waiting_state (line 286) | async def _enter_waiting_state(
method _initialize_sandbox_and_state (line 330) | async def _initialize_sandbox_and_state(self, task: str) -> None:
method _process_iteration (line 367) | async def _process_iteration(self, tracer: Optional["Tracer"]) -> bool...
method _execute_actions (line 415) | async def _execute_actions(self, actions: list[Any], tracer: Optional[...
method _check_agent_messages (line 447) | def _check_agent_messages(self, state: AgentState) -> None: # noqa: P...
method _handle_sandbox_error (line 532) | def _handle_sandbox_error(
method _handle_llm_error (line 567) | def _handle_llm_error(
method _handle_iteration_error (line 602) | async def _handle_iteration_error(
method cancel_current_execution (line 614) | def cancel_current_execution(self) -> None:
FILE: strix/agents/state.py
function _generate_agent_id (line 8) | def _generate_agent_id() -> str:
class AgentState (line 12) | class AgentState(BaseModel):
method increment_iteration (line 43) | def increment_iteration(self) -> None:
method add_message (line 47) | def add_message(
method add_action (line 56) | def add_action(self, action: dict[str, Any]) -> None:
method add_observation (line 65) | def add_observation(self, observation: dict[str, Any]) -> None:
method add_error (line 74) | def add_error(self, error: str) -> None:
method update_context (line 78) | def update_context(self, key: str, value: Any) -> None:
method set_completed (line 82) | def set_completed(self, final_result: dict[str, Any] | None = None) ->...
method request_stop (line 87) | def request_stop(self) -> None:
method should_stop (line 91) | def should_stop(self) -> bool:
method is_waiting_for_input (line 94) | def is_waiting_for_input(self) -> bool:
method enter_waiting_state (line 97) | def enter_waiting_state(self, llm_failed: bool = False) -> None:
method resume_from_waiting (line 103) | def resume_from_waiting(self, new_task: str | None = None) -> None:
method has_reached_max_iterations (line 113) | def has_reached_max_iterations(self) -> bool:
method is_approaching_max_iterations (line 116) | def is_approaching_max_iterations(self, threshold: float = 0.85) -> bool:
method has_waiting_timeout (line 119) | def has_waiting_timeout(self) -> bool:
method has_empty_last_messages (line 137) | def has_empty_last_messages(self, count: int = 3) -> bool:
method get_conversation_history (line 150) | def get_conversation_history(self) -> list[dict[str, Any]]:
method get_execution_summary (line 153) | def get_execution_summary(self) -> dict[str, Any]:
FILE: strix/config/config.py
class Config (line 11) | class Config:
method _tracked_names (line 60) | def _tracked_names(cls) -> list[str]:
method tracked_vars (line 68) | def tracked_vars(cls) -> list[str]:
method _llm_env_vars (line 72) | def _llm_env_vars(cls) -> set[str]:
method _llm_env_changed (line 76) | def _llm_env_changed(cls, saved_env: dict[str, Any]) -> bool:
method get (line 86) | def get(cls, name: str) -> str | None:
method config_dir (line 92) | def config_dir(cls) -> Path:
method config_file (line 96) | def config_file(cls) -> Path:
method load (line 102) | def load(cls) -> dict[str, Any]:
method save (line 114) | def save(cls, config: dict[str, Any]) -> bool:
method apply_saved (line 127) | def apply_saved(cls, force: bool = False) -> dict[str, str]:
method capture_current (line 157) | def capture_current(cls) -> dict[str, Any]:
method save_current (line 166) | def save_current(cls) -> bool:
function apply_saved_config (line 182) | def apply_saved_config(force: bool = False) -> dict[str, str]:
function save_current_config (line 186) | def save_current_config() -> bool:
function resolve_llm_config (line 190) | def resolve_llm_config() -> tuple[str | None, str | None, str | None]:
FILE: strix/interface/cli.py
function run_cli (line 23) | async def run_cli(args: Any) -> None: # noqa: PLR0915
FILE: strix/interface/main.py
function validate_environment (line 51) | def validate_environment() -> None: # noqa: PLR0912, PLR0915
function check_docker_installed (line 186) | def check_docker_installed() -> None:
function warm_up_llm (line 208) | async def warm_up_llm() -> None:
function get_version (line 259) | def get_version() -> str:
function parse_arguments (line 268) | def parse_arguments() -> argparse.Namespace:
function display_completion_message (line 408) | def display_completion_message(args: argparse.Namespace, results_path: P...
function pull_docker_image (line 466) | def pull_docker_image() -> None:
function apply_config_override (line 510) | def apply_config_override(config_path: str) -> None:
function persist_config (line 515) | def persist_config() -> None:
function main (line 520) | def main() -> None:
FILE: strix/interface/streaming_parser.py
function _get_safe_content (line 18) | def _get_safe_content(content: str) -> tuple[str, str]:
class StreamSegment (line 35) | class StreamSegment:
function parse_streaming_content (line 43) | def parse_streaming_content(content: str) -> list[StreamSegment]:
function _parse_streaming_params (line 106) | def _parse_streaming_params(func_body: str) -> dict[str, str]:
FILE: strix/interface/tool_components/agent_message_renderer.py
function _get_style_colors (line 25) | def _get_style_colors() -> dict[Any, str]:
function _get_token_color (line 30) | def _get_token_color(token_type: Any) -> str | None:
function _highlight_code (line 39) | def _highlight_code(code: str, language: str | None = None) -> Text:
function _try_parse_header (line 57) | def _try_parse_header(line: str) -> tuple[str, str] | None:
function _apply_markdown_styles (line 64) | def _apply_markdown_styles(text: str) -> Text: # noqa: PLR0912
function _process_inline_formatting (line 120) | def _process_inline_formatting(line: str) -> Text:
class AgentMessageRenderer (line 164) | class AgentMessageRenderer(BaseToolRenderer):
method render (line 169) | def render(cls, tool_data: dict[str, Any]) -> Static:
method render_simple (line 180) | def render_simple(cls, content: str) -> Text:
FILE: strix/interface/tool_components/agents_graph_renderer.py
class ViewAgentGraphRenderer (line 11) | class ViewAgentGraphRenderer(BaseToolRenderer):
method render (line 16) | def render(cls, tool_data: dict[str, Any]) -> Static:
class CreateAgentRenderer (line 28) | class CreateAgentRenderer(BaseToolRenderer):
method render (line 33) | def render(cls, tool_data: dict[str, Any]) -> Static:
class SendMessageToAgentRenderer (line 54) | class SendMessageToAgentRenderer(BaseToolRenderer):
method render (line 59) | def render(cls, tool_data: dict[str, Any]) -> Static:
class AgentFinishRenderer (line 82) | class AgentFinishRenderer(BaseToolRenderer):
method render (line 87) | def render(cls, tool_data: dict[str, Any]) -> Static:
class WaitForMessageRenderer (line 120) | class WaitForMessageRenderer(BaseToolRenderer):
method render (line 125) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/base_renderer.py
class BaseToolRenderer (line 8) | class BaseToolRenderer(ABC):
method render (line 14) | def render(cls, tool_data: dict[str, Any]) -> Static:
method build_text (line 18) | def build_text(cls, tool_data: dict[str, Any]) -> Text: # noqa: ARG003
method create_static (line 22) | def create_static(cls, content: Text, status: str) -> Static:
method status_icon (line 27) | def status_icon(cls, status: str) -> tuple[str, str]:
method get_css_classes (line 37) | def get_css_classes(cls, status: str) -> str:
method text_with_style (line 43) | def text_with_style(cls, content: str, style: str | None = None) -> Text:
method text_icon_label (line 49) | def text_icon_label(
method text_header (line 63) | def text_header(
method text_key_value (line 81) | def text_key_value(
FILE: strix/interface/tool_components/browser_renderer.py
function _get_style_colors (line 14) | def _get_style_colors() -> dict[Any, str]:
class BrowserRenderer (line 20) | class BrowserRenderer(BaseToolRenderer):
method _get_token_color (line 41) | def _get_token_color(cls, token_type: Any) -> str | None:
method _highlight_js (line 50) | def _highlight_js(cls, code: str) -> Text:
method render (line 63) | def render(cls, tool_data: dict[str, Any]) -> Static:
method _build_url_action (line 74) | def _build_url_action(cls, text: Text, label: str, url: str | None, su...
method _build_content (line 82) | def _build_content(cls, action: str, args: dict[str, Any]) -> Text:
FILE: strix/interface/tool_components/file_edit_renderer.py
function _get_style_colors (line 15) | def _get_style_colors() -> dict[Any, str]:
function _get_lexer_for_file (line 20) | def _get_lexer_for_file(path: str) -> Any:
class StrReplaceEditorRenderer (line 28) | class StrReplaceEditorRenderer(BaseToolRenderer):
method _get_token_color (line 33) | def _get_token_color(cls, token_type: Any) -> str | None:
method _highlight_code (line 42) | def _highlight_code(cls, code: str, path: str) -> Text:
method render (line 55) | def render(cls, tool_data: dict[str, Any]) -> Static:
class ListFilesRenderer (line 125) | class ListFilesRenderer(BaseToolRenderer):
method render (line 130) | def render(cls, tool_data: dict[str, Any]) -> Static:
class SearchFilesRenderer (line 150) | class SearchFilesRenderer(BaseToolRenderer):
method render (line 155) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/finish_renderer.py
class FinishScanRenderer (line 14) | class FinishScanRenderer(BaseToolRenderer):
method render (line 19) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/load_skill_renderer.py
class LoadSkillRenderer (line 11) | class LoadSkillRenderer(BaseToolRenderer):
method render (line 16) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/notes_renderer.py
class CreateNoteRenderer (line 11) | class CreateNoteRenderer(BaseToolRenderer):
method render (line 16) | def render(cls, tool_data: dict[str, Any]) -> Static:
class DeleteNoteRenderer (line 46) | class DeleteNoteRenderer(BaseToolRenderer):
method render (line 51) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: ARG003
class UpdateNoteRenderer (line 61) | class UpdateNoteRenderer(BaseToolRenderer):
method render (line 66) | def render(cls, tool_data: dict[str, Any]) -> Static:
class ListNotesRenderer (line 93) | class ListNotesRenderer(BaseToolRenderer):
method render (line 98) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/proxy_renderer.py
function _truncate (line 15) | def _truncate(text: str, max_len: int = 80) -> str:
function _sanitize (line 19) | def _sanitize(text: str, max_len: int = 150) -> str:
function _status_style (line 25) | def _status_style(code: int | None) -> str:
class ListRequestsRenderer (line 40) | class ListRequestsRenderer(BaseToolRenderer):
method render (line 45) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912...
class ViewRequestRenderer (line 113) | class ViewRequestRenderer(BaseToolRenderer):
method render (line 118) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912...
class SendRequestRenderer (line 199) | class SendRequestRenderer(BaseToolRenderer):
method render (line 204) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912...
class RepeatRequestRenderer (line 273) | class RepeatRequestRenderer(BaseToolRenderer):
method render (line 278) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912...
class ScopeRulesRenderer (line 375) | class ScopeRulesRenderer(BaseToolRenderer):
method render (line 380) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912...
class ListSitemapRenderer (line 465) | class ListSitemapRenderer(BaseToolRenderer):
method render (line 470) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912...
class ViewSitemapEntryRenderer (line 549) | class ViewSitemapEntryRenderer(BaseToolRenderer):
method render (line 554) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912
FILE: strix/interface/tool_components/python_renderer.py
function _get_style_colors (line 25) | def _get_style_colors() -> dict[Any, str]:
function _get_lexer (line 31) | def _get_lexer() -> PythonLexer:
function _get_token_color (line 36) | def _get_token_color(token_type: Any) -> str | None:
class PythonRenderer (line 46) | class PythonRenderer(BaseToolRenderer):
method _highlight_python (line 51) | def _highlight_python(cls, code: str) -> Text:
method _clean_output (line 59) | def _clean_output(cls, output: str) -> str:
method _strip_ansi (line 66) | def _strip_ansi(cls, text: str) -> str:
method _truncate_line (line 70) | def _truncate_line(cls, line: str) -> str:
method _format_output (line 77) | def _format_output(cls, output: str) -> Text:
method _append_output (line 115) | def _append_output(cls, text: Text, result: dict[str, Any] | str) -> N...
method render (line 131) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/registry.py
class ToolTUIRegistry (line 9) | class ToolTUIRegistry:
method register (line 13) | def register(cls, renderer_class: type[BaseToolRenderer]) -> None:
method get_renderer (line 20) | def get_renderer(cls, tool_name: str) -> type[BaseToolRenderer] | None:
method list_tools (line 24) | def list_tools(cls) -> list[str]:
method has_renderer (line 28) | def has_renderer(cls, tool_name: str) -> bool:
function register_tool_renderer (line 32) | def register_tool_renderer(renderer_class: type[BaseToolRenderer]) -> ty...
function get_tool_renderer (line 37) | def get_tool_renderer(tool_name: str) -> type[BaseToolRenderer] | None:
function render_tool_widget (line 41) | def render_tool_widget(tool_data: dict[str, Any]) -> Static:
function _render_default_tool_widget (line 50) | def _render_default_tool_widget(tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/reporting_renderer.py
function _get_style_colors (line 19) | def _get_style_colors() -> dict[Any, str]:
class CreateVulnerabilityReportRenderer (line 35) | class CreateVulnerabilityReportRenderer(BaseToolRenderer):
method _get_token_color (line 48) | def _get_token_color(cls, token_type: Any) -> str | None:
method _highlight_python (line 57) | def _highlight_python(cls, code: str) -> Text:
method _get_cvss_color (line 70) | def _get_cvss_color(cls, cvss_score: float) -> str:
method render (line 82) | def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: PLR0912...
FILE: strix/interface/tool_components/scan_info_renderer.py
class ScanStartInfoRenderer (line 11) | class ScanStartInfoRenderer(BaseToolRenderer):
method render (line 16) | def render(cls, tool_data: dict[str, Any]) -> Static:
method _get_target_display (line 38) | def _get_target_display(cls, target_info: dict[str, Any]) -> str:
class SubagentStartInfoRenderer (line 46) | class SubagentStartInfoRenderer(BaseToolRenderer):
method render (line 51) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/terminal_renderer.py
function _get_style_colors (line 32) | def _get_style_colors() -> dict[Any, str]:
class TerminalRenderer (line 38) | class TerminalRenderer(BaseToolRenderer):
method _get_token_color (line 106) | def _get_token_color(cls, token_type: Any) -> str | None:
method _highlight_bash (line 115) | def _highlight_bash(cls, code: str) -> Text:
method render (line 128) | def render(cls, tool_data: dict[str, Any]) -> Static:
method _build_content (line 142) | def _build_content(
method _clean_output (line 182) | def _clean_output(cls, output: str, command: str = "") -> str:
method _append_output (line 210) | def _append_output(
method _is_status_message (line 253) | def _is_status_message(cls, message: str) -> bool:
method _format_output (line 265) | def _format_output(cls, output: str) -> Text:
method _truncate_line (line 303) | def _truncate_line(cls, line: str) -> str:
method _format_command (line 310) | def _format_command(cls, command: str) -> Text:
FILE: strix/interface/tool_components/thinking_renderer.py
class ThinkRenderer (line 11) | class ThinkRenderer(BaseToolRenderer):
method render (line 16) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/todo_renderer.py
function _format_todo_lines (line 17) | def _format_todo_lines(text: Text, result: dict[str, Any]) -> None:
class CreateTodoRenderer (line 43) | class CreateTodoRenderer(BaseToolRenderer):
method render (line 48) | def render(cls, tool_data: dict[str, Any]) -> Static:
class ListTodosRenderer (line 74) | class ListTodosRenderer(BaseToolRenderer):
method render (line 79) | def render(cls, tool_data: dict[str, Any]) -> Static:
class UpdateTodoRenderer (line 105) | class UpdateTodoRenderer(BaseToolRenderer):
method render (line 110) | def render(cls, tool_data: dict[str, Any]) -> Static:
class MarkTodoDoneRenderer (line 136) | class MarkTodoDoneRenderer(BaseToolRenderer):
method render (line 141) | def render(cls, tool_data: dict[str, Any]) -> Static:
class MarkTodoPendingRenderer (line 167) | class MarkTodoPendingRenderer(BaseToolRenderer):
method render (line 172) | def render(cls, tool_data: dict[str, Any]) -> Static:
class DeleteTodoRenderer (line 198) | class DeleteTodoRenderer(BaseToolRenderer):
method render (line 203) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tool_components/user_message_renderer.py
class UserMessageRenderer (line 11) | class UserMessageRenderer(BaseToolRenderer):
method render (line 16) | def render(cls, tool_data: dict[str, Any]) -> Static:
method render_simple (line 27) | def render_simple(cls, content: str) -> Text:
method _format_user_message (line 34) | def _format_user_message(cls, content: str) -> Text:
FILE: strix/interface/tool_components/web_search_renderer.py
class WebSearchRenderer (line 11) | class WebSearchRenderer(BaseToolRenderer):
method render (line 16) | def render(cls, tool_data: dict[str, Any]) -> Static:
FILE: strix/interface/tui.py
function get_package_version (line 44) | def get_package_version() -> str:
class ChatTextArea (line 51) | class ChatTextArea(TextArea): # type: ignore[misc]
method __init__ (line 52) | def __init__(self, *args: Any, **kwargs: Any) -> None:
method set_app_reference (line 56) | def set_app_reference(self, app: "StrixTUIApp") -> None:
method on_mount (line 59) | def on_mount(self) -> None:
method _on_key (line 62) | def _on_key(self, event: events.Key) -> None:
method _update_height (line 82) | def _update_height(self, _event: TextArea.Changed | None = None) -> None:
class SplashScreen (line 96) | class SplashScreen(Static): # type: ignore[misc]
method __init__ (line 108) | def __init__(self, *args: Any, **kwargs: Any) -> None:
method compose (line 115) | def compose(self) -> ComposeResult:
method on_mount (line 125) | def on_mount(self) -> None:
method on_unmount (line 128) | def on_unmount(self) -> None:
method _animate_start_line (line 133) | def _animate_start_line(self) -> None:
method _build_panel (line 142) | def _build_panel(self, start_line: Text) -> Panel:
method _build_url_text (line 157) | def _build_url_text(self) -> Text:
method _build_welcome_text (line 160) | def _build_welcome_text(self) -> Text:
method _build_version_text (line 166) | def _build_version_text(self) -> Text:
method _build_tagline_text (line 169) | def _build_tagline_text(self) -> Text:
method _build_start_line_text (line 172) | def _build_start_line_text(self, phase: int) -> Text:
class HelpScreen (line 196) | class HelpScreen(ModalScreen): # type: ignore[misc]
method compose (line 197) | def compose(self) -> ComposeResult:
method on_key (line 208) | def on_key(self, _event: events.Key) -> None:
class StopAgentScreen (line 212) | class StopAgentScreen(ModalScreen): # type: ignore[misc]
method __init__ (line 213) | def __init__(self, agent_name: str, agent_id: str):
method compose (line 218) | def compose(self) -> ComposeResult:
method on_mount (line 229) | def on_mount(self) -> None:
method on_key (line 233) | def on_key(self, event: events.Key) -> None:
method on_button_pressed (line 254) | def on_button_pressed(self, event: Button.Pressed) -> None:
class VulnerabilityDetailScreen (line 260) | class VulnerabilityDetailScreen(ModalScreen): # type: ignore[misc]
method __init__ (line 273) | def __init__(self, vulnerability: dict[str, Any]) -> None:
method compose (line 277) | def compose(self) -> ComposeResult:
method on_mount (line 289) | def on_mount(self) -> None:
method _get_cvss_color (line 293) | def _get_cvss_color(self, cvss_score: float) -> str:
method _highlight_python (line 304) | def _highlight_python(self, code: str) -> Text:
method _render_vulnerability (line 332) | def _render_vulnerability(self) -> Text: # noqa: PLR0912, PLR0915
method _get_markdown_report (line 458) | def _get_markdown_report(self) -> str: # noqa: PLR0912, PLR0915
method on_key (line 565) | def on_key(self, event: events.Key) -> None:
method on_button_pressed (line 570) | def on_button_pressed(self, event: Button.Pressed) -> None:
class VulnerabilityItem (line 582) | class VulnerabilityItem(Static): # type: ignore[misc]
method __init__ (line 585) | def __init__(self, label: Text, vuln_data: dict[str, Any], **kwargs: A...
method on_click (line 589) | def on_click(self, _event: events.Click) -> None:
class VulnerabilitiesPanel (line 594) | class VulnerabilitiesPanel(VerticalScroll): # type: ignore[misc]
method __init__ (line 605) | def __init__(self, *args: Any, **kwargs: Any) -> None:
method compose (line 609) | def compose(self) -> ComposeResult:
method update_vulnerabilities (line 612) | def update_vulnerabilities(self, vulnerabilities: list[dict[str, Any]]...
method _render_panel (line 619) | def _render_panel(self) -> None:
class QuitScreen (line 641) | class QuitScreen(ModalScreen): # type: ignore[misc]
method compose (line 642) | def compose(self) -> ComposeResult:
method on_mount (line 653) | def on_mount(self) -> None:
method on_key (line 657) | def on_key(self, event: events.Key) -> None:
method on_button_pressed (line 678) | def on_button_pressed(self, event: Button.Pressed) -> None:
class StrixTUIApp (line 685) | class StrixTUIApp(App): # type: ignore[misc]
method __init__ (line 701) | def __init__(self, args: argparse.Namespace):
method _build_scan_config (line 739) | def _build_scan_config(self, args: argparse.Namespace) -> dict[str, Any]:
method _build_agent_config (line 747) | def _build_agent_config(self, args: argparse.Namespace) -> dict[str, A...
method _setup_cleanup_handlers (line 761) | def _setup_cleanup_handlers(self) -> None:
method compose (line 778) | def compose(self) -> ComposeResult:
method watch_show_splash (line 782) | def watch_show_splash(self, show_splash: bool) -> None:
method _focus_chat_input (line 846) | def _focus_chat_input(self) -> None:
method _focus_agents_tree (line 861) | def _focus_agents_tree(self) -> None:
method on_mount (line 878) | def on_mount(self) -> None:
method _hide_splash_screen (line 883) | def _hide_splash_screen(self) -> None:
method _update_ui_from_tracer (line 890) | def _update_ui_from_tracer(self) -> None:
method _update_agent_node (line 929) | def _update_agent_node(self, agent_id: str, agent_data: dict[str, Any]...
method _get_chat_content (line 964) | def _get_chat_content(
method _update_chat_view (line 994) | def _update_chat_view(self) -> None:
method _get_chat_placeholder_content (line 1022) | def _get_chat_placeholder_content(
method _merge_renderables (line 1031) | def _merge_renderables(renderables: list[Any]) -> Text:
method _sanitize_text (line 1041) | def _sanitize_text(text: Text) -> Text:
method _append_renderable (line 1065) | def _append_renderable(combined: Text, item: Any) -> None:
method _get_rendered_events_content (line 1081) | def _get_rendered_events_content(self, events: list[dict[str, Any]]) -...
method _render_streaming_content (line 1117) | def _render_streaming_content(self, content: str, agent_id: str | None...
method _render_streaming_tool (line 1156) | def _render_streaming_tool(
method _render_default_streaming_tool (line 1173) | def _render_default_streaming_tool(
method _get_status_display_content (line 1196) | def _get_status_display_content(
method _update_agent_status_display (line 1253) | def _update_agent_status_display(self) -> None:
method _update_stats_display (line 1289) | def _update_stats_display(self) -> None:
method _update_vulnerabilities_panel (line 1312) | def _update_vulnerabilities_panel(self) -> None:
method _get_agent_name_for_vulnerability (line 1340) | def _get_agent_name_for_vulnerability(self, report_id: str) -> str | N...
method _get_sweep_animation (line 1352) | def _get_sweep_animation(self, color_palette: list[str]) -> Text:
method _get_animated_verb_text (line 1381) | def _get_animated_verb_text(self, agent_id: str, verb: str) -> Text: ...
method _start_dot_animation (line 1392) | def _start_dot_animation(self) -> None:
method _stop_dot_animation (line 1396) | def _stop_dot_animation(self) -> None:
method _animate_dots (line 1401) | def _animate_dots(self) -> None:
method _agent_has_real_activity (line 1427) | def _agent_has_real_activity(self, agent_id: str) -> bool:
method _agent_vulnerability_count (line 1439) | def _agent_vulnerability_count(self, agent_id: str) -> int:
method _gather_agent_events (line 1452) | def _gather_agent_events(self, agent_id: str) -> list[dict[str, Any]]:
method watch_selected_agent_id (line 1479) | def watch_selected_agent_id(self, _agent_id: str | None) -> None:
method _start_scan_thread (line 1493) | def _start_scan_thread(self) -> None:
method _add_agent_node (line 1524) | def _add_agent_node(self, agent_data: dict[str, Any]) -> None:
method _expand_new_agent_nodes (line 1585) | def _expand_new_agent_nodes(self) -> None:
method _expand_all_agent_nodes (line 1592) | def _expand_all_agent_nodes(self) -> None:
method _expand_node_recursively (line 1605) | def _expand_node_recursively(self, node: TreeNode) -> None:
method _copy_node_under (line 1611) | def _copy_node_under(self, node_to_copy: TreeNode, new_parent: TreeNod...
method _reorganize_orphaned_agents (line 1646) | def _reorganize_orphaned_agents(self, new_parent_id: str) -> None:
method _render_chat_content (line 1676) | def _render_chat_content(self, msg_data: dict[str, Any]) -> Any:
method _render_tool_content_simple (line 1697) | def _render_tool_content_simple(self, tool_data: dict[str, Any]) -> Any:
method _render_error_details (line 1747) | def _render_error_details(self, text: Any, tool_name: str, args: dict[...
method handle_tree_highlight (line 1763) | def handle_tree_highlight(self, event: Tree.NodeHighlighted) -> None:
method handle_tree_node_selected (line 1783) | def handle_tree_node_selected(self, event: Tree.NodeSelected) -> None:
method _send_user_message (line 1798) | def _send_user_message(self, message: str) -> None:
method _get_agent_name (line 1846) | def _get_agent_name(self, agent_id: str) -> str:
method action_toggle_help (line 1856) | def action_toggle_help(self) -> None:
method action_request_quit (line 1874) | def action_request_quit(self) -> None:
method action_stop_selected_agent (line 1890) | def action_stop_selected_agent(self) -> None:
method _validate_agent_for_stopping (line 1912) | def _validate_agent_for_stopping(self) -> tuple[str, bool]:
method action_confirm_stop_agent (line 1937) | def action_confirm_stop_agent(self, agent_id: str) -> None:
method action_custom_quit (line 1955) | def action_custom_quit(self) -> None:
method _is_widget_safe (line 1965) | def _is_widget_safe(self, widget: Any) -> bool:
method _safe_widget_operation (line 1973) | def _safe_widget_operation(
method on_resize (line 1983) | def on_resize(self, event: events.Resize) -> None:
method on_mouse_up (line 2000) | def on_mouse_up(self, _event: events.MouseUp) -> None:
method _clean_copied_text (line 2040) | def _clean_copied_text(text: str) -> str:
method _auto_copy_selection (line 2058) | def _auto_copy_selection(self) -> None:
function run_tui (line 2087) | async def run_tui(args: argparse.Namespace) -> None:
FILE: strix/interface/utils.py
function format_token_count (line 23) | def format_token_count(count: float) -> str:
function get_severity_color (line 33) | def get_severity_color(severity: str) -> str:
function get_cvss_color (line 44) | def get_cvss_color(cvss_score: float) -> str:
function format_vulnerability_report (line 56) | def format_vulnerability_report(report: dict[str, Any]) -> Text: # noqa...
function _build_vulnerability_stats (line 205) | def _build_vulnerability_stats(stats_text: Text, tracer: Any) -> None:
function _build_llm_stats (line 244) | def _build_llm_stats(stats_text: Text, total_stats: dict[str, Any]) -> N...
function build_final_stats_text (line 273) | def build_final_stats_text(tracer: Any) -> Text:
function build_live_stats_text (line 298) | def build_live_stats_text(tracer: Any, agent_config: dict[str, Any] | No...
function build_tui_stats_text (line 371) | def build_tui_stats_text(tracer: Any, agent_config: dict[str, Any] | Non...
function _slugify_for_run_name (line 405) | def _slugify_for_run_name(text: str, max_length: int = 32) -> str:
function _derive_target_label_for_run_name (line 414) | def _derive_target_label_for_run_name(targets_info: list[dict[str, Any]]...
function generate_run_name (line 453) | def generate_run_name(targets_info: list[dict[str, Any]] | None = None) ...
function _is_http_git_repo (line 465) | def _is_http_git_repo(url: str) -> bool:
function infer_target_type (line 477) | def infer_target_type(target: str) -> tuple[str, dict[str, str]]: # noq...
function sanitize_name (line 545) | def sanitize_name(name: str) -> str:
function derive_repo_base_name (line 550) | def derive_repo_base_name(repo_url: str) -> str:
function derive_local_base_name (line 566) | def derive_local_base_name(path_str: str) -> str:
function assign_workspace_subdirs (line 574) | def assign_workspace_subdirs(targets_info: list[dict[str, Any]]) -> None:
function collect_local_sources (line 598) | def collect_local_sources(targets_info: list[dict[str, Any]]) -> list[di...
function _is_localhost_host (line 624) | def _is_localhost_host(host: str) -> bool:
function rewrite_localhost_targets (line 642) | def rewrite_localhost_targets(targets_info: list[dict[str, Any]], host_g...
function clone_repository (line 666) | def clone_repository(repo_url: str, run_name: str, dest_name: str | None...
function check_docker_connection (line 743) | def check_docker_connection() -> Any:
function image_exists (line 768) | def image_exists(client: Any, image_name: str) -> bool:
function update_layer_status (line 777) | def update_layer_status(layers_info: dict[str, str], layer_id: str, laye...
function process_pull_line (line 790) | def process_pull_line(
function validate_llm_response (line 819) | def validate_llm_response(response: Any) -> None:
function validate_config_file (line 824) | def validate_config_file(config_path: str) -> Path:
FILE: strix/llm/config.py
class LLMConfig (line 6) | class LLMConfig:
method __init__ (line 7) | def __init__(
FILE: strix/llm/dedupe.py
function _prepare_report_for_comparison (line 79) | def _prepare_report_for_comparison(report: dict[str, Any]) -> dict[str, ...
function _extract_xml_field (line 103) | def _extract_xml_field(content: str, field: str) -> str:
function _parse_dedupe_response (line 111) | def _parse_dedupe_response(content: str) -> dict[str, Any]:
function check_duplicate (line 142) | def check_duplicate(
FILE: strix/llm/llm.py
class LLMRequestFailedError (line 29) | class LLMRequestFailedError(Exception):
method __init__ (line 30) | def __init__(self, message: str, details: str | None = None):
class LLMResponse (line 37) | class LLMResponse:
class RequestStats (line 44) | class RequestStats:
method to_dict (line 51) | def to_dict(self) -> dict[str, int | float]:
class LLM (line 61) | class LLM:
method __init__ (line 62) | def __init__(self, config: LLMConfig, agent_name: str | None = None):
method _load_system_prompt (line 79) | def _load_system_prompt(self, agent_name: str | None) -> str:
method _get_skills_to_load (line 105) | def _get_skills_to_load(self) -> list[str]:
method add_skills (line 118) | def add_skills(self, skill_names: list[str]) -> list[str]:
method set_agent_identity (line 135) | def set_agent_identity(self, agent_name: str | None, agent_id: str | N...
method generate (line 141) | async def generate(
method _stream (line 158) | async def _stream(self, messages: list[dict[str, Any]]) -> AsyncIterat...
method _prepare_messages (line 196) | def _prepare_messages(self, conversation_history: list[dict[str, Any]]...
method _build_completion_args (line 226) | def _build_completion_args(self, messages: list[dict[str, Any]]) -> di...
method _get_chunk_content (line 246) | def _get_chunk_content(self, chunk: Any) -> str:
method _extract_thinking (line 251) | def _extract_thinking(self, chunks: list[Any]) -> list[dict[str, Any]]...
method _update_usage_stats (line 263) | def _update_usage_stats(self, response: Any) -> None:
method _extract_cost (line 290) | def _extract_cost(self, response: Any) -> float:
method _should_retry (line 302) | def _should_retry(self, e: Exception) -> bool:
method _raise_error (line 308) | def _raise_error(self, e: Exception) -> None:
method _is_anthropic (line 314) | def _is_anthropic(self) -> bool:
method _supports_vision (line 319) | def _supports_vision(self) -> bool:
method _supports_reasoning (line 325) | def _supports_reasoning(self) -> bool:
method _strip_images (line 331) | def _strip_images(self, messages: list[dict[str, Any]]) -> list[dict[s...
method _add_cache_control (line 347) | def _add_cache_control(self, messages: list[dict[str, Any]]) -> list[d...
FILE: strix/llm/memory_compressor.py
function _count_tokens (line 46) | def _count_tokens(text: str, model: str) -> int:
function _get_message_tokens (line 55) | def _get_message_tokens(msg: dict[str, Any], model: str) -> int:
function _extract_message_text (line 68) | def _extract_message_text(msg: dict[str, Any]) -> str:
function _summarize_messages (line 86) | def _summarize_messages(
function _handle_images (line 134) | def _handle_images(messages: list[dict[str, Any]], max_images: int) -> N...
class MemoryCompressor (line 152) | class MemoryCompressor:
method __init__ (line 153) | def __init__(
method compress_history (line 166) | def compress_history(
FILE: strix/llm/utils.py
function normalize_tool_format (line 12) | def normalize_tool_format(content: str) -> str:
function resolve_strix_model (line 47) | def resolve_strix_model(model_name: str | None) -> tuple[str | None, str...
function _truncate_to_first_function (line 64) | def _truncate_to_first_function(content: str) -> str:
function parse_tool_invocations (line 80) | def parse_tool_invocations(content: str) -> list[dict[str, Any]] | None:
function fix_incomplete_tool_call (line 110) | def fix_incomplete_tool_call(content: str) -> str:
function format_tool_call (line 124) | def format_tool_call(tool_name: str, args: dict[str, Any]) -> str:
function clean_content (line 135) | def clean_content(content: str) -> str:
FILE: strix/runtime/__init__.py
class SandboxInitializationError (line 6) | class SandboxInitializationError(Exception):
method __init__ (line 9) | def __init__(self, message: str, details: str | None = None):
function get_runtime (line 18) | def get_runtime() -> AbstractRuntime:
function cleanup_runtime (line 35) | def cleanup_runtime() -> None:
FILE: strix/runtime/docker_runtime.py
class DockerRuntime (line 28) | class DockerRuntime(AbstractRuntime):
method __init__ (line 29) | def __init__(self) -> None:
method _find_available_port (line 43) | def _find_available_port(self) -> int:
method _get_scan_id (line 48) | def _get_scan_id(self, agent_id: str) -> str:
method _verify_image_available (line 59) | def _verify_image_available(self, image_name: str, max_retries: int = ...
method _recover_container_state (line 72) | def _recover_container_state(self, container: Container) -> None:
method _wait_for_tool_server (line 87) | def _wait_for_tool_server(self, max_retries: int = 30, timeout: int = ...
method _create_container (line 111) | def _create_container(self, scan_id: str, max_retries: int = 2) -> Con...
method _get_or_create_container (line 175) | def _get_or_create_container(self, scan_id: str) -> Container:
method _copy_local_directory_to_container (line 222) | def _copy_local_directory_to_container(
method create_sandbox (line 250) | async def create_sandbox(
method _register_agent (line 292) | async def _register_agent(self, api_url: str, agent_id: str, token: st...
method get_sandbox_url (line 305) | async def get_sandbox_url(self, container_id: str, port: int) -> str:
method _resolve_docker_host (line 312) | def _resolve_docker_host(self) -> str:
method destroy_sandbox (line 322) | async def destroy_sandbox(self, container_id: str) -> None:
method cleanup (line 334) | def cleanup(self) -> None:
FILE: strix/runtime/runtime.py
class SandboxInfo (line 5) | class SandboxInfo(TypedDict):
class AbstractRuntime (line 14) | class AbstractRuntime(ABC):
method create_sandbox (line 16) | async def create_sandbox(
method get_sandbox_url (line 25) | async def get_sandbox_url(self, container_id: str, port: int) -> str:
method destroy_sandbox (line 29) | async def destroy_sandbox(self, container_id: str) -> None:
method cleanup (line 32) | def cleanup(self) -> None:
FILE: strix/runtime/tool_server.py
function verify_token (line 42) | def verify_token(credentials: HTTPAuthorizationCredentials) -> str:
class ToolExecutionRequest (line 60) | class ToolExecutionRequest(BaseModel):
class ToolExecutionResponse (line 66) | class ToolExecutionResponse(BaseModel):
function _run_tool (line 71) | async def _run_tool(agent_id: str, tool_name: str, kwargs: dict[str, Any...
function execute_tool (line 87) | async def execute_tool(
function register_agent (line 131) | async def register_agent(
function health_check (line 139) | async def health_check() -> dict[str, Any]:
function signal_handler (line 150) | def signal_handler(_signum: int, _frame: Any) -> None:
FILE: strix/skills/__init__.py
function get_available_skills (line 10) | def get_available_skills() -> dict[str, list[str]]:
function get_all_skill_names (line 36) | def get_all_skill_names() -> set[str]:
function validate_skill_names (line 43) | def validate_skill_names(skill_names: list[str]) -> dict[str, list[str]]:
function parse_skill_list (line 57) | def parse_skill_list(skills: str | None) -> list[str]:
function validate_requested_skills (line 63) | def validate_requested_skills(skill_list: list[str], max_skills: int = 5...
function generate_skills_description (line 81) | def generate_skills_description() -> str:
function _get_all_categories (line 105) | def _get_all_categories() -> dict[str, list[str]]:
function load_skills (line 128) | def load_skills(skill_names: list[str]) -> dict[str, str]:
FILE: strix/telemetry/flags.py
function _is_enabled (line 7) | def _is_enabled(raw_value: str | None, default: str = "1") -> bool:
function is_otel_enabled (line 12) | def is_otel_enabled() -> bool:
function is_posthog_enabled (line 19) | def is_posthog_enabled() -> bool:
FILE: strix/telemetry/posthog.py
function _is_enabled (line 21) | def _is_enabled() -> bool:
function _is_first_run (line 25) | def _is_first_run() -> bool:
function _get_version (line 37) | def _get_version() -> str:
function _send (line 46) | def _send(event: str, properties: dict[str, Any]) -> None:
function _base_props (line 67) | def _base_props() -> dict[str, Any]:
function start (line 76) | def start(
function finding (line 97) | def finding(severity: str) -> None:
function end (line 107) | def end(tracer: "Tracer", exit_reason: str = "completed") -> None:
function error (line 133) | def error(error_type: str, error_msg: str | None = None) -> None:
FILE: strix/telemetry/tracer.py
function get_global_tracer (line 39) | def get_global_tracer() -> Optional["Tracer"]:
function set_global_tracer (line 43) | def set_global_tracer(tracer: "Tracer") -> None:
class Tracer (line 48) | class Tracer:
method __init__ (line 49) | def __init__(self, run_name: str | None = None):
method events_file_path (line 93) | def events_file_path(self) -> Path:
method _active_events_file_path (line 98) | def _active_events_file_path(self) -> Path:
method _get_events_write_lock (line 104) | def _get_events_write_lock(self, output_path: Path | None = None) -> t...
method _active_run_metadata (line 108) | def _active_run_metadata(self) -> dict[str, Any]:
method _setup_telemetry (line 114) | def _setup_telemetry(self) -> None:
method _set_association_properties (line 148) | def _set_association_properties(self, properties: dict[str, Any]) -> N...
method _sanitize_data (line 157) | def _sanitize_data(self, data: Any, key_hint: str | None = None) -> Any:
method _append_event_record (line 160) | def _append_event_record(self, record: dict[str, Any]) -> None:
method _enrich_actor (line 166) | def _enrich_actor(self, actor: dict[str, Any] | None) -> dict[str, Any...
method _emit_event (line 185) | def _emit_event(
method set_run_name (line 268) | def set_run_name(self, run_name: str) -> None:
method _emit_run_started_event (line 279) | def _emit_run_started_event(self) -> None:
method get_run_dir (line 295) | def get_run_dir(self) -> Path:
method add_vulnerability_report (line 306) | def add_vulnerability_report( # noqa: PLR0912
method get_existing_vulnerabilities (line 379) | def get_existing_vulnerabilities(self) -> list[dict[str, Any]]:
method update_scan_final_fields (line 382) | def update_scan_final_fields(
method log_agent_creation (line 428) | def log_agent_creation(
method log_chat_message (line 455) | def log_chat_message(
method log_tool_execution_start (line 484) | def log_tool_execution_start(
method update_tool_execution (line 525) | def update_tool_execution(
method update_agent_status (line 567) | def update_agent_status(
method set_scan_config (line 588) | def set_scan_config(self, config: dict[str, Any]) -> None:
method save_run_data (line 612) | def save_run_data(self, mark_complete: bool = False) -> None:
method _calculate_duration (line 775) | def _calculate_duration(self) -> float:
method get_agent_tools (line 785) | def get_agent_tools(self, agent_id: str) -> list[dict[str, Any]]:
method get_real_tool_count (line 792) | def get_real_tool_count(self) -> int:
method get_total_llm_stats (line 799) | def get_total_llm_stats(self) -> dict[str, Any]:
method update_streaming_content (line 826) | def update_streaming_content(self, agent_id: str, content: str) -> None:
method clear_streaming_content (line 829) | def clear_streaming_content(self, agent_id: str) -> None:
method get_streaming_content (line 832) | def get_streaming_content(self, agent_id: str) -> str | None:
method finalize_streaming_as_interrupted (line 835) | def finalize_streaming_as_interrupted(self, agent_id: str) -> str | None:
method cleanup (line 849) | def cleanup(self) -> None:
FILE: strix/telemetry/utils.py
class _SecretFilth (line 57) | class _SecretFilth(Filth): # type: ignore[misc]
class _SecretTokenDetector (line 61) | class _SecretTokenDetector(RegexDetector): # type: ignore[misc]
class TelemetrySanitizer (line 67) | class TelemetrySanitizer:
method __init__ (line 68) | def __init__(self) -> None:
method sanitize (line 71) | def sanitize(self, data: Any, key_hint: str | None = None) -> Any: # ...
function format_trace_id (line 106) | def format_trace_id(trace_id: int | None) -> str | None:
function format_span_id (line 112) | def format_span_id(span_id: int | None) -> str | None:
function iso_from_unix_ns (line 118) | def iso_from_unix_ns(unix_ns: int | None) -> str | None:
function get_events_write_lock (line 128) | def get_events_write_lock(output_path: Path) -> threading.Lock:
function reset_events_write_locks (line 138) | def reset_events_write_locks() -> None:
function append_jsonl_record (line 143) | def append_jsonl_record(output_path: Path, record: dict[str, Any]) -> None:
function default_resource_attributes (line 149) | def default_resource_attributes() -> dict[str, str]:
function parse_traceloop_headers (line 156) | def parse_traceloop_headers(raw_headers: str) -> dict[str, str]:
function prune_otel_span_attributes (line 184) | def prune_otel_span_attributes(attributes: dict[str, Any]) -> dict[str, ...
class JsonlSpanExporter (line 207) | class JsonlSpanExporter(SpanExporter): # type: ignore[misc]
method __init__ (line 210) | def __init__(
method export (line 222) | def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
method shutdown (line 246) | def shutdown(self) -> None:
method force_flush (line 249) | def force_flush(self, timeout_millis: int = 30_000) -> bool: # noqa: ...
method _span_to_record (line 252) | def _span_to_record(
function bootstrap_otel (line 305) | def bootstrap_otel(
FILE: strix/tools/agents_graph/agents_graph_actions.py
function _run_agent_in_thread (line 24) | def _run_agent_in_thread(
function view_agent_graph (line 106) | def view_agent_graph(agent_state: Any) -> dict[str, Any]:
function create_agent (line 188) | def create_agent(
function send_message_to_agent (line 279) | def send_message_to_agent(
function agent_finish (line 350) | def agent_finish(
function stop_agent (line 463) | def stop_agent(agent_id: str) -> dict[str, Any]:
function send_user_message_to_agent (line 526) | def send_user_message_to_agent(agent_id: str, message: str) -> dict[str,...
function wait_for_message (line 572) | def wait_for_message(
FILE: strix/tools/argument_parser.py
class ArgumentConversionError (line 9) | class ArgumentConversionError(Exception):
method __init__ (line 10) | def __init__(self, message: str, param_name: str | None = None) -> None:
function convert_arguments (line 15) | def convert_arguments(func: Callable[..., Any], kwargs: dict[str, Any]) ...
function convert_string_to_type (line 50) | def convert_string_to_type(value: str, param_type: Any) -> Any:
function _convert_basic_types (line 71) | def _convert_basic_types(value: str, param_type: Any, origin: Any = None...
function _convert_to_bool (line 92) | def _convert_to_bool(value: str) -> bool:
function _convert_to_list (line 100) | def _convert_to_list(value: str) -> list[Any]:
function _convert_to_dict (line 113) | def _convert_to_dict(value: str) -> dict[str, Any]:
FILE: strix/tools/browser/browser_actions.py
function _validate_url (line 35) | def _validate_url(action_name: str, url: str | None) -> None:
function _validate_coordinate (line 40) | def _validate_coordinate(action_name: str, coordinate: str | None) -> None:
function _validate_text (line 45) | def _validate_text(action_name: str, text: str | None) -> None:
function _validate_tab_id (line 50) | def _validate_tab_id(action_name: str, tab_id: str | None) -> None:
function _validate_js_code (line 55) | def _validate_js_code(action_name: str, js_code: str | None) -> None:
function _validate_duration (line 60) | def _validate_duration(action_name: str, duration: float | None) -> None:
function _validate_key (line 65) | def _validate_key(action_name: str, key: str | None) -> None:
function _validate_file_path (line 70) | def _validate_file_path(action_name: str, file_path: str | None) -> None:
function _handle_navigation_actions (line 75) | def _handle_navigation_actions(
function _handle_interaction_actions (line 94) | def _handle_interaction_actions(
function _raise_unknown_action (line 128) | def _raise_unknown_action(action: str) -> NoReturn:
function _handle_tab_actions (line 132) | def _handle_tab_actions(
function _handle_utility_actions (line 153) | def _handle_utility_actions(
function browser_action (line 184) | def browser_action(
FILE: strix/tools/browser/browser_instance.py
class _BrowserState (line 21) | class _BrowserState:
function _ensure_event_loop (line 34) | def _ensure_event_loop() -> None:
function _create_browser (line 50) | async def _create_browser() -> Browser:
function _get_browser (line 76) | def _get_browser() -> tuple[asyncio.AbstractEventLoop, Browser]:
class BrowserInstance (line 89) | class BrowserInstance:
method __init__ (line 90) | def __init__(self) -> None:
method _run_async (line 104) | def _run_async(self, coro: Any) -> dict[str, Any]:
method _setup_console_logging (line 111) | async def _setup_console_logging(self, page: Page, tab_id: str) -> None:
method _create_context (line 133) | async def _create_context(self, url: str | None = None) -> dict[str, A...
method _get_page_state (line 157) | async def _get_page_state(self, tab_id: str | None = None) -> dict[str...
method launch (line 191) | def launch(self, url: str | None = None) -> dict[str, Any]:
method goto (line 199) | def goto(self, url: str, tab_id: str | None = None) -> dict[str, Any]:
method _goto (line 203) | async def _goto(self, url: str, tab_id: str | None = None) -> dict[str...
method click (line 215) | def click(self, coordinate: str, tab_id: str | None = None) -> dict[st...
method _click (line 219) | async def _click(self, coordinate: str, tab_id: str | None = None) -> ...
method type_text (line 236) | def type_text(self, text: str, tab_id: str | None = None) -> dict[str,...
method _type_text (line 240) | async def _type_text(self, text: str, tab_id: str | None = None) -> di...
method scroll (line 252) | def scroll(self, direction: str, tab_id: str | None = None) -> dict[st...
method _scroll (line 256) | async def _scroll(self, direction: str, tab_id: str | None = None) -> ...
method back (line 274) | def back(self, tab_id: str | None = None) -> dict[str, Any]:
method _back (line 278) | async def _back(self, tab_id: str | None = None) -> dict[str, Any]:
method forward (line 290) | def forward(self, tab_id: str | None = None) -> dict[str, Any]:
method _forward (line 294) | async def _forward(self, tab_id: str | None = None) -> dict[str, Any]:
method new_tab (line 306) | def new_tab(self, url: str | None = None) -> dict[str, Any]:
method _new_tab (line 310) | async def _new_tab(self, url: str | None = None) -> dict[str, Any]:
method switch_tab (line 327) | def switch_tab(self, tab_id: str) -> dict[str, Any]:
method _switch_tab (line 331) | async def _switch_tab(self, tab_id: str) -> dict[str, Any]:
method close_tab (line 338) | def close_tab(self, tab_id: str) -> dict[str, Any]:
method _close_tab (line 342) | async def _close_tab(self, tab_id: str) -> dict[str, Any]:
method wait (line 360) | def wait(self, duration: float, tab_id: str | None = None) -> dict[str...
method _wait (line 364) | async def _wait(self, duration: float, tab_id: str | None = None) -> d...
method execute_js (line 368) | def execute_js(self, js_code: str, tab_id: str | None = None) -> dict[...
method _execute_js (line 372) | async def _execute_js(self, js_code: str, tab_id: str | None = None) -...
method get_console_logs (line 398) | def get_console_logs(self, tab_id: str | None = None, clear: bool = Fa...
method _get_console_logs (line 402) | async def _get_console_logs(
method view_source (line 447) | def view_source(self, tab_id: str | None = None) -> dict[str, Any]:
method _view_source (line 451) | async def _view_source(self, tab_id: str | None = None) -> dict[str, A...
method double_click (line 476) | def double_click(self, coordinate: str, tab_id: str | None = None) -> ...
method _double_click (line 480) | async def _double_click(self, coordinate: str, tab_id: str | None = No...
method hover (line 497) | def hover(self, coordinate: str, tab_id: str | None = None) -> dict[st...
method _hover (line 501) | async def _hover(self, coordinate: str, tab_id: str | None = None) -> ...
method press_key (line 518) | def press_key(self, key: str, tab_id: str | None = None) -> dict[str, ...
method _press_key (line 522) | async def _press_key(self, key: str, tab_id: str | None = None) -> dic...
method save_pdf (line 534) | def save_pdf(self, file_path: str, tab_id: str | None = None) -> dict[...
method _save_pdf (line 538) | async def _save_pdf(self, file_path: str, tab_id: str | None = None) -...
method close (line 555) | def close(self) -> None:
method _close_context (line 568) | async def _close_context(self) -> None:
method is_alive (line 575) | def is_alive(self) -> bool:
FILE: strix/tools/browser/tab_manager.py
class BrowserTabManager (line 11) | class BrowserTabManager:
method __init__ (line 12) | def __init__(self) -> None:
method _get_agent_browser (line 18) | def _get_agent_browser(self) -> BrowserInstance | None:
method _set_agent_browser (line 23) | def _set_agent_browser(self, browser: BrowserInstance | None) -> None:
method launch_browser (line 31) | def launch_browser(self, url: str | None = None) -> dict[str, Any]:
method goto_url (line 47) | def goto_url(self, url: str, tab_id: str | None = None) -> dict[str, A...
method click (line 60) | def click(self, coordinate: str, tab_id: str | None = None) -> dict[st...
method type_text (line 73) | def type_text(self, text: str, tab_id: str | None = None) -> dict[str,...
method scroll (line 86) | def scroll(self, direction: str, tab_id: str | None = None) -> dict[st...
method back (line 99) | def back(self, tab_id: str | None = None) -> dict[str, Any]:
method forward (line 112) | def forward(self, tab_id: str | None = None) -> dict[str, Any]:
method new_tab (line 125) | def new_tab(self, url: str | None = None) -> dict[str, Any]:
method switch_tab (line 138) | def switch_tab(self, tab_id: str) -> dict[str, Any]:
method close_tab (line 151) | def close_tab(self, tab_id: str) -> dict[str, Any]:
method wait_browser (line 164) | def wait_browser(self, duration: float, tab_id: str | None = None) -> ...
method execute_js (line 177) | def execute_js(self, js_code: str, tab_id: str | None = None) -> dict[...
method double_click (line 190) | def double_click(self, coordinate: str, tab_id: str | None = None) -> ...
method hover (line 203) | def hover(self, coordinate: str, tab_id: str | None = None) -> dict[st...
method press_key (line 216) | def press_key(self, key: str, tab_id: str | None = None) -> dict[str, ...
method save_pdf (line 229) | def save_pdf(self, file_path: str, tab_id: str | None = None) -> dict[...
method get_console_logs (line 242) | def get_console_logs(self, tab_id: str | None = None, clear: bool = Fa...
method view_source (line 264) | def view_source(self, tab_id: str | None = None) -> dict[str, Any]:
method list_tabs (line 277) | def list_tabs(self) -> dict[str, Any]:
method close_browser (line 306) | def close_browser(self) -> dict[str, Any]:
method cleanup_agent (line 324) | def cleanup_agent(self, agent_id: str) -> None:
method cleanup_dead_browser (line 332) | def cleanup_dead_browser(self) -> None:
method close_all (line 344) | def close_all(self) -> None:
method _register_cleanup_handlers (line 353) | def _register_cleanup_handlers(self) -> None:
function get_browser_tab_manager (line 360) | def get_browser_tab_manager() -> BrowserTabManager:
FILE: strix/tools/context.py
function get_current_agent_id (line 7) | def get_current_agent_id() -> str:
function set_current_agent_id (line 11) | def set_current_agent_id(agent_id: str) -> None:
FILE: strix/tools/executor.py
function execute_tool (line 29) | async def execute_tool(tool_name: str, agent_state: Any | None = None, *...
function _execute_tool_in_sandbox (line 39) | async def _execute_tool_in_sandbox(tool_name: str, agent_state: Any, **k...
function _execute_tool_locally (line 101) | async def _execute_tool_locally(tool_name: str, agent_state: Any | None,...
function validate_tool_availability (line 118) | def validate_tool_availability(tool_name: str | None) -> tuple[bool, str]:
function _validate_tool_arguments (line 130) | def _validate_tool_arguments(tool_name: str, kwargs: dict[str, Any]) -> ...
function _format_schema_hint (line 156) | def _format_schema_hint(tool_name: str, required: set[str], optional: se...
function execute_tool_with_validation (line 165) | async def execute_tool_with_validation(
function execute_tool_invocation (line 189) | async def execute_tool_invocation(tool_inv: dict[str, Any], agent_state:...
function _check_error_result (line 196) | def _check_error_result(result: Any) -> tuple[bool, Any]:
function _update_tracer_with_result (line 209) | def _update_tracer_with_result(
function _format_tool_result (line 227) | def _format_tool_result(tool_name: str, result: Any) -> tuple[str, list[...
function _execute_single_tool (line 259) | async def _execute_single_tool(
function _get_tracer_and_agent_id (line 300) | def _get_tracer_and_agent_id(agent_state: Any | None) -> tuple[Any | Non...
function process_tool_invocations (line 313) | async def process_tool_invocations(
function extract_screenshot_from_result (line 345) | def extract_screenshot_from_result(result: Any) -> str | None:
function remove_screenshot_from_result (line 356) | def remove_screenshot_from_result(result: Any) -> Any:
FILE: strix/tools/file_edit/file_edit_actions.py
function _parse_file_editor_output (line 9) | def _parse_file_editor_output(output: str) -> dict[str, Any]:
function str_replace_editor (line 24) | def str_replace_editor(
function list_files (line 62) | def list_files(
function search_files (line 115) | def search_files(
FILE: strix/tools/finish/finish_actions.py
function _validate_root_agent (line 6) | def _validate_root_agent(agent_state: Any) -> dict[str, Any] | None:
function _check_active_agents (line 17) | def _check_active_agents(agent_state: Any = None) -> dict[str, Any] | None:
function finish_scan (line 87) | def finish_scan(
FILE: strix/tools/load_skill/load_skill_actions.py
function load_skill (line 7) | def load_skill(agent_state: Any, skills: str) -> dict[str, Any]:
FILE: strix/tools/notes/notes_actions.py
function _filter_notes (line 11) | def _filter_notes(
function create_note (line 43) | def create_note(
function list_notes (line 89) | def list_notes(
function update_note (line 113) | def update_note(
function delete_note (line 150) | def delete_note(note_id: str) -> dict[str, Any]:
FILE: strix/tools/proxy/proxy_actions.py
function list_requests (line 10) | def list_requests(
function view_request (line 37) | def view_request(
function send_request (line 51) | def send_request(
function repeat_request (line 67) | def repeat_request(
function scope_rules (line 80) | def scope_rules(
function list_sitemap (line 94) | def list_sitemap(
function view_sitemap_entry (line 107) | def view_sitemap_entry(
FILE: strix/tools/proxy/proxy_manager.py
class ProxyManager (line 22) | class ProxyManager:
method __init__ (line 23) | def __init__(self, auth_token: str | None = None):
method _get_client (line 32) | def _get_client(self) -> Client:
method list_requests (line 38) | def list_requests(
method view_request (line 114) | def view_request(
method _search_content (line 175) | def _search_content(
method _paginate_content (line 208) | def _paginate_content(
method send_simple_request (line 239) | def send_simple_request(
method repeat_request (line 279) | def repeat_request(
method _parse_http_request (line 307) | def _parse_http_request(self, raw_content: str) -> dict[str, Any]:
method _build_full_url (line 329) | def _build_full_url(
method _apply_modifications (line 347) | def _apply_modifications(
method _send_modified_request (line 383) | def _send_modified_request(
method _handle_scope_list (line 441) | def _handle_scope_list(self) -> dict[str, Any]:
method _handle_scope_get (line 448) | def _handle_scope_get(self, scope_id: str | None) -> dict[str, Any]:
method _handle_scope_create (line 463) | def _handle_scope_create(
method _handle_scope_update (line 499) | def _handle_scope_update(
method _handle_scope_delete (line 540) | def _handle_scope_delete(self, scope_id: str) -> dict[str, Any]:
method scope_rules (line 554) | def scope_rules(
method list_sitemap (line 596) | def list_sitemap(
method _process_sitemap_metadata (line 693) | def _process_sitemap_metadata(self, node: dict[str, Any]) -> dict[str,...
method _process_sitemap_request (line 708) | def _process_sitemap_request(self, req: dict[str, Any]) -> dict[str, A...
method _process_sitemap_response (line 719) | def _process_sitemap_response(self, resp: dict[str, Any]) -> dict[str,...
method view_sitemap_entry (line 729) | def view_sitemap_entry(self, entry_id: str) -> dict[str, Any]:
method close (line 786) | def close(self) -> None:
function get_proxy_manager (line 793) | def get_proxy_manager() -> ProxyManager:
FILE: strix/tools/python/python_actions.py
function python_action (line 10) | def python_action(
FILE: strix/tools/python/python_instance.py
class PythonInstance (line 13) | class PythonInstance:
method __init__ (line 14) | def __init__(self, session_id: str) -> None:
method _setup_proxy_functions (line 30) | def _setup_proxy_functions(self) -> None:
method _validate_session (line 49) | def _validate_session(self) -> dict[str, Any] | None:
method _truncate_output (line 59) | def _truncate_output(self, content: str, max_length: int, suffix: str)...
method _format_execution_result (line 64) | def _format_execution_result(
method _handle_execution_error (line 103) | def _handle_execution_error(self, error: BaseException) -> dict[str, A...
method execute_code (line 116) | def execute_code(self, code: str, timeout: int = 30) -> dict[str, Any]:
method close (line 169) | def close(self) -> None:
method is_alive (line 173) | def is_alive(self) -> bool:
FILE: strix/tools/python/python_manager.py
class PythonSessionManager (line 11) | class PythonSessionManager:
method __init__ (line 12) | def __init__(self) -> None:
method _get_agent_sessions (line 19) | def _get_agent_sessions(self) -> dict[str, PythonInstance]:
method create_session (line 26) | def create_session(
method execute_code (line 53) | def execute_code(
method close_session (line 73) | def close_session(self, session_id: str | None = None) -> dict[str, Any]:
method list_sessions (line 91) | def list_sessions(self) -> dict[str, Any]:
method cleanup_agent (line 103) | def cleanup_agent(self, agent_id: str) -> None:
method cleanup_dead_sessions (line 111) | def cleanup_dead_sessions(self) -> None:
method close_all_sessions (line 124) | def close_all_sessions(self) -> None:
method _register_cleanup_handlers (line 135) | def _register_cleanup_handlers(self) -> None:
function get_python_session_manager (line 142) | def get_python_session_manager() -> PythonSessionManager:
FILE: strix/tools/registry.py
class ImplementedInClientSideOnlyError (line 21) | class ImplementedInClientSideOnlyError(Exception):
method __init__ (line 22) | def __init__(
function _process_dynamic_content (line 30) | def _process_dynamic_content(content: str) -> str:
function _load_xml_schema (line 47) | def _load_xml_schema(path: Path) -> Any:
function _parse_param_schema (line 90) | def _parse_param_schema(tool_xml: str) -> dict[str, Any]:
function _get_module_name (line 118) | def _get_module_name(func: Callable[..., Any]) -> str:
function _get_schema_path (line 131) | def _get_schema_path(func: Callable[..., Any]) -> Path | None:
function _is_sandbox_mode (line 152) | def _is_sandbox_mode() -> bool:
function _is_browser_disabled (line 156) | def _is_browser_disabled() -> bool:
function _has_perplexity_api (line 166) | def _has_perplexity_api() -> bool:
function _should_register_tool (line 175) | def _should_register_tool(
function register_tool (line 190) | def register_tool(
function get_tool_by_name (line 253) | def get_tool_by_name(name: str) -> Callable[..., Any] | None:
function get_tool_names (line 257) | def get_tool_names() -> list[str]:
function get_tool_param_schema (line 261) | def get_tool_param_schema(name: str) -> dict[str, Any] | None:
function needs_agent_state (line 265) | def needs_agent_state(tool_name: str) -> bool:
function should_execute_in_sandbox (line 273) | def should_execute_in_sandbox(tool_name: str) -> bool:
function get_tools_prompt (line 280) | def get_tools_prompt() -> str:
function clear_registry (line 303) | def clear_registry() -> None:
FILE: strix/tools/reporting/reporting_actions.py
function parse_cvss_xml (line 21) | def parse_cvss_xml(xml_str: str) -> dict[str, str] | None:
function parse_code_locations_xml (line 32) | def parse_code_locations_xml(xml_str: str) -> list[dict[str, Any]] | None:
function _validate_file_path (line 66) | def _validate_file_path(path: str) -> str | None:
function _validate_code_locations (line 77) | def _validate_code_locations(locations: list[dict[str, Any]]) -> list[str]:
function _extract_cve (line 96) | def _extract_cve(cve: str) -> str:
function _validate_cve (line 101) | def _validate_cve(cve: str) -> str | None:
function _extract_cwe (line 107) | def _extract_cwe(cwe: str) -> str:
function _validate_cwe (line 112) | def _validate_cwe(cwe: str) -> str | None:
function calculate_cvss_and_severity (line 118) | def calculate_cvss_and_severity(
function _validate_required_fields (line 155) | def _validate_required_fields(**kwargs: str | None) -> list[str]:
function _validate_cvss_parameters (line 177) | def _validate_cvss_parameters(**kwargs: str) -> list[str]:
function create_vulnerability_report (line 202) | def create_vulnerability_report( # noqa: PLR0912
FILE: strix/tools/terminal/terminal_actions.py
function terminal_execute (line 7) | def terminal_execute(
FILE: strix/tools/terminal/terminal_manager.py
class TerminalManager (line 11) | class TerminalManager:
method __init__ (line 12) | def __init__(self) -> None:
method _get_agent_sessions (line 20) | def _get_agent_sessions(self) -> dict[str, TerminalSession]:
method execute_command (line 27) | def execute_command(
method _get_or_create_session (line 73) | def _get_or_create_session(self, terminal_id: str) -> TerminalSession:
method close_session (line 80) | def close_session(self, terminal_id: str | None = None) -> dict[str, A...
method list_sessions (line 110) | def list_sessions(self) -> dict[str, Any]:
method cleanup_agent (line 122) | def cleanup_agent(self, agent_id: str) -> None:
method cleanup_dead_sessions (line 130) | def cleanup_dead_sessions(self) -> None:
method close_all_sessions (line 143) | def close_all_sessions(self) -> None:
method _register_cleanup_handlers (line 154) | def _register_cleanup_handlers(self) -> None:
function get_terminal_manager (line 161) | def get_terminal_manager() -> TerminalManager:
FILE: strix/tools/terminal/terminal_session.py
class BashCommandStatus (line 15) | class BashCommandStatus(Enum):
function _remove_command_prefix (line 22) | def _remove_command_prefix(command_output: str, command: str) -> str:
class TerminalSession (line 26) | class TerminalSession:
method __init__ (line 31) | def __init__(self, session_id: str, work_dir: str = "/workspace") -> N...
method PS1 (line 49) | def PS1(self) -> str: # noqa: N802
method PS1_PATTERN (line 53) | def PS1_PATTERN(self) -> str: # noqa: N802
method initialize (line 56) | def initialize(self) -> None:
method _get_pane_content (line 96) | def _get_pane_content(self) -> str:
method _clear_screen (line 103) | def _clear_screen(self) -> None:
method _is_control_key (line 110) | def _is_control_key(self, command: str) -> bool:
method _is_function_key (line 118) | def _is_function_key(self, command: str) -> bool:
method _is_navigation_or_special_key (line 127) | def _is_navigation_or_special_key(self, command: str) -> bool:
method _is_complex_modifier_key (line 134) | def _is_complex_modifier_key(self, command: str) -> bool:
method _is_special_key (line 140) | def _is_special_key(self, command: str) -> bool:
method _matches_ps1_metadata (line 153) | def _matches_ps1_metadata(self, content: str) -> list[re.Match[str]]:
method _get_command_output (line 156) | def _get_command_output(
method _combine_outputs_between_matches (line 172) | def _combine_outputs_between_matches(
method _extract_exit_code_from_matches (line 192) | def _extract_exit_code_from_matches(self, ps1_matches: list[re.Match[s...
method _handle_empty_command (line 202) | def _handle_empty_command(
method _handle_input_command (line 261) | def _handle_input_command(
method _execute_new_command (line 308) | def _execute_new_command(self, command: str, no_enter: bool, timeout: ...
method execute (line 380) | def execute(
method _ready_for_next_command (line 418) | def _ready_for_next_command(self) -> None:
method is_running (line 421) | def is_running(self) -> bool:
method get_working_dir (line 430) | def get_working_dir(self) -> str:
method close (line 433) | def close(self) -> None:
FILE: strix/tools/thinking/thinking_actions.py
function think (line 7) | def think(thought: str) -> dict[str, Any]:
FILE: strix/tools/todo/todo_actions.py
function _get_agent_todos (line 15) | def _get_agent_todos(agent_id: str) -> dict[str, dict[str, Any]]:
function _normalize_priority (line 21) | def _normalize_priority(priority: str | None, default: str = "normal") -...
function _sorted_todos (line 28) | def _sorted_todos(agent_id: str) -> list[dict[str, Any]]:
function _normalize_todo_ids (line 50) | def _normalize_todo_ids(raw_ids: Any) -> list[str]:
function _normalize_bulk_updates (line 72) | def _normalize_bulk_updates(raw_updates: Any) -> list[dict[str, Any]]:
function _normalize_bulk_todos (line 114) | def _normalize_bulk_todos(raw_todos: Any) -> list[dict[str, Any]]:
function create_todo (line 162) | def create_todo(
function list_todos (line 237) | def list_todos(
function _apply_single_update (line 300) | def _apply_single_update(
function update_todo (line 345) | def update_todo(
function mark_todo_done (line 417) | def mark_todo_done(
function mark_todo_pending (line 470) | def mark_todo_pending(
function delete_todo (line 523) | def delete_todo(
FILE: strix/tools/web_search/web_search_actions.py
function web_search (line 35) | def web_search(query: str) -> dict[str, Any]:
FILE: strix/utils/resource_paths.py
function get_strix_resource_path (line 5) | def get_strix_resource_path(*parts: str) -> Path:
FILE: tests/config/test_config_telemetry.py
function test_traceloop_vars_are_tracked (line 6) | def test_traceloop_vars_are_tracked() -> None:
function test_apply_saved_uses_saved_traceloop_vars (line 16) | def test_apply_saved_uses_saved_traceloop_vars(monkeypatch, tmp_path) ->...
function test_apply_saved_respects_existing_env_traceloop_vars (line 43) | def test_apply_saved_respects_existing_env_traceloop_vars(monkeypatch, t...
FILE: tests/llm/test_llm_otel.py
function test_llm_does_not_modify_litellm_callbacks (line 7) | def test_llm_does_not_modify_litellm_callbacks(monkeypatch) -> None:
FILE: tests/telemetry/test_flags.py
function test_flags_fallback_to_strix_telemetry (line 4) | def test_flags_fallback_to_strix_telemetry(monkeypatch) -> None:
function test_otel_flag_overrides_global_telemetry (line 13) | def test_otel_flag_overrides_global_telemetry(monkeypatch) -> None:
function test_posthog_flag_overrides_global_telemetry (line 22) | def test_posthog_flag_overrides_global_telemetry(monkeypatch) -> None:
FILE: tests/telemetry/test_tracer.py
function _load_events (line 15) | def _load_events(events_path: Path) -> list[dict[str, Any]]:
function _reset_tracer_globals (line 21) | def _reset_tracer_globals(monkeypatch) -> None:
function test_tracer_local_mode_writes_jsonl_with_correlation (line 34) | def test_tracer_local_mode_writes_jsonl_with_correlation(monkeypatch, tm...
function test_tracer_redacts_sensitive_payloads (line 62) | def test_tracer_redacts_sensitive_payloads(monkeypatch, tmp_path) -> None:
function test_tracer_remote_mode_configures_traceloop_export (line 91) | def test_tracer_remote_mode_configures_traceloop_export(monkeypatch, tmp...
function test_tracer_local_mode_avoids_traceloop_remote_endpoint (line 130) | def test_tracer_local_mode_avoids_traceloop_remote_endpoint(monkeypatch,...
function test_otlp_fallback_includes_auth_and_custom_headers (line 159) | def test_otlp_fallback_includes_auth_and_custom_headers(monkeypatch, tmp...
function test_traceloop_init_failure_does_not_mark_bootstrapped_on_provider_failure (line 200) | def test_traceloop_init_failure_does_not_mark_bootstrapped_on_provider_f...
function test_run_completed_event_emitted_once (line 228) | def test_run_completed_event_emitted_once(monkeypatch, tmp_path) -> None:
function test_events_with_agent_id_include_agent_name (line 242) | def test_events_with_agent_id_include_agent_name(monkeypatch, tmp_path) ...
function test_run_metadata_is_only_on_run_lifecycle_events (line 258) | def test_run_metadata_is_only_on_run_lifecycle_events(monkeypatch, tmp_p...
function test_set_run_name_resets_cached_paths (line 278) | def test_set_run_name_resets_cached_paths(monkeypatch, tmp_path) -> None:
function test_set_run_name_resets_run_completed_flag (line 297) | def test_set_run_name_resets_run_completed_flag(monkeypatch, tmp_path) -...
function test_set_run_name_updates_traceloop_association_properties (line 315) | def test_set_run_name_updates_traceloop_association_properties(monkeypat...
function test_events_write_locks_are_scoped_by_events_file (line 340) | def test_events_write_locks_are_scoped_by_events_file(monkeypatch, tmp_p...
function test_tracer_skips_jsonl_when_telemetry_disabled (line 355) | def test_tracer_skips_jsonl_when_telemetry_disabled(monkeypatch, tmp_pat...
function test_tracer_otel_flag_overrides_global_telemetry (line 368) | def test_tracer_otel_flag_overrides_global_telemetry(monkeypatch, tmp_pa...
FILE: tests/telemetry/test_utils.py
function test_prune_otel_span_attributes_drops_high_volume_prompt_content (line 4) | def test_prune_otel_span_attributes_drops_high_volume_prompt_content() -...
function test_prune_otel_span_attributes_keeps_metadata_when_nothing_is_dropped (line 30) | def test_prune_otel_span_attributes_keeps_metadata_when_nothing_is_dropp...
FILE: tests/tools/conftest.py
function sample_function_with_types (line 10) | def sample_function_with_types() -> Callable[..., None]:
function sample_function_no_annotations (line 28) | def sample_function_no_annotations() -> Callable[..., None]:
FILE: tests/tools/test_argument_parser.py
class TestConvertToBool (line 16) | class TestConvertToBool:
method test_truthy_values (line 23) | def test_truthy_values(self, value: str) -> None:
method test_falsy_values (line 31) | def test_falsy_values(self, value: str) -> None:
method test_non_standard_truthy_string (line 35) | def test_non_standard_truthy_string(self) -> None:
method test_empty_string (line 40) | def test_empty_string(self) -> None:
class TestConvertToList (line 45) | class TestConvertToList:
method test_json_array_string (line 48) | def test_json_array_string(self) -> None:
method test_json_array_with_numbers (line 53) | def test_json_array_with_numbers(self) -> None:
method test_comma_separated_string (line 58) | def test_comma_separated_string(self) -> None:
method test_comma_separated_no_spaces (line 63) | def test_comma_separated_no_spaces(self) -> None:
method test_single_value (line 68) | def test_single_value(self) -> None:
method test_json_non_array_wraps_in_list (line 73) | def test_json_non_array_wraps_in_list(self) -> None:
method test_json_object_wraps_in_list (line 78) | def test_json_object_wraps_in_list(self) -> None:
method test_empty_json_array (line 83) | def test_empty_json_array(self) -> None:
class TestConvertToDict (line 89) | class TestConvertToDict:
method test_valid_json_object (line 92) | def test_valid_json_object(self) -> None:
method test_empty_json_object (line 97) | def test_empty_json_object(self) -> None:
method test_invalid_json_returns_empty_dict (line 102) | def test_invalid_json_returns_empty_dict(self) -> None:
method test_json_array_returns_empty_dict (line 107) | def test_json_array_returns_empty_dict(self) -> None:
method test_nested_json_object (line 112) | def test_nested_json_object(self) -> None:
class TestConvertBasicTypes (line 118) | class TestConvertBasicTypes:
method test_convert_to_int (line 121) | def test_convert_to_int(self) -> None:
method test_convert_to_float (line 126) | def test_convert_to_float(self) -> None:
method test_convert_to_str (line 131) | def test_convert_to_str(self) -> None:
method test_convert_to_bool (line 135) | def test_convert_to_bool(self) -> None:
method test_convert_to_list_type (line 140) | def test_convert_to_list_type(self) -> None:
method test_convert_to_dict_type (line 145) | def test_convert_to_dict_type(self) -> None:
method test_unknown_type_attempts_json (line 150) | def test_unknown_type_attempts_json(self) -> None:
method test_unknown_type_returns_original (line 155) | def test_unknown_type_returns_original(self) -> None:
class TestConvertStringToType (line 161) | class TestConvertStringToType:
method test_basic_type_conversion (line 164) | def test_basic_type_conversion(self) -> None:
method test_optional_type (line 170) | def test_optional_type(self) -> None:
method test_union_type (line 175) | def test_union_type(self) -> None:
method test_union_type_with_none (line 180) | def test_union_type_with_none(self) -> None:
method test_modern_union_syntax (line 185) | def test_modern_union_syntax(self) -> None:
class TestConvertArguments (line 191) | class TestConvertArguments:
method test_converts_typed_arguments (line 194) | def test_converts_typed_arguments(
method test_passes_through_none_values (line 215) | def test_passes_through_none_values(
method test_passes_through_non_string_values (line 223) | def test_passes_through_non_string_values(
method test_unknown_parameter_passed_through (line 231) | def test_unknown_parameter_passed_through(
method test_function_without_annotations (line 239) | def test_function_without_annotations(
method test_raises_error_on_conversion_failure (line 248) | def test_raises_error_on_conversion_failure(
class TestArgumentConversionError (line 258) | class TestArgumentConversionError:
method test_error_with_param_name (line 261) | def test_error_with_param_name(self) -> None:
method test_error_without_param_name (line 267) | def test_error_without_param_name(self) -> None:
FILE: tests/tools/test_load_skill_tool.py
class _DummyLLM (line 7) | class _DummyLLM:
method __init__ (line 8) | def __init__(self, initial_skills: list[str] | None = None) -> None:
method add_skills (line 11) | def add_skills(self, skill_names: list[str]) -> list[str]:
class _DummyAgent (line 17) | class _DummyAgent:
method __init__ (line 18) | def __init__(self, initial_skills: list[str] | None = None) -> None:
class _DummyAgentState (line 22) | class _DummyAgentState:
method __init__ (line 23) | def __init__(self, agent_id: str) -> None:
method update_context (line 27) | def update_context(self, key: str, value: Any) -> None:
function test_load_skill_success_and_context_update (line 31) | def test_load_skill_success_and_context_update() -> None:
function test_load_skill_uses_same_plain_skill_format_as_create_agent (line 50) | def test_load_skill_uses_same_plain_skill_format_as_create_agent() -> None:
function test_load_skill_invalid_skill_returns_error (line 69) | def test_load_skill_invalid_skill_returns_error() -> None:
function test_load_skill_rejects_more_than_five_skills (line 87) | def test_load_skill_rejects_more_than_five_skills() -> None:
function test_load_skill_missing_agent_instance_returns_error (line 106) | def test_load_skill_missing_agent_instance_returns_error() -> None:
function test_load_skill_does_not_reload_skill_already_present_from_agent_creation (line 122) | def test_load_skill_does_not_reload_skill_already_present_from_agent_cre...
FILE: tests/tools/test_tool_registration_modes.py
function _empty_config_load (line 10) | def _empty_config_load(_cls: type[Config]) -> dict[str, dict[str, str]]:
function _reload_tools_module (line 14) | def _reload_tools_module() -> ModuleType:
function test_non_sandbox_registers_agents_graph_but_not_browser_or_web_search_when_disabled (line 24) | def test_non_sandbox_registers_agents_graph_but_not_browser_or_web_searc...
function test_sandbox_registers_sandbox_tools_but_not_non_sandbox_tools (line 40) | def test_sandbox_registers_sandbox_tools_but_not_non_sandbox_tools(
function test_load_skill_import_does_not_register_create_agent_in_sandbox (line 61) | def test_load_skill_import_does_not_register_create_agent_in_sandbox(
Condensed preview — 207 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,204K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 647,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Describe"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 613,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[FEATURE]\"\nlabels: enhancement\nassignees: ''\n\n"
},
{
"path": ".github/workflows/build-release.yml",
"chars": 2086,
"preview": "name: Build & Release\n\non:\n push:\n tags:\n - 'v*'\n workflow_dispatch:\n\njobs:\n build:\n strategy:\n fail-"
},
{
"path": ".gitignore",
"chars": 893,
"preview": "# Python\n__pycache__/\n*.py[cod]\n*$py.class\n*.so\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\np"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1605,
"preview": "repos:\n # Ruff for fast linting and formatting\n - repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v0.11.13"
},
{
"path": "CONTRIBUTING.md",
"chars": 3054,
"preview": "# Contributing to Strix\n\nThank you for your interest in contributing to Strix! This guide will help you get started with"
},
{
"path": "LICENSE",
"chars": 11345,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 2987,
"preview": ".PHONY: help install dev-install format lint type-check test test-cov clean pre-commit setup-dev\n\nhelp:\n\t@echo \"Availabl"
},
{
"path": "README.md",
"chars": 10179,
"preview": "<p align=\"center\">\n <a href=\"https://strix.ai/\">\n <img src=\"https://github.com/usestrix/.github/raw/main/imgs/cover."
},
{
"path": "benchmarks/README.md",
"chars": 1634,
"preview": "# Benchmarks\n\nWe use security benchmarks to track Strix's capabilities and improvements over time. We plan to add more b"
},
{
"path": "containers/Dockerfile",
"chars": 7061,
"preview": "FROM kalilinux/kali-rolling:latest\n\nLABEL description=\"AI Agent Penetration Testing Environment with Comprehensive Autom"
},
{
"path": "containers/docker-entrypoint.sh",
"chars": 5737,
"preview": "#!/bin/bash\nset -e\n\nCAIDO_PORT=48080\nCAIDO_LOG=\"/tmp/caido_startup.log\"\n\nif [ ! -f /app/certs/ca.p12 ]; then\n echo \"ERR"
},
{
"path": "docs/README.md",
"chars": 179,
"preview": "# Strix Documentation\n\nDocumentation source files for Strix, powered by [Mintlify](https://mintlify.com).\n\n## Local Prev"
},
{
"path": "docs/advanced/configuration.mdx",
"chars": 4462,
"preview": "---\ntitle: \"Configuration\"\ndescription: \"Environment variables for Strix\"\n---\n\nConfigure Strix using environment variabl"
},
{
"path": "docs/advanced/skills.mdx",
"chars": 5888,
"preview": "---\ntitle: \"Skills\"\ndescription: \"Specialized knowledge packages that enhance agent capabilities\"\n---\n\nSkills are struct"
},
{
"path": "docs/cloud/overview.mdx",
"chars": 1166,
"preview": "---\ntitle: \"Introduction\"\ndescription: \"Managed security testing without local setup\"\n---\n\nSkip the setup. Run Strix in "
},
{
"path": "docs/contributing.mdx",
"chars": 2159,
"preview": "---\ntitle: \"Contributing\"\ndescription: \"Contribute to Strix development\"\n---\n\n## Development Setup\n\n### Prerequisites\n\n-"
},
{
"path": "docs/docs.json",
"chars": 2876,
"preview": "{\n \"$schema\": \"https://mintlify.com/docs.json\",\n \"theme\": \"maple\",\n \"name\": \"Strix\",\n \"colors\": {\n \"primary\": \"#0"
},
{
"path": "docs/index.mdx",
"chars": 3577,
"preview": "---\ntitle: \"Introduction\"\ndescription: \"Open-source AI hackers to secure your apps\"\n---\n\nStrix are autonomous AI agents "
},
{
"path": "docs/integrations/ci-cd.mdx",
"chars": 1541,
"preview": "---\ntitle: \"CI/CD Integration\"\ndescription: \"Run Strix in any CI/CD pipeline\"\n---\n\nStrix runs in headless mode for autom"
},
{
"path": "docs/integrations/github-actions.mdx",
"chars": 1346,
"preview": "---\ntitle: \"GitHub Actions\"\ndescription: \"Run Strix security scans on every pull request\"\n---\n\nIntegrate Strix into your"
},
{
"path": "docs/llm-providers/anthropic.mdx",
"chars": 505,
"preview": "---\ntitle: \"Anthropic\"\ndescription: \"Configure Strix with Claude models\"\n---\n\n## Setup\n\n```bash\nexport STRIX_LLM=\"openai"
},
{
"path": "docs/llm-providers/azure.mdx",
"chars": 950,
"preview": "---\ntitle: \"Azure OpenAI\"\ndescription: \"Configure Strix with OpenAI models via Azure\"\n---\n\n## Setup\n\n```bash\nexport STRI"
},
{
"path": "docs/llm-providers/bedrock.mdx",
"chars": 1086,
"preview": "---\ntitle: \"AWS Bedrock\"\ndescription: \"Configure Strix with models via AWS Bedrock\"\n---\n\n## Setup\n\n```bash\nexport STRIX_"
},
{
"path": "docs/llm-providers/local.mdx",
"chars": 1961,
"preview": "---\ntitle: \"Local Models\"\ndescription: \"Run Strix with self-hosted LLMs for privacy and air-gapped testing\"\n---\n\nRunning"
},
{
"path": "docs/llm-providers/models.mdx",
"chars": 2010,
"preview": "---\ntitle: \"Strix Router\"\ndescription: \"Access top LLMs through a single API with high rate limits and zero data retenti"
},
{
"path": "docs/llm-providers/openai.mdx",
"chars": 593,
"preview": "---\ntitle: \"OpenAI\"\ndescription: \"Configure Strix with OpenAI models\"\n---\n\n## Setup\n\n```bash\nexport STRIX_LLM=\"openai/gp"
},
{
"path": "docs/llm-providers/openrouter.mdx",
"chars": 1057,
"preview": "---\ntitle: \"OpenRouter\"\ndescription: \"Configure Strix with models via OpenRouter\"\n---\n\n[OpenRouter](https://openrouter.a"
},
{
"path": "docs/llm-providers/overview.mdx",
"chars": 2509,
"preview": "---\ntitle: \"Overview\"\ndescription: \"Configure your AI model for Strix\"\n---\n\nStrix uses [LiteLLM](https://docs.litellm.ai"
},
{
"path": "docs/llm-providers/vertex.mdx",
"chars": 1066,
"preview": "---\ntitle: \"Google Vertex AI\"\ndescription: \"Configure Strix with Gemini models via Google Cloud\"\n---\n\n## Installation\n\nV"
},
{
"path": "docs/quickstart.mdx",
"chars": 1719,
"preview": "---\ntitle: \"Quick Start\"\ndescription: \"Install Strix and run your first security scan\"\n---\n\n## Prerequisites\n\n- Docker ("
},
{
"path": "docs/tools/browser.mdx",
"chars": 1339,
"preview": "---\ntitle: \"Browser\"\ndescription: \"Playwright-powered Chrome for web application testing\"\n---\n\nStrix uses a headless Chr"
},
{
"path": "docs/tools/overview.mdx",
"chars": 1230,
"preview": "---\ntitle: \"Agent Tools\"\ndescription: \"How Strix agents interact with targets\"\n---\n\nStrix agents use specialized tools t"
},
{
"path": "docs/tools/proxy.mdx",
"chars": 4132,
"preview": "---\ntitle: \"HTTP Proxy\"\ndescription: \"Caido-powered proxy for request interception and replay\"\n---\n\nStrix includes [Caid"
},
{
"path": "docs/tools/sandbox.mdx",
"chars": 5052,
"preview": "---\ntitle: \"Sandbox Tools\"\ndescription: \"Pre-installed security tools in the Strix container\"\n---\n\nStrix runs inside a K"
},
{
"path": "docs/tools/terminal.mdx",
"chars": 1506,
"preview": "---\ntitle: \"Terminal\"\ndescription: \"Bash shell for running commands and security tools\"\n---\n\nStrix has access to a persi"
},
{
"path": "docs/usage/cli.mdx",
"chars": 1601,
"preview": "---\ntitle: \"CLI Reference\"\ndescription: \"Command-line options for Strix\"\n---\n\n## Basic Usage\n\n```bash\nstrix --target <ta"
},
{
"path": "docs/usage/instructions.mdx",
"chars": 1526,
"preview": "---\ntitle: \"Custom Instructions\"\ndescription: \"Guide Strix with custom testing instructions\"\n---\n\nUse instructions to pr"
},
{
"path": "docs/usage/scan-modes.mdx",
"chars": 1161,
"preview": "---\ntitle: \"Scan Modes\"\ndescription: \"Choose the right scan depth for your use case\"\n---\n\nStrix offers three scan modes "
},
{
"path": "pyproject.toml",
"chars": 10591,
"preview": "[tool.poetry]\nname = \"strix-agent\"\nversion = \"0.8.2\"\ndescription = \"Open-source AI Hackers for your apps\"\nauthors = [\"St"
},
{
"path": "scripts/build.sh",
"chars": 2918,
"preview": "#!/bin/bash\nset -e\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pw"
},
{
"path": "scripts/install.sh",
"chars": 11215,
"preview": "#!/usr/bin/env bash\n\nset -euo pipefail\n\nAPP=strix\nREPO=\"usestrix/strix\"\nSTRIX_IMAGE=\"ghcr.io/usestrix/strix-sandbox:0.1."
},
{
"path": "strix/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "strix/agents/StrixAgent/__init__.py",
"chars": 63,
"preview": "from .strix_agent import StrixAgent\n\n\n__all__ = [\"StrixAgent\"]\n"
},
{
"path": "strix/agents/StrixAgent/strix_agent.py",
"chars": 3073,
"preview": "from typing import Any\n\nfrom strix.agents.base_agent import BaseAgent\nfrom strix.llm.config import LLMConfig\n\n\nclass Str"
},
{
"path": "strix/agents/StrixAgent/system_prompt.jinja",
"chars": 25192,
"preview": "You are Strix, an advanced AI cybersecurity agent developed by OmniSecure Labs. Your purpose is to conduct security asse"
},
{
"path": "strix/agents/__init__.py",
"chars": 168,
"preview": "from .base_agent import BaseAgent\nfrom .state import AgentState\nfrom .StrixAgent import StrixAgent\n\n\n__all__ = [\n \"Ag"
},
{
"path": "strix/agents/base_agent.py",
"chars": 24580,
"preview": "import asyncio\nimport contextlib\nimport logging\nfrom typing import TYPE_CHECKING, Any, Optional\n\n\nif TYPE_CHECKING:\n "
},
{
"path": "strix/agents/state.py",
"chars": 6010,
"preview": "import uuid\nfrom datetime import UTC, datetime\nfrom typing import Any\n\nfrom pydantic import BaseModel, Field\n\n\ndef _gene"
},
{
"path": "strix/config/__init__.py",
"chars": 180,
"preview": "from strix.config.config import (\n Config,\n apply_saved_config,\n save_current_config,\n)\n\n\n__all__ = [\n \"Conf"
},
{
"path": "strix/config/config.py",
"chars": 6439,
"preview": "import contextlib\nimport json\nimport os\nfrom pathlib import Path\nfrom typing import Any\n\n\nSTRIX_API_BASE = \"https://mode"
},
{
"path": "strix/interface/__init__.py",
"chars": 44,
"preview": "from .main import main\n\n\n__all__ = [\"main\"]\n"
},
{
"path": "strix/interface/assets/tui_styles.tcss",
"chars": 11943,
"preview": "Screen {\n background: #000000;\n color: #d4d4d4;\n}\n\n.screen--selection {\n background: #2d3d2f;\n color: #e5e5e"
},
{
"path": "strix/interface/cli.py",
"chars": 5930,
"preview": "import atexit\nimport signal\nimport sys\nimport threading\nimport time\nfrom typing import Any\n\nfrom rich.console import Con"
},
{
"path": "strix/interface/main.py",
"chars": 19554,
"preview": "#!/usr/bin/env python3\n\"\"\"\nStrix Agent Interface\n\"\"\"\n\nimport argparse\nimport asyncio\nimport logging\nimport shutil\nimport"
},
{
"path": "strix/interface/streaming_parser.py",
"chars": 3750,
"preview": "import html\nimport re\nfrom dataclasses import dataclass\nfrom typing import Literal\n\nfrom strix.llm.utils import normaliz"
},
{
"path": "strix/interface/tool_components/__init__.py",
"chars": 1085,
"preview": "from . import (\n agent_message_renderer,\n agents_graph_renderer,\n browser_renderer,\n file_edit_renderer,\n "
},
{
"path": "strix/interface/tool_components/agent_message_renderer.py",
"chars": 5903,
"preview": "from functools import cache\nfrom typing import Any, ClassVar\n\nfrom pygments.lexers import get_lexer_by_name, guess_lexer"
},
{
"path": "strix/interface/tool_components/agents_graph_renderer.py",
"chars": 4370,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/base_renderer.py",
"chars": 2588,
"preview": "from abc import ABC, abstractmethod\nfrom typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets im"
},
{
"path": "strix/interface/tool_components/browser_renderer.py",
"chars": 4573,
"preview": "from functools import cache\nfrom typing import Any, ClassVar\n\nfrom pygments.lexers import get_lexer_by_name\nfrom pygment"
},
{
"path": "strix/interface/tool_components/file_edit_renderer.py",
"chars": 5961,
"preview": "from functools import cache\nfrom typing import Any, ClassVar\n\nfrom pygments.lexers import get_lexer_by_name, get_lexer_f"
},
{
"path": "strix/interface/tool_components/finish_renderer.py",
"chars": 2086,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/load_skill_renderer.py",
"chars": 997,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/notes_renderer.py",
"chars": 4211,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/proxy_renderer.py",
"chars": 25227,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/python_renderer.py",
"chars": 4843,
"preview": "import re\nfrom functools import cache\nfrom typing import Any, ClassVar\n\nfrom pygments.lexers import PythonLexer\nfrom pyg"
},
{
"path": "strix/interface/tool_components/registry.py",
"chars": 2411,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/reporting_renderer.py",
"chars": 8693,
"preview": "from functools import cache\nfrom typing import Any, ClassVar\n\nfrom pygments.lexers import PythonLexer\nfrom pygments.styl"
},
{
"path": "strix/interface/tool_components/scan_info_renderer.py",
"chars": 2204,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/terminal_renderer.py",
"chars": 9227,
"preview": "import re\nfrom functools import cache\nfrom typing import Any, ClassVar\n\nfrom pygments.lexers import get_lexer_by_name\nfr"
},
{
"path": "strix/interface/tool_components/thinking_renderer.py",
"chars": 902,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/todo_renderer.py",
"chars": 7403,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/user_message_renderer.py",
"chars": 1381,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tool_components/web_search_renderer.py",
"chars": 841,
"preview": "from typing import Any, ClassVar\n\nfrom rich.text import Text\nfrom textual.widgets import Static\n\nfrom .base_renderer imp"
},
{
"path": "strix/interface/tui.py",
"chars": 73362,
"preview": "import argparse\nimport asyncio\nimport atexit\nimport logging\nimport signal\nimport sys\nimport threading\nfrom collections.a"
},
{
"path": "strix/interface/utils.py",
"chars": 29195,
"preview": "import ipaddress\nimport json\nimport re\nimport secrets\nimport shutil\nimport subprocess\nimport sys\nimport tempfile\nfrom pa"
},
{
"path": "strix/llm/__init__.py",
"chars": 414,
"preview": "import logging\nimport warnings\n\nimport litellm\n\nfrom .config import LLMConfig\nfrom .llm import LLM, LLMRequestFailedErro"
},
{
"path": "strix/llm/config.py",
"chars": 1170,
"preview": "from strix.config import Config\nfrom strix.config.config import resolve_llm_config\nfrom strix.llm.utils import resolve_s"
},
{
"path": "strix/llm/dedupe.py",
"chars": 7121,
"preview": "import json\nimport logging\nimport re\nfrom typing import Any\n\nimport litellm\n\nfrom strix.config.config import resolve_llm"
},
{
"path": "strix/llm/llm.py",
"chars": 13668,
"preview": "import asyncio\nfrom collections.abc import AsyncIterator\nfrom dataclasses import dataclass\nfrom typing import Any\n\nimpor"
},
{
"path": "strix/llm/memory_compressor.py",
"chars": 7355,
"preview": "import logging\nfrom typing import Any\n\nimport litellm\n\nfrom strix.config.config import Config, resolve_llm_config\n\n\nlogg"
},
{
"path": "strix/llm/utils.py",
"chars": 5586,
"preview": "import html\nimport re\nfrom typing import Any\n\n\n_INVOKE_OPEN = re.compile(r'<invoke\\s+name=[\"\\']([^\"\\']+)[\"\\']>')\n_PARAM_"
},
{
"path": "strix/runtime/__init__.py",
"chars": 1146,
"preview": "from strix.config import Config\n\nfrom .runtime import AbstractRuntime\n\n\nclass SandboxInitializationError(Exception):\n "
},
{
"path": "strix/runtime/docker_runtime.py",
"chars": 13432,
"preview": "import contextlib\nimport os\nimport secrets\nimport socket\nimport time\nfrom pathlib import Path\nfrom typing import cast\n\ni"
},
{
"path": "strix/runtime/runtime.py",
"chars": 816,
"preview": "from abc import ABC, abstractmethod\nfrom typing import TypedDict\n\n\nclass SandboxInfo(TypedDict):\n workspace_id: str\n "
},
{
"path": "strix/runtime/tool_server.py",
"chars": 5057,
"preview": "from __future__ import annotations\n\nimport argparse\nimport asyncio\nimport os\nimport signal\nimport sys\nfrom typing import"
},
{
"path": "strix/skills/README.md",
"chars": 3105,
"preview": "# 📚 Strix Skills\n\n## 🎯 Overview\n\nSkills are specialized knowledge packages that enhance Strix agents with deep expertise"
},
{
"path": "strix/skills/__init__.py",
"chars": 5193,
"preview": "import re\n\nfrom strix.utils.resource_paths import get_strix_resource_path\n\n\n_EXCLUDED_CATEGORIES = {\"scan_modes\", \"coord"
},
{
"path": "strix/skills/cloud/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "strix/skills/coordination/root_agent.md",
"chars": 2788,
"preview": "---\nname: root-agent\ndescription: Orchestration layer that coordinates specialized subagents for security assessments\n--"
},
{
"path": "strix/skills/custom/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "strix/skills/frameworks/fastapi.md",
"chars": 7437,
"preview": "---\nname: fastapi\ndescription: Security testing playbook for FastAPI applications covering ASGI, dependency injection, a"
},
{
"path": "strix/skills/frameworks/nestjs.md",
"chars": 10645,
"preview": "---\nname: nestjs\ndescription: Security testing playbook for NestJS applications covering guards, pipes, decorators, modu"
},
{
"path": "strix/skills/frameworks/nextjs.md",
"chars": 7971,
"preview": "---\nname: nextjs\ndescription: Security testing playbook for Next.js covering App Router, Server Actions, RSC, and Edge r"
},
{
"path": "strix/skills/protocols/graphql.md",
"chars": 7990,
"preview": "---\nname: graphql\ndescription: GraphQL security testing covering introspection, resolver injection, batching attacks, an"
},
{
"path": "strix/skills/reconnaissance/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "strix/skills/scan_modes/deep.md",
"chars": 6532,
"preview": "---\nname: deep\ndescription: Exhaustive security assessment with maximum coverage, depth, and vulnerability chaining\n---\n"
},
{
"path": "strix/skills/scan_modes/quick.md",
"chars": 2678,
"preview": "---\nname: quick\ndescription: Time-boxed rapid assessment targeting high-impact vulnerabilities\n---\n\n# Quick Testing Mode"
},
{
"path": "strix/skills/scan_modes/standard.md",
"chars": 3622,
"preview": "---\nname: standard\ndescription: Balanced security assessment with systematic methodology and full attack surface coverag"
},
{
"path": "strix/skills/technologies/firebase_firestore.md",
"chars": 8427,
"preview": "---\nname: firebase-firestore\ndescription: Firebase/Firestore security testing covering security rules, Cloud Functions, "
},
{
"path": "strix/skills/technologies/supabase.md",
"chars": 9497,
"preview": "---\nname: supabase\ndescription: Supabase security testing covering Row Level Security, PostgREST, Edge Functions, and se"
},
{
"path": "strix/skills/tooling/ffuf.md",
"chars": 3018,
"preview": "---\nname: ffuf\ndescription: ffuf fuzzing syntax with matcher/filter strategy and non-interactive defaults.\n---\n\n# ffuf C"
},
{
"path": "strix/skills/tooling/httpx.md",
"chars": 3197,
"preview": "---\nname: httpx\ndescription: ProjectDiscovery httpx probing syntax, exact probe flags, and automation-safe output patter"
},
{
"path": "strix/skills/tooling/katana.md",
"chars": 3533,
"preview": "---\nname: katana\ndescription: Katana crawler syntax, depth/js/known-files behavior, and stable concurrency controls.\n---"
},
{
"path": "strix/skills/tooling/naabu.md",
"chars": 2911,
"preview": "---\nname: naabu\ndescription: Naabu port-scanning syntax with host input, scan-type, verification, and rate controls.\n---"
},
{
"path": "strix/skills/tooling/nmap.md",
"chars": 2867,
"preview": "---\nname: nmap\ndescription: Canonical Nmap CLI syntax, two-pass scanning workflow, and sandbox-safe bounded scan pattern"
},
{
"path": "strix/skills/tooling/nuclei.md",
"chars": 2839,
"preview": "---\nname: nuclei\ndescription: Exact Nuclei command structure, template selection, and bounded high-throughput execution "
},
{
"path": "strix/skills/tooling/semgrep.md",
"chars": 3557,
"preview": "---\nname: semgrep\ndescription: Exact Semgrep CLI structure, metrics-off scanning, scoped ruleset selection, and automati"
},
{
"path": "strix/skills/tooling/sqlmap.md",
"chars": 2876,
"preview": "---\nname: sqlmap\ndescription: sqlmap target syntax, non-interactive execution, and common validation/enumeration workflo"
},
{
"path": "strix/skills/tooling/subfinder.md",
"chars": 2577,
"preview": "---\nname: subfinder\ndescription: Subfinder passive subdomain enumeration syntax, source controls, and pipeline-ready out"
},
{
"path": "strix/skills/vulnerabilities/authentication_jwt.md",
"chars": 7950,
"preview": "---\nname: authentication-jwt\ndescription: JWT and OIDC security testing covering token forgery, algorithm confusion, and"
},
{
"path": "strix/skills/vulnerabilities/broken_function_level_authorization.md",
"chars": 6718,
"preview": "---\nname: broken-function-level-authorization\ndescription: BFLA testing for action-level authorization failures across e"
},
{
"path": "strix/skills/vulnerabilities/business_logic.md",
"chars": 9258,
"preview": "---\nname: business-logic\ndescription: Business logic testing for workflow bypass, state manipulation, and domain invaria"
},
{
"path": "strix/skills/vulnerabilities/csrf.md",
"chars": 8145,
"preview": "---\nname: csrf\ndescription: CSRF testing covering token bypass, SameSite cookies, CORS misconfigurations, and state-chan"
},
{
"path": "strix/skills/vulnerabilities/idor.md",
"chars": 9942,
"preview": "---\nname: idor\ndescription: IDOR/BOLA testing for object-level authorization failures and cross-account data access\n---\n"
},
{
"path": "strix/skills/vulnerabilities/information_disclosure.md",
"chars": 8493,
"preview": "---\nname: information-disclosure\ndescription: Information disclosure testing covering error messages, debug endpoints, m"
},
{
"path": "strix/skills/vulnerabilities/insecure_file_uploads.md",
"chars": 8703,
"preview": "---\nname: insecure-file-uploads\ndescription: File upload security testing covering extension bypass, content-type manipu"
},
{
"path": "strix/skills/vulnerabilities/mass_assignment.md",
"chars": 6277,
"preview": "---\nname: mass-assignment\ndescription: Mass assignment testing for unauthorized field binding and privilege escalation v"
},
{
"path": "strix/skills/vulnerabilities/open_redirect.md",
"chars": 6660,
"preview": "---\nname: open-redirect\ndescription: Open redirect testing for phishing pivots, OAuth token theft, and allowlist bypass\n"
},
{
"path": "strix/skills/vulnerabilities/path_traversal_lfi_rfi.md",
"chars": 7805,
"preview": "---\nname: path-traversal-lfi-rfi\ndescription: Path traversal and file inclusion testing for local/remote file access and"
},
{
"path": "strix/skills/vulnerabilities/race_conditions.md",
"chars": 7831,
"preview": "---\nname: race-conditions\ndescription: Race condition testing for TOCTOU bugs, double-spend, and concurrent state manipu"
},
{
"path": "strix/skills/vulnerabilities/rce.md",
"chars": 7723,
"preview": "---\nname: rce\ndescription: RCE testing covering command injection, deserialization, template injection, and code evaluat"
},
{
"path": "strix/skills/vulnerabilities/sql_injection.md",
"chars": 8477,
"preview": "---\nname: sql-injection\ndescription: SQL injection testing covering union, blind, error-based, and ORM bypass techniques"
},
{
"path": "strix/skills/vulnerabilities/ssrf.md",
"chars": 7991,
"preview": "---\nname: ssrf\ndescription: SSRF testing for cloud metadata access, internal service discovery, and protocol smuggling\n-"
},
{
"path": "strix/skills/vulnerabilities/subdomain_takeover.md",
"chars": 7136,
"preview": "---\nname: subdomain-takeover\ndescription: Subdomain takeover testing for dangling DNS records and unclaimed cloud resour"
},
{
"path": "strix/skills/vulnerabilities/xss.md",
"chars": 7452,
"preview": "---\nname: xss\ndescription: XSS testing covering reflected, stored, and DOM-based vectors with CSP bypass techniques\n---\n"
},
{
"path": "strix/skills/vulnerabilities/xxe.md",
"chars": 7176,
"preview": "---\nname: xxe\ndescription: XXE testing for external entity injection, file disclosure, and SSRF via XML parsers\n---\n\n# X"
},
{
"path": "strix/telemetry/README.md",
"chars": 1952,
"preview": "### Overview\n\nTo help make Strix better for everyone, we collect anonymized data that helps us understand how to better "
},
{
"path": "strix/telemetry/__init__.py",
"chars": 182,
"preview": "from . import posthog\nfrom .tracer import Tracer, get_global_tracer, set_global_tracer\n\n\n__all__ = [\n \"Tracer\",\n \""
},
{
"path": "strix/telemetry/flags.py",
"chars": 708,
"preview": "from strix.config import Config\n\n\n_DISABLED_VALUES = {\"0\", \"false\", \"no\", \"off\"}\n\n\ndef _is_enabled(raw_value: str | None"
},
{
"path": "strix/telemetry/posthog.py",
"chars": 3769,
"preview": "import json\nimport platform\nimport sys\nimport urllib.request\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, "
},
{
"path": "strix/telemetry/tracer.py",
"chars": 31718,
"preview": "import json\nimport logging\nimport threading\nfrom datetime import UTC, datetime\nfrom pathlib import Path\nfrom typing impo"
},
{
"path": "strix/telemetry/utils.py",
"chars": 13769,
"preview": "import json\nimport logging\nimport re\nimport threading\nfrom collections.abc import Callable, Sequence\nfrom datetime impor"
},
{
"path": "strix/tools/__init__.py",
"chars": 1323,
"preview": "from .agents_graph import * # noqa: F403\nfrom .browser import * # noqa: F403\nfrom .executor import (\n execute_tool,"
},
{
"path": "strix/tools/agents_graph/__init__.py",
"chars": 278,
"preview": "from .agents_graph_actions import (\n agent_finish,\n create_agent,\n send_message_to_agent,\n view_agent_graph,"
},
{
"path": "strix/tools/agents_graph/agents_graph_actions.py",
"chars": 20672,
"preview": "import threading\nfrom datetime import UTC, datetime\nfrom typing import Any, Literal\n\nfrom strix.tools.registry import re"
},
{
"path": "strix/tools/agents_graph/agents_graph_actions_schema.xml",
"chars": 12563,
"preview": "<tools>\n <tool name=\"agent_finish\">\n <description>Mark a subagent's task as completed and optionally report results "
},
{
"path": "strix/tools/argument_parser.py",
"chars": 3861,
"preview": "import contextlib\nimport inspect\nimport json\nimport types\nfrom collections.abc import Callable\nfrom typing import Any, U"
},
{
"path": "strix/tools/browser/__init__.py",
"chars": 75,
"preview": "from .browser_actions import browser_action\n\n\n__all__ = [\"browser_action\"]\n"
},
{
"path": "strix/tools/browser/browser_actions.py",
"chars": 7140,
"preview": "from typing import TYPE_CHECKING, Any, Literal, NoReturn\n\nfrom strix.tools.registry import register_tool\n\n\nif TYPE_CHECK"
},
{
"path": "strix/tools/browser/browser_actions_schema.xml",
"chars": 9949,
"preview": "<tools>\n <tool name=\"browser_action\">\n <description>Perform browser actions using a Playwright-controlled browser wi"
},
{
"path": "strix/tools/browser/browser_instance.py",
"chars": 19925,
"preview": "import asyncio\nimport base64\nimport contextlib\nimport logging\nimport threading\nfrom pathlib import Path\nfrom typing impo"
},
{
"path": "strix/tools/browser/tab_manager.py",
"chars": 13338,
"preview": "import atexit\nimport contextlib\nimport threading\nfrom typing import Any\n\nfrom strix.tools.context import get_current_age"
},
{
"path": "strix/tools/context.py",
"chars": 280,
"preview": "from contextvars import ContextVar\n\n\ncurrent_agent_id: ContextVar[str] = ContextVar(\"current_agent_id\", default=\"default"
},
{
"path": "strix/tools/executor.py",
"chars": 12665,
"preview": "import inspect\nimport os\nfrom typing import Any\n\nimport httpx\n\nfrom strix.config import Config\nfrom strix.telemetry impo"
},
{
"path": "strix/tools/file_edit/__init__.py",
"chars": 141,
"preview": "from .file_edit_actions import list_files, search_files, str_replace_editor\n\n\n__all__ = [\"list_files\", \"search_files\", \""
},
{
"path": "strix/tools/file_edit/file_edit_actions.py",
"chars": 4017,
"preview": "import json\nimport re\nfrom pathlib import Path\nfrom typing import Any, cast\n\nfrom strix.tools.registry import register_t"
},
{
"path": "strix/tools/file_edit/file_edit_actions_schema.xml",
"chars": 6815,
"preview": "<tools>\n <tool name=\"list_files\">\n <description>List files and directories within the specified directory.</descript"
},
{
"path": "strix/tools/finish/__init__.py",
"chars": 68,
"preview": "from .finish_actions import finish_scan\n\n\n__all__ = [\"finish_scan\"]\n"
},
{
"path": "strix/tools/finish/finish_actions.py",
"chars": 5085,
"preview": "from typing import Any\n\nfrom strix.tools.registry import register_tool\n\n\ndef _validate_root_agent(agent_state: Any) -> d"
},
{
"path": "strix/tools/finish/finish_actions_schema.xml",
"chars": 12949,
"preview": "<tools>\n <tool name=\"finish_scan\">\n <description>Complete the security scan by providing the final assessment fields"
},
{
"path": "strix/tools/load_skill/__init__.py",
"chars": 70,
"preview": "from .load_skill_actions import load_skill\n\n\n__all__ = [\"load_skill\"]\n"
},
{
"path": "strix/tools/load_skill/load_skill_actions.py",
"chars": 2635,
"preview": "from typing import Any\n\nfrom strix.tools.registry import register_tool\n\n\n@register_tool(sandbox_execution=False)\ndef loa"
},
{
"path": "strix/tools/load_skill/load_skill_actions_schema.xml",
"chars": 1579,
"preview": "<tools>\n <tool name=\"load_skill\">\n <description>Dynamically load one or more skills into the current agent at runtim"
},
{
"path": "strix/tools/notes/__init__.py",
"chars": 189,
"preview": "from .notes_actions import (\n create_note,\n delete_note,\n list_notes,\n update_note,\n)\n\n\n__all__ = [\n \"cre"
},
{
"path": "strix/tools/notes/notes_actions.py",
"chars": 4907,
"preview": "import uuid\nfrom datetime import UTC, datetime\nfrom typing import Any\n\nfrom strix.tools.registry import register_tool\n\n\n"
},
{
"path": "strix/tools/notes/notes_actions_schema.xml",
"chars": 6083,
"preview": "<tools>\n <tool name=\"create_note\">\n <description>Create a personal note for observations, findings, and research dur"
},
{
"path": "strix/tools/proxy/__init__.py",
"chars": 329,
"preview": "from .proxy_actions import (\n list_requests,\n list_sitemap,\n repeat_request,\n scope_rules,\n send_request,"
},
{
"path": "strix/tools/proxy/proxy_actions.py",
"chars": 2849,
"preview": "from typing import Any, Literal\n\nfrom strix.tools.registry import register_tool\n\n\nRequestPart = Literal[\"request\", \"resp"
},
{
"path": "strix/tools/proxy/proxy_actions_schema.xml",
"chars": 11538,
"preview": "<tools>\n <tool name=\"list_requests\">\n <description>List and filter proxy requests using HTTPQL with pagination.</des"
},
{
"path": "strix/tools/proxy/proxy_manager.py",
"chars": 29186,
"preview": "import base64\nimport os\nimport re\nimport time\nfrom typing import TYPE_CHECKING, Any\nfrom urllib.parse import parse_qs, u"
},
{
"path": "strix/tools/python/__init__.py",
"chars": 72,
"preview": "from .python_actions import python_action\n\n\n__all__ = [\"python_action\"]\n"
},
{
"path": "strix/tools/python/python_actions.py",
"chars": 1436,
"preview": "from typing import Any, Literal\n\nfrom strix.tools.registry import register_tool\n\n\nPythonAction = Literal[\"new_session\", "
},
{
"path": "strix/tools/python/python_actions_schema.xml",
"chars": 7443,
"preview": "<tools>\n <tool name=\"python_action\">\n <description>Perform Python actions using persistent interpreter sessions for "
},
{
"path": "strix/tools/python/python_instance.py",
"chars": 5965,
"preview": "import io\nimport sys\nimport threading\nfrom typing import Any\n\nfrom IPython.core.interactiveshell import InteractiveShell"
},
{
"path": "strix/tools/python/python_manager.py",
"chars": 4851,
"preview": "import atexit\nimport contextlib\nimport threading\nfrom typing import Any\n\nfrom strix.tools.context import get_current_age"
},
{
"path": "strix/tools/registry.py",
"chars": 9189,
"preview": "import inspect\nimport logging\nimport os\nfrom collections.abc import Callable\nfrom functools import wraps\nfrom inspect im"
},
{
"path": "strix/tools/reporting/__init__.py",
"chars": 110,
"preview": "from .reporting_actions import create_vulnerability_report\n\n\n__all__ = [\n \"create_vulnerability_report\",\n]\n"
},
{
"path": "strix/tools/reporting/reporting_actions.py",
"chars": 11190,
"preview": "import contextlib\nimport re\nfrom pathlib import PurePosixPath\nfrom typing import Any\n\nfrom strix.tools.registry import r"
},
{
"path": "strix/tools/reporting/reporting_actions_schema.xml",
"chars": 21646,
"preview": "<tools>\n <tool name=\"create_vulnerability_report\">\n <description>Create a vulnerability report for a discovered secu"
},
{
"path": "strix/tools/terminal/__init__.py",
"chars": 80,
"preview": "from .terminal_actions import terminal_execute\n\n\n__all__ = [\"terminal_execute\"]\n"
},
{
"path": "strix/tools/terminal/terminal_actions.py",
"chars": 892,
"preview": "from typing import Any\n\nfrom strix.tools.registry import register_tool\n\n\n@register_tool\ndef terminal_execute(\n comman"
},
{
"path": "strix/tools/terminal/terminal_actions_schema.xml",
"chars": 7360,
"preview": "<tools>\n <tool name=\"terminal_execute\">\n <description>Execute a bash command in a persistent terminal session. The t"
},
{
"path": "strix/tools/terminal/terminal_manager.py",
"chars": 5415,
"preview": "import atexit\nimport contextlib\nimport threading\nfrom typing import Any\n\nfrom strix.tools.context import get_current_age"
},
{
"path": "strix/tools/terminal/terminal_session.py",
"chars": 16008,
"preview": "import logging\nimport re\nimport time\nimport uuid\nfrom enum import Enum\nfrom pathlib import Path\nfrom typing import Any\n\n"
},
{
"path": "strix/tools/thinking/__init__.py",
"chars": 58,
"preview": "from .thinking_actions import think\n\n\n__all__ = [\"think\"]\n"
},
{
"path": "strix/tools/thinking/thinking_actions.py",
"chars": 564,
"preview": "from typing import Any\n\nfrom strix.tools.registry import register_tool\n\n\n@register_tool(sandbox_execution=False)\ndef thi"
},
{
"path": "strix/tools/thinking/thinking_actions_schema.xml",
"chars": 2260,
"preview": "<tools>\n <tool name=\"think\">\n <description>Use the tool to think about something. It will not obtain new information"
},
{
"path": "strix/tools/todo/__init__.py",
"chars": 278,
"preview": "from .todo_actions import (\n create_todo,\n delete_todo,\n list_todos,\n mark_todo_done,\n mark_todo_pending,"
},
{
"path": "strix/tools/todo/todo_actions.py",
"chars": 17238,
"preview": "import json\nimport uuid\nfrom datetime import UTC, datetime\nfrom typing import Any\n\nfrom strix.tools.registry import regi"
},
{
"path": "strix/tools/todo/todo_actions_schema.xml",
"chars": 10107,
"preview": "<tools>\n <important>\n The todo tool is available for organizing complex tasks when needed. Each subagent has their own"
},
{
"path": "strix/tools/web_search/__init__.py",
"chars": 70,
"preview": "from .web_search_actions import web_search\n\n\n__all__ = [\"web_search\"]\n"
},
{
"path": "strix/tools/web_search/web_search_actions.py",
"chars": 3142,
"preview": "import os\nfrom typing import Any\n\nimport requests\n\nfrom strix.tools.registry import register_tool\n\n\nSYSTEM_PROMPT = \"\"\"Y"
},
{
"path": "strix/tools/web_search/web_search_actions_schema.xml",
"chars": 4805,
"preview": "<tools>\n <tool name=\"web_search\">\n <description>Search the web using Perplexity AI for real-time information and cur"
},
{
"path": "strix/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "strix/utils/resource_paths.py",
"chars": 351,
"preview": "import sys\nfrom pathlib import Path\n\n\ndef get_strix_resource_path(*parts: str) -> Path:\n frozen_base = getattr(sys, \""
},
{
"path": "strix.spec",
"chars": 4832,
"preview": "# -*- mode: python ; coding: utf-8 -*-\n\nimport sys\nfrom pathlib import Path\nfrom PyInstaller.utils.hooks import collect_"
},
{
"path": "tests/__init__.py",
"chars": 19,
"preview": "# Strix Test Suite\n"
},
{
"path": "tests/agents/__init__.py",
"chars": 37,
"preview": "\"\"\"Tests for strix.agents module.\"\"\"\n"
},
{
"path": "tests/config/__init__.py",
"chars": 37,
"preview": "\"\"\"Tests for strix.config module.\"\"\"\n"
},
{
"path": "tests/config/test_config_telemetry.py",
"chars": 1813,
"preview": "import json\n\nfrom strix.config.config import Config\n\n\ndef test_traceloop_vars_are_tracked() -> None:\n tracked = Confi"
},
{
"path": "tests/conftest.py",
"chars": 64,
"preview": "\"\"\"Pytest configuration and shared fixtures for Strix tests.\"\"\"\n"
},
{
"path": "tests/interface/__init__.py",
"chars": 40,
"preview": "\"\"\"Tests for strix.interface module.\"\"\"\n"
},
{
"path": "tests/llm/__init__.py",
"chars": 34,
"preview": "\"\"\"Tests for strix.llm module.\"\"\"\n"
},
{
"path": "tests/llm/test_llm_otel.py",
"chars": 472,
"preview": "import litellm\n\nfrom strix.llm.config import LLMConfig\nfrom strix.llm.llm import LLM\n\n\ndef test_llm_does_not_modify_lite"
},
{
"path": "tests/runtime/__init__.py",
"chars": 38,
"preview": "\"\"\"Tests for strix.runtime module.\"\"\"\n"
},
{
"path": "tests/skills/__init__.py",
"chars": 44,
"preview": "# Tests for skill-related runtime behavior.\n"
},
{
"path": "tests/telemetry/__init__.py",
"chars": 40,
"preview": "\"\"\"Tests for strix.telemetry module.\"\"\"\n"
},
{
"path": "tests/telemetry/test_flags.py",
"chars": 1020,
"preview": "from strix.telemetry.flags import is_otel_enabled, is_posthog_enabled\n\n\ndef test_flags_fallback_to_strix_telemetry(monke"
}
]
// ... and 7 more files (download for full content)
About this extraction
This page contains the full source code of the usestrix/strix GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 207 files (1.1 MB), approximately 265.7k tokens, and a symbol index with 882 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.