Skip to main content

A safe bridge between AI assistants and your computer

Project description

Solveig

PyPI CI codecov Python 3.12+ License: GPL v3 Code style: black

demo

A safe bridge between AI assistants and your computer.

Solveig transforms any LLM into a practical assistant that can read files and run commandsโ€”with your explicit approval for every operation. No more copying and pasting between your terminal and ChatGPT.

๐Ÿ”’ Safe โ€ข 160+ tests with 83% coverage โ€ข Secure file API โ€ข Command validation
๐Ÿš€ Useful โ€ข Works with any OpenAI-compatible API โ€ข Handles real tasks efficiently
๐Ÿงฉ Extensible โ€ข Drop-in plugin system โ€ข Easy to customize and extend


๐Ÿš€ Quick start

# Install from source:
git clone https://github.com/FranciscoSilveira/solveig.git
cd solveig
pip install -e .

# Or install from PyPI:
pip install solveig

# Run a local model:
solveig -u "http://localhost:5001/v1" "Tell me a joke"

# Run from a remote API like OpenRouter:
solveig -u "https://openrouter.ai/api/v1" -k "<API_KEY>" -m "moonshotai/kimi-k2:free" "Summarize my day"


โ“ FAQ

What is Solveig?

A terminal AI helper that can request file access and run commands with your explicit approval.

Is Solveig an LLM like ChatGPT?

No, it's a safe interface between LLM services and your computer. It can use ChatGPT, Claude, or any OpenAI-compatible service.

Why use Solveig instead of a plain LLM?

LLMs can only work with what you manually provide. If ChatGPT needs a file or command output, you have to copy-paste it yourself. Solveig lets the LLM request exactly what it needs, and you just approve or deny each request.

Why use Solveig over other LLMโ€‘toโ€‘shell assistants?

Solveig focuses on preventing dangerous operations through explicit user consent and validation. It prefers direct file access over arbitrary commands when possible, and validates commands with Shellcheck before execution.

Is Solveig safe to run?

Solveig requires your approval for every file read, write, or command execution. It uses Shellcheck to validate commands and catch dangerous patterns. However, you're ultimately responsible for reviewing and denying any request you don't understand.

This is still a tool that connects an AI to your computer - always review what it wants to do.


๐ŸŽญ Examples

These were obtained with Kimi K2 on OpenRouter.

click to expand:

Do any of the files in ~/Sync look dangerous?
โ”€โ”€โ”€ User โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Reply:
 > Do any of the files in ~/Sync look dangerous?

โ ‡ Waiting... (Ctrl+C to stop)

โ”€โ”€โ”€ Assistant โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ  I'll check the contents of your ~/Sync directory to identify any potentially dangerous files. Let me start by reading the directory structure and then examine the files within.
[ Requirements (1) ]
  [ Read (1) ]
    โ  First, let me read the ~/Sync directory to see what files are present
    ๐Ÿ—  ~/Sync  (/home/francisco/Sync)

โ”€โ”€โ”€ User โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
[ Results (1) ]
  [ Read ]
    โ  First, let me read the ~/Sync directory to see what files are present
    ๐Ÿ—  ~/Sync  (/home/francisco/Sync)
    โ”Œโ”€โ”€โ”€ Metadata โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚ ๐Ÿ— /home/francisco/Sync | owner_name=francisco | group_name=francisco | path=/home/francisco/Sync | size=4096 | modified_time=Wed ... โ”‚
    โ”‚ โ”œโ”€๐Ÿ— d1                                                                                                                               โ”‚
    โ”‚ โ”œโ”€๐Ÿ—Ž dev.sh                                                                                                                           โ”‚
    โ”‚ โ”œโ”€๐Ÿ—Ž f1                                                                                                                               โ”‚
    โ”‚ โ”œโ”€๐Ÿ—Ž hello.py                                                                                                                         โ”‚
    โ”‚ โ”œโ”€๐Ÿ—Ž j1.json                                                                                                                          โ”‚
    โ”‚ โ”œโ”€๐Ÿ—Ž run.sh.bak                                                                                                                       โ”‚
    โ”‚ โ””โ”€๐Ÿ—Ž stuff.txt                                                                                                                        โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    ?  Allow sending metadata? [y/N]: y
  
?  >  

โ  Waiting... (Ctrl+C to stop)

โ”€โ”€โ”€ Assistant โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ  I can see several files in your ~/Sync directory. Let me examine the contents of the potentially executable files (shell scripts and Python files) to check if they contain any dangerous commands.
[ Requirements (3) ]
  [ Read (3) ]
    โ  Checking the dev.sh shell script for potentially dangerous commands
    ๐Ÿ—Ž  ~/Sync/dev.sh  (/home/francisco/Sync/dev.sh)
    โ  Checking the hello.py Python script for potentially dangerous code
    ๐Ÿ—Ž  ~/Sync/hello.py  (/home/francisco/Sync/hello.py)
    โ  Checking the run.sh.bak backup shell script for potentially dangerous commands
    ๐Ÿ—Ž  ~/Sync/run.sh.bak  (/home/francisco/Sync/run.sh.bak)


๐Ÿงฉ Plugins

Solveig has an extensible plugin system that automatically discovers and loads plugins on startup.

Plugin Types:

  1. Hook into requirements: Use @before() or @after() decorators to validate or process existing requirements (file/command operations)
  2. Schema extensions: Create new requirement types that the LLM can request by extending Requirement and implementing _actually_solve()
  3. Plugin tests: Add comprehensive test suites in tests/plugins/test_my_plugin.py

Adding a hook plugin:

  1. Create a file in solveig/plugins/hooks/my_plugin.py
  2. Use decorators: @before(requirements=(CommandRequirement,)), @after(), both, or neither
  3. Add tests in tests/plugins/test_my_plugin.py following the existing patterns
  4. Plugins auto-load when Solveig starts - no configuration needed!

Check out solveig/plugins/hooks/shellcheck.py and tests/plugins/test_shellcheck.py for complete examples.

Examples:

click to expand:

Block dangerous commands with custom patterns
from solveig.config import SolveigConfig
from solveig.plugins.hooks import before
from solveig.plugins.exceptions import SecurityError
from solveig.schema.requirement import CommandRequirement

@before(requirements=(CommandRequirement,))
def block_dangerous_commands(config: SolveigConfig, requirement: CommandRequirement):
    """Block commands that could be dangerous to system security."""
    dangerous_patterns = [
        "sudo chmod 777",
        "wget http://",  # Block HTTP downloads
        "curl http://",
        "dd if=",        # Block disk operations
    ]
    
    for pattern in dangerous_patterns:
        if pattern in requirement.command:
            raise SecurityError(f"Blocked dangerous command pattern: {pattern}")
Anonymize all paths before sending to LLM
import re

from solveig.config import SolveigConfig
from solveig.plugins.hooks import after
from solveig.plugins.exceptions import ProcessingError
from solveig.schema.requirement import ReadRequirement, WriteRequirement
from solveig.schema.result import ReadResult, WriteResult

@after(requirements=(ReadRequirement, WriteRequirement))
def anonymize_paths(config: SolveigConfig, requirement: ReadRequirement|WriteRequirement, result: ReadResult|WriteResult):
    """Anonymize file paths in results before sending to LLM."""
    try:
        original_path = result.metadata['path']
    except:
        return
    anonymous_path = re.sub(r"/home/\w+", "/home/jdoe", original_path)
    anonymous_path = re.sub(r"^([A-Z]:\\Users\\)[^\\]+", r"\1JohnDoe", anonymous_path, flags=re.IGNORECASE)
    result.metadata['path'] = anonymous_path

๐Ÿค Contributing

We use modern Python tooling to maintain code quality and consistency:

Development Tools

All code is automatically checked on main and develop branches:

  1. Formatting: black . - Ensures consistent code style
  2. Linting: ruff check . - Catches potential bugs and code quality issues
  3. Type checking: mypy solveig/ scripts/ --ignore-missing-imports - Validates type hints
  4. Testing: pytest - Runs full test suite with coverage reporting

Testing Philosophy

Solveig follows strict testing guidelines to ensure reliability and safety:

Test Coverage Requirements

  • Success and failure paths: Every feature must test both successful execution and error conditions
  • Mock only when necessary: Mock only low-level I/O behavior with potential side effects
  • No untested code paths: All business logic, error handling, and user interactions must be tested

Testing Architecture

Unit Tests (tests/unit/):

  • Mock all I/O and side-effect operations (file system, user interface, external commands)
  • Use minimal mocking: Mock only the lowest-level behaviors while keeping high-level logic unmocked
  • Mock framework provides utility methods for easy test setup (mock filesystem with directory structure)
  • Test real object serialization and business logic with actual Pydantic models
  • Config tests use cli_args to bypass reading sys.argv and pass mock values without complex patching

Integration Tests (tests/integration/):

  • Allow real file I/O operations using temporary directories
  • Mock only user interactions to avoid interactive prompts
  • Test full stack from requirement parsing to actual file operations
  • Marked with @pytest.mark.no_file_mocking to bypass file system mocks

Mocking Strategy:

  • File operations: Mock solveig.utils.file methods for filesystem interactions
  • User interface: Mock input/output methods while preserving all display logic and formatting
  • External commands: Mock subprocess calls and command execution
  • Real objects: Never mock requirement/result objects - test actual Pydantic serialization

Running Tests

# Install with testing dependencies:
pip install -e .[dev]

# Unit tests only
python -m pytest tests/unit/ -v

# Integration tests only  
python -m pytest tests/integration/ -v

# Specific test class
python -m pytest tests/unit/test_main.py::TestInitializeConversation -v

# Run all checks locally (same as CI) 
black . && ruff check . && mypy solveig/ scripts/ --ignore-missing-imports && pytest ./tests/ --cov=solveig --cov=scripts --cov-report=term-missing -vv

Test Organization

tests/
โ”œโ”€โ”€ unit/           # Unit tests
โ”œโ”€โ”€ integration/    # Integration tests
โ”œโ”€โ”€ mocks/          # Mock implementations
โ””โ”€โ”€ plugins/        # Plugin-specific tests

๐Ÿ“ˆ Roadmap

Next Steps:

  • Enhanced command validation with Semgrep static analysis
  • Second-opinion LLM validation for generated commands
  • Improve test coverage
  • API integration for Claude/Gemini

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

solveig-0.2.9.tar.gz (80.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

solveig-0.2.9-py3-none-any.whl (69.7 kB view details)

Uploaded Python 3

File details

Details for the file solveig-0.2.9.tar.gz.

File metadata

  • Download URL: solveig-0.2.9.tar.gz
  • Upload date:
  • Size: 80.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for solveig-0.2.9.tar.gz
Algorithm Hash digest
SHA256 cb8da29b186c377408cbdea836a966b3f63479470d057408d342d49f7905bcfe
MD5 e2af0bf819f730841e91738edd3cc5a5
BLAKE2b-256 7984d34f7f69138038fb6e56e7d7cef24be081247e61fb6d0f4d7628615cd0a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for solveig-0.2.9.tar.gz:

Publisher: cd.yml on FranciscoSilveira/solveig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file solveig-0.2.9-py3-none-any.whl.

File metadata

  • Download URL: solveig-0.2.9-py3-none-any.whl
  • Upload date:
  • Size: 69.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for solveig-0.2.9-py3-none-any.whl
Algorithm Hash digest
SHA256 047fa741e6f002e491d1f8db66a3757438e860ff241ed64b3bc9ec3da3980af1
MD5 406361d145c30582b215793917458dba
BLAKE2b-256 73f6aad199d3becbafa17ccd729c380e3519f7e927e4a7fca1c329f77d379f2b

See more details on using hashes here.

Provenance

The following attestation bundles were made for solveig-0.2.9-py3-none-any.whl:

Publisher: cd.yml on FranciscoSilveira/solveig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page