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.

Locking MCP permission toggles for protected databases

Swordfish stores GUI and MCP config in ~/.config/swordfish/swordfish.json unless XDG_CONFIG_HOME is set.

If the running user cannot write that config file, Swordfish treats MCP permission toggles specially:

  • Host, port, and HTTP path remain editable in the GUI.
  • MCP permission toggles may be locked or session-only, depending on a configured Smalltalk check.
  • If the Smalltalk check says the connected database is protected, all MCP permission toggles are disabled in the GUI.
  • If the Smalltalk check says the connected database is not protected, the user may change MCP permission toggles for the current session only.
  • Session-only permission changes are not persisted and are reset on logout.
  • The Smalltalk check source is config-only; it is not editable via the GUI.

To configure this, add an mcp_permission_policy section to swordfish.json:

{
  "schema_version": 2,
  "mcp_permission_policy": {
    "allow_session_permission_changes_condition_source": "System stoneName ~= 'prod'"
  },
  "mcp_runtime_config": {
    "allow_source_read": true,
    "allow_source_write": false,
    "allow_eval_arbitrary": false,
    "allow_test_execution": false,
    "allow_ide_read": true,
    "allow_ide_write": false,
    "allow_commit": false,
    "allow_tracing": false,
    "require_gemstone_ast": false,
    "mcp_host": "127.0.0.1",
    "mcp_port": 8000,
    "mcp_http_path": "/mcp"
  }
}

The configured Smalltalk source must answer true or false in the current GemStone session:

  • true: session-only MCP permission changes are allowed when the config file is read-only.
  • false: MCP permission toggles are locked when the config file is read-only.

If the policy is missing, answers something other than a boolean, or raises an error, Swordfish fails closed and locks the permission toggles.

Run GemStone code on login

Swordfish can also evaluate a configured GemStone script immediately after a successful login.

  • The script source is config-only; it is not editable via the GUI.
  • The script is evaluated in the logged-in GemStone session before the IDE transitions to the main browser UI.
  • If the script raises an error, login is aborted and the opened session is logged out again.

To configure this, add a login section to swordfish.json:

{
  "schema_version": 2,
  "login": {
    "gemstone_script_source": "System stoneName"
  },
  "mcp_runtime_config": {
    "allow_source_read": true,
    "allow_source_write": false,
    "allow_eval_arbitrary": false,
    "allow_test_execution": false,
    "allow_ide_read": true,
    "allow_ide_write": false,
    "allow_commit": false,
    "allow_tracing": false,
    "require_gemstone_ast": false,
    "mcp_host": "127.0.0.1",
    "mcp_port": 8000,
    "mcp_http_path": "/mcp"
  }
}

The configured source is passed to the same GemStone code-evaluation path used by the IDE Run tool, so it may contain any Smalltalk you would normally execute in the connected session.

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 src/reahl/swordfish/__init__.py
  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
./docker-start.sh --gemstone-version 3.6.5

The Docker setup includes:

  • Ubuntu 24.04 base with Python 3.12
  • GemStone/Smalltalk environment (default 3.7.4.3, configurable)
  • 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 "${GEMSTONE_VERSION:-3.7.4.3}"

To run and test specifically against GemStone 3.6.5:

GEMSTONE_VERSION=3.6.5 ./docker-start.sh --no-cache --enable-ssh --ssh-pubkey-file ~/.ssh/id_ed25519.pub
./docker-test-over-ssh.sh
# 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.10.0.tar.gz (243.3 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.10.0-py3-none-any.whl (171.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: reahl_swordfish-0.10.0.tar.gz
  • Upload date:
  • Size: 243.3 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.10.0.tar.gz
Algorithm Hash digest
SHA256 b3f6710d9dcd7f65237b6af995d4514571caf9124093a82f2d29bf24cb1a216d
MD5 3cbfc6ca2f42324ede44c5fd11a3089c
BLAKE2b-256 a63872f38954253a4cdf4d8b9ccdaba78d720fb8179614e946a9750af9d2af2e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for reahl_swordfish-0.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f49a5099828c345480b4f92f47dfafdc7985f20f90c9c20e83ddb659124556b9
MD5 345cbda09cc52846502098bee3b69a38
BLAKE2b-256 590e250da5e25ba9909fbe2daf8c62d8fd9dea826034dc607e37a94d0f26a203

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