Skip to main content

A classic Smalltalk IDE for GemStone/Smalltalk

Project description

Swordfish

A classic Smalltalk IDE for GemStone/Smalltalk developed by Reahl Software Services.

Overview

Swordfish is a Python-based IDE that provides a classic Smalltalk development experience for GemStone/Smalltalk. It features class/method browsing, method editing, debugging capabilities with stepping functionality, and an object inspector.

This project was developed as an experiment in AI-assisted programming, with significant portions (including this README and other metadata) generated through collaboration between human developers and AI, followed by developer refinement and refactoring.

Features

  • Class and method browsing
  • Method editing
  • Debugging with step execution
  • Object inspection
  • Classic Smalltalk IDE experience

Technical Details

Swordfish is built with:

  • Python
  • Tcl/Tk for the GUI interface (implemented without prior knowledge of the toolkit)
  • Parseltongue (reahl-parseltongue) - library that enables calling GemStone/Smalltalk methods from Python

IDE

This section covers using Swordfish as a GUI IDE via the swordfish command.

Installation

For Docker-based development of both IDE and MCP, see How to Develop (Docker) at the end of this README.

From PyPI (Recommended)

# Create a virtual environment (optional but recommended)
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install from PyPI
pip install reahl-swordfish

From Source

# Clone the repository
git clone https://github.com/reahl/swordfish.git
cd swordfish

# Set up a virtual environment (optional but recommended)
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install in development mode
pip install -e .

Run the IDE

# After installation, run directly from command line
swordfish

# Or if installed from source
python -m swordfish

MCP

Swordfish includes MCP modes on the same swordfish executable.

Install

pip install reahl-swordfish

Run the server

swordfish --headless-mcp

Attach Claude to a running IDE/MCP process

To let Claude connect to an MCP server hosted inside an already-running IDE process, start the GUI (it now starts embedded MCP automatically):

# Run inside the container (GUI + embedded MCP)
swordfish --mcp-host 0.0.0.0 --mcp-port 9177 --mcp-http-path /mcp

Then configure Claude outside the container to use that URL:

claude mcp remove -s project swordfish 2>/dev/null || true
claude mcp add -s project --transport http swordfish http://127.0.0.1:9177/mcp
claude mcp list

If your IDE/MCP runs on a different host/port/path, change the URL accordingly. stdio mode cannot attach to an already-running process. In the GUI, use the MCP menu to start/stop the embedded server and edit runtime MCP policy/network settings.

Add MCP to Claude Code and Codex (Docker-over-SSH)

For Docker and SSH setup details used by this flow, see How to Develop (Docker) at the end of this README.

Start the development container with SSH enabled in one terminal and keep it running:

./docker-start.sh --enable-ssh --ssh-pubkey-file ~/.ssh/id_ed25519.pub --foreground

In another terminal, from the project root, configure MCP clients to launch swordfish --headless-mcp through docker-run-over-ssh.sh:

PROJECT_DIR="$(pwd)"

# Claude Code
claude mcp remove -s project swordfish 2>/dev/null || true
claude mcp add -s project swordfish -- "$PROJECT_DIR/docker-run-over-ssh.sh" swordfish --headless-mcp --allow-compile --allow-tracing
claude mcp list

# Codex
codex mcp remove swordfish 2>/dev/null || true
codex mcp add swordfish -- "$PROJECT_DIR/docker-run-over-ssh.sh" swordfish --headless-mcp --allow-compile --allow-tracing
codex mcp list --json

To enable eval/commit with human-approval handshakes, add:

--allow-eval --allow-commit

Add --allow-eval to enable gs_eval and gs_debug_eval. When enabled, each eval call requires explicit human confirmation:

  • Provide approved_by_user=true and a non-empty approval_note.
  • Keep unsafe=True and a non-empty reason. Add --allow-commit only when you explicitly want transactions to persist. When enabled, gs_commit always requires explicit human approval:
  • Provide approved_by_user=true and a non-empty approval_note on each gs_commit call. Add --require-gemstone-ast to enforce AST-strict refactoring mode; when enabled, heuristic refactoring tools are blocked unless real GemStone AST adapter support is available. In strict mode, refactoring actions attempt an automatic AST support install/refresh when possible. For new AI sessions, call gs_capabilities first to discover active policy switches and available workflows, then call gs_guidance for task-specific tool selection and sequencing. For normal browse/edit/test workflows, prefer explicit tools like: gs_create_class, gs_create_class_in_package, gs_create_test_case_class, gs_compile_method, and gs_run_gemstone_tests. For selector exploration, use gs_find_implementors and gs_find_senders instead of free-form evaluation. Both support max_results and count_only. For method-level semantic navigation, use gs_method_ast, gs_method_sends, gs_method_structure_summary, and gs_method_control_flow_summary to inspect statement structure, send sites, structural counts, and control-flow signals. For versioned image support of AST helpers, use gs_ast_status to inspect manifest/hash status and gs_ast_install to install or refresh AST support code in the connected GemStone image. For pattern-based method discovery across a scope, use gs_query_methods_by_ast_pattern and tune ranking with sort_by / sort_descending. For class-scoped method renames, use gs_preview_rename_method and gs_apply_rename_method instead of a global selector rename. For class-scoped method moves, use gs_preview_move_method before gs_apply_move_method, and review sender warnings before deleting the source. For class-scoped parameter addition with compatibility forwarding, use gs_preview_add_parameter then gs_apply_add_parameter. For class-scoped parameter removal with compatibility forwarding, use gs_preview_remove_parameter then gs_apply_remove_parameter; when you want to update same-class callers immediately, set rewrite_source_senders=true. For statement-level method extraction in one class/side, use gs_preview_extract_method then gs_apply_extract_method. For conservative unary self-send inline in one caller method, use gs_preview_inline_method then gs_apply_inline_method. For optional tracer installation, use gs_tracer_install and verify with gs_tracer_status before enabling via gs_tracer_enable. For runtime caller evidence, use gs_tracer_trace_selector, run your tests, then query gs_tracer_find_observed_senders. Tracer and evidence tools require MCP startup with --allow-tracing. Use gs_plan_evidence_tests to build a static candidate test superset and gs_collect_sender_evidence to run that plan and collect observed callers. When you do use gs_eval, pass unsafe=True, approved_by_user=true, a non-empty approval_note, and a non-empty reason. Write tools require an explicit transaction: call gs_begin before writes, then gs_commit (or gs_abort) when done. With default policy, gs_commit is disabled unless the MCP server is started with --allow-commit and explicit confirmation is supplied.

The server identifies itself as SwordfishMCP and currently supports:

  • gs_connect
  • gs_disconnect
  • gs_begin
  • gs_begin_if_needed
  • gs_commit
  • gs_abort
  • gs_transaction_status
  • gs_capabilities
  • gs_guidance
  • gs_list_packages
  • gs_list_classes
  • gs_list_method_categories
  • gs_list_methods
  • gs_get_method_source
  • gs_find_classes
  • gs_find_selectors
  • gs_find_implementors
  • gs_find_senders
  • gs_ast_status
  • gs_ast_install
  • gs_method_ast
  • gs_method_sends
  • gs_method_structure_summary
  • gs_method_control_flow_summary
  • gs_query_methods_by_ast_pattern
  • gs_preview_rename_method
  • gs_apply_rename_method
  • gs_preview_move_method
  • gs_apply_move_method
  • gs_preview_add_parameter
  • gs_apply_add_parameter
  • gs_preview_remove_parameter
  • gs_apply_remove_parameter
  • gs_preview_extract_method
  • gs_apply_extract_method
  • gs_preview_inline_method
  • gs_apply_inline_method
  • gs_tracer_status
  • gs_tracer_install
  • gs_tracer_enable
  • gs_tracer_disable
  • gs_tracer_uninstall
  • gs_tracer_trace_selector
  • gs_tracer_untrace_selector
  • gs_tracer_clear_observed_senders
  • gs_tracer_find_observed_senders
  • gs_plan_evidence_tests
  • gs_collect_sender_evidence
  • gs_create_class
  • gs_create_test_case_class
  • gs_get_class_definition
  • gs_delete_class
  • gs_compile_method
  • gs_delete_method
  • gs_set_method_category
  • gs_preview_selector_rename
  • gs_apply_selector_rename
  • gs_list_test_case_classes
  • gs_run_tests_in_package
  • gs_run_test_method
  • gs_global_set
  • gs_global_remove
  • gs_global_exists
  • gs_run_gemstone_tests
  • gs_debug_eval
  • gs_debug_stack
  • gs_debug_continue
  • gs_debug_step_over
  • gs_debug_step_into
  • gs_debug_step_through
  • gs_debug_stop
  • gs_eval

Requirements

  • Python 3.6+
  • Tcl/Tk
  • reahl-parseltongue
  • Access to a GemStone/Smalltalk environment

AI-Assisted Development

This project serves as an exploration of how AI can be incorporated into software development workflows. Our key insights include:

  • The initial framework of the app was developed entirely by prompting the AI.
  • As the codebase grew, we started refactoring to extract duplication and address other important code smells.
  • We introduced an event-handling mechanism to allow for better design regarding event handling.
  • We found that refactoring helps tremendously by allowing us to give the AI smaller relevant chunks of context to work with.

Throughout the process, human developers provided domain expertise, drove architectural decisions, performed code reviews, and handled integration and testing. The project demonstrates how AI can be an effective collaborator in software development when combined with sound software engineering practices.

License

This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.

GemStone/S is proprietary software by GemTalk Systems and is not distributed as part of this project. You must obtain and use GemStone/S under separate GemTalk license terms. No rights to GemStone/S are granted by this project's GPL license.

Development & CI/CD

Continuous Integration

This project uses GitHub Actions for continuous integration and deployment:

  • CI Workflow: Automatically runs on pull requests and pushes to main branch

    • Tests package installation across Python 3.8-3.12
    • Validates code formatting with Black and isort
    • Builds wheel packages for verification
    • Runs import tests
  • Deploy Workflow: Automatically publishes to PyPI on version tags

    • Triggers on tags matching v* pattern (e.g., v1.0.0)
    • Builds wheel and source distributions
    • Publishes to PyPI using secure token authentication
    • Creates GitHub releases with auto-generated notes

Release Process

To create a new release:

  1. Update the version in pyproject.toml
  2. Commit your changes and push to main branch
  3. Create and push a version tag:
    git tag v1.0.0
    git push origin v1.0.0
    
  4. The GitHub Actions workflow will automatically:
    • Build the package
    • Publish to PyPI as reahl-swordfish
    • Create a GitHub release

Repository Setup

To enable automated PyPI publishing, the repository must have a PYPI_API_TOKEN secret configured with a valid PyPI API token for the reahl-swordfish package.

Contributing

We welcome contributions! Please feel free to submit a Pull Request.

About Reahl Software Services

Reahl Software Services (Pty) Ltd is a software development company specializing in innovative software solutions. For more information, visit our website.

How to Develop (Docker)

This section applies to both IDE and MCP workflows.

Start the development container

# Clone the repository
git clone https://github.com/reahl/swordfish.git
cd swordfish

# Start the development environment
./docker-start.sh

Docker script options:

./docker-start.sh                    # Normal development mode
./docker-start.sh --no-cache         # Clean rebuild (clears Docker cache)
./docker-start.sh --foreground       # Foreground shell with entrypoint setup
./docker-start.sh --foreground --no-entry-point  # Root shell without entrypoint setup
./docker-start.sh --enable-ssh       # Start sshd in container (key-only auth)
./docker-start.sh --enable-ssh --ssh-pubkey-file ~/.ssh/id_ed25519.pub

The Docker setup includes:

  • Ubuntu 24.04 base with Python 3.12
  • GemStone/Smalltalk 3.7.4.3 environment
  • Python development tools (black, isort, pytest) in virtual environment
  • X11 forwarding for GUI applications
  • Volume mounts for live code editing
  • Automatic user mapping for file permissions
  • Entry-point setup that adds ~/.local/venv/bin to PATH and loads GemStone environment in interactive shells

SSH access for automated commands

# Start container with sshd enabled and your public key provisioned
./docker-start.sh --enable-ssh --ssh-pubkey-file ~/.ssh/id_ed25519.pub

# Optional overrides
export SF_SSH_PORT=2222
export SF_SSH_BIND_ADDRESS=127.0.0.1
export SF_MCP_PORT=9177
export SF_MCP_BIND_ADDRESS=127.0.0.1

Run commands from the host (recommended):

# Run any command in /workspace with ~/.local/venv activated
./docker-run-over-ssh.sh python -V
./docker-run-over-ssh.sh pytest -q

# Convenience wrapper for pytest
./docker-test-over-ssh.sh
./docker-test-over-ssh.sh tests/test_mcp_session_registry.py -q

Optional direct SSH session for troubleshooting:

ssh -p 2222 "$(whoami)"@127.0.0.1

GemStone server management

Once inside the container, you can start and manage the GemStone server:

# Start the GemStone server (stone name: gs64stone)
sudo -u gemstone bash -l -c "startstone gs64stone"

# Check server status
sudo -u gemstone bash -l -c "gslist"

# Stop the GemStone server
sudo -u gemstone bash -l -c "stopstone gs64stone"

# Alternative: Interactive gemstone user session
sudo -u gemstone -i

Note: GemStone server operations must be run as the gemstone user for proper permissions and security. The -l flag ensures the GemStone environment is loaded.

Run the IDE inside the container

When started normally (without --no-entry-point), the container entrypoint sets up your shell environment for Swordfish:

  • ~/.local/venv/bin is added to PATH
  • GemStone environment is loaded for interactive shells (including GEMSTONE)

If you bypass the entrypoint (for example --no-entry-point), configure the environment manually:

source ~/.local/venv/bin/activate
. /opt/dev/gemstone/gemShell.sh 3.7.4.3
# 1. Start the GemStone server
sudo -u gemstone bash -l -c "startstone gs64stone"

# 2. Verify the stone is running
sudo -u gemstone bash -l -c "gslist"

# 3. Install Swordfish in development mode
pip install -e .

# 4. Run Swordfish
swordfish

# 5. In the Swordfish GUI, connect to GemStone:
#    - Use "Linked Session" connection type
#    - Set stone name to: gs64stone
#    - Leave other connection settings as defaults

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

reahl_swordfish-0.2.0.tar.gz (166.5 kB view details)

Uploaded Source

Built Distribution

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

reahl_swordfish-0.2.0-py3-none-any.whl (117.6 kB view details)

Uploaded Python 3

File details

Details for the file reahl_swordfish-0.2.0.tar.gz.

File metadata

  • Download URL: reahl_swordfish-0.2.0.tar.gz
  • Upload date:
  • Size: 166.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for reahl_swordfish-0.2.0.tar.gz
Algorithm Hash digest
SHA256 c37dd783f8604e16087cbcfc4387aff80a780b5a732a6715f69d31a2f4d27fb0
MD5 e139a5b7d07377bf59443928a7b1f1bf
BLAKE2b-256 940d8c580b12e5c4885dd94544f2b1da870b89b6d23d8e4379fe591fdd752ef1

See more details on using hashes here.

File details

Details for the file reahl_swordfish-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for reahl_swordfish-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 06d509691e032074974cdb220bbe0e696b31bc2a5403855ebe778c19d558ea87
MD5 3a5291701d99cd4b43041cf4c31181cd
BLAKE2b-256 6e7ec469cc499351e974a5d9224ae5a1df7ece67e6746bbef72a0712214f3c55

See more details on using hashes here.

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