๐Ÿค– Agent Instructions

August 27, 2025 ยท View on GitHub

This file contains instructions for AI agents on how to interact with and contribute to this repository.

๐Ÿ“œ General Agent Guidance

This section outlines the universal rules and expectations for any AI agent working within this repository.

  • Safety and Quality First: The highest priority is to produce secure, well-documented, and high-quality code. Do not introduce vulnerabilities, hardcoded secrets, or unreadable code.

  • Propose a Plan: For any new task, first provide a brief plan of action. This plan should clearly outline the intended changes and the rationale behind them.

  • Maintain Context: Before making any changes, an agent must read and understand the relevant files, including the project's main documentation and existing code structure.

  • Clear Contributions: All contributions must be submitted via a pull request with a clear, concise commit message and a brief description of the changes.

๐Ÿ“ Project-Specific Guidelines

Tone and Style

  • Art Gallery with Humor: The overall tone of the project, especially in user-facing documentation like READMEs, should be that of a slightly quirky art gallery curator. Think "art gallery with a bit of humor".

Bash Compatibility

  • Bash v3.2 is the target: The main screensaver.sh script must be compatible with Bash v3.2. This is to ensure it runs on a wide variety of systems, including older macOS versions.
  • Individual screensavers: Individual screensavers can use newer bash features, but it's good practice to stick to v3.2 if possible.
  • Cross-platform: All scripts should be written to be cross-platform, working on macOS, Linux, WSL, Cygwin, etc. Avoid using platform-specific commands without fallbacks.

Bash Scripting Style

The following scripting guidelines are heavily based on the Bash Style Guide by Dave Eddy, which should be considered the primary reference for style. Adhere to the following principles to ensure scripts are safe, predictable, and maintainable.

  • Shebang: Start scripts with #!/usr/bin/env bash for portability.
  • Error Checking: Always check for potential errors, especially for commands that can fail, like cd.
    # wrong
    cd /some/path
    rm file
    
    # right
    cd /some/path || exit 1
    rm file
    
  • set -e: Do not use set -e. Handle errors explicitly. It can have unintended consequences.
  • Quoting: This is critical.
    • Use double quotes (") for strings that require variable expansion.
    • Use single quotes (') for all other literal strings.
    • Always quote variable expansions ("$var") to prevent word-splitting and globbing issues.
  • Variables:
    • Use lowercase variable names (e.g., my_var).
    • Use local for all variables inside functions.
  • Functions:
    • Do not use the function keyword.
    • Use my_func() { ... } syntax.
  • Conditionals:
    • Always use [[ ... ]] for conditional testing, not [ ... ] or test.
    • Use ((...)) for arithmetic comparisons (e.g., ((a > b))).
  • Command Substitution:
    • Always use $(...) for command substitution, not backticks.
  • Arrays:
    • Use Bash arrays to manage lists of items instead of space-separated strings.
    • Iterate over arrays using for item in "${my_array[@]}"; do ... done.
  • Avoid External Commands:
    • Use Bash's built-in parameter expansion for string manipulation (e.g., ${var/foo/bar}).
    • Use globbing (*) to iterate over files, not ls.
    • Avoid cat when a command can read a file directly (e.g., grep "pattern" file).
  • eval: Never use eval.

Screen Handling

  • tput is your friend: Use tput for all screen manipulations, such as moving the cursor, changing colors, and clearing the screen. This ensures that the scripts are portable across different terminal types.
  • Colors: Use tput setaf (foreground) and tput setab (background) for colors. The standard 8-color palette is the most portable.
  • Animations: Animations are created by a loop of clearing the screen (or parts of it), drawing the next frame, and then sleeping for a short period. sleep 0.1 is a common choice.

Project Structure

  • screensaver.sh: The main entry point. It displays a menu of screensavers and runs the chosen one.
  • gallery/: Each subdirectory in gallery/ is a screensaver.
    • <name>/<name>.sh: The main script for the screensaver.
    • <name>/config.sh: Metadata for the screensaver (name, tagline, etc.).
  • spotlight/: Contains helper scripts for generating previews and other marketing materials.
  • jury/: Contains the bats test suite.

General Tips

  • Cleanup is crucial: Always use trap to ensure that the terminal is restored to a usable state when the user presses Ctrl+C. This includes showing the cursor again (tput cnorm), resetting colors (tput sgr0), and clearing the screen.
  • Subshells for safety: The main screensaver.sh script runs each screensaver in a subshell. This is to prevent the screensaver from accidentally exiting the main menu.
  • Tools: This project uses asciinema to record terminal sessions as .cast files and agg to convert those .cast files into animated GIFs. The spotlight/smile-for-the-camera.sh script automates this process.

๐Ÿงช Testing

The tests for this project are written using the bats (Bash Automated Testing System) framework.

Running Tests

The tests should be run from the root of the repository using the project-specific command, which executes all test files in the jury/ directory:

bats jury

To run a specific test file, you can execute bats jury/my_test.bats.

Test Structure

Tests are located in the jury/ directory. The main test file is jury/tests.bats, which tests the main screensaver.sh script. There are also individual test files for each screensaver.

A BATS test file is a Bash script with special syntax. Here is a typical structure:

#!/usr/bin/env bats

# setup() { ... } # optional: runs before each test
# teardown() { ... } # optional: runs after each test

@test "description of the test" {
  # The test code goes here
  run my_script "some argument"
  [ "$status" -eq 0 ]
  [ "$output" = "expected output" ]
}

Key BATS Concepts

  • Key Variables:

    • run: Executes a command and captures its output and status code.
    • $status: The exit status of the command run.
    • $output: The combined stdout and stderr of the command run.
    • $lines: An array containing each line of the output.
  • Best Practices:

    • Isolate Tests: Each @test should be independent. Use setup and teardown functions to prepare and clean up the test environment if needed.
    • Be Specific: Test descriptions should clearly state what is being tested.
    • Assert One Thing: Ideally, each test should assert a single condition or outcome.
    • Use Helpers: For complex setup or repeated assertions, create helper functions within your test files. BATS automatically exports functions that are not named setup or teardown.

Project-Specific Considerations

  • Dependencies: The tests require bats, bats-support, and bats-assert. These are not checked in to the repository. Refer to the "Environment Setup Guide" in "Jules's Corner" for instructions on installing them using the assemble-the-jury.sh script. It is better to download the release tarballs and extract them rather than cloning with git.
  • Paths: The test scripts are written with the assumption that they are being run from the root of the repository. All paths in the test files should be relative to the root.
  • timeout and Assertions: Many of the tests use timeout to run the screensavers for a short period. Since the screensavers are designed to run indefinitely, timeout will kill them, resulting in a non-zero exit code. Therefore, the tests should use assert_failure to check for this expected failure, not assert_success.
  • Environment Limitations: The testing environment can be restrictive. Commands like cd, pwd, and git restore may not work as expected. It's important to be aware of these limitations and find workarounds when necessary.

Learnings on Test Execution and Reporting

This section documents the work done to simplify test execution and reporting.

  1. Idempotent Dependency Installation:

    • Issue: The assemble-the-jury.sh script would re-download dependencies on every run, which was slow and could fail due to network timeouts.
    • Resolution: I modified the script to first check if the dependency directories exist before attempting to download and extract them. This makes the script idempotent and much faster on subsequent runs.
  2. Automated Test Runner:

    • Issue: Running the tests required two separate commands: one to install dependencies and another to run the bats suite. The process was manual and didn't save the results.
    • Resolution: I created a new script, jury/render-the-verdict.sh, which automates the entire process. It calls assemble-the-jury.sh and then runs the test suite twice, saving the output to jury/verdict.txt (human-readable) and jury/verdict.tap (machine-readable).
  3. Location-Independent Scripts:

    • Issue: The initial version of render-the-verdict.sh relied on being run from the repository root.
    • Resolution: I refactored the script to be location-independent. It now uses dirname on ${BASH_SOURCE[0]} to determine its own location and constructs absolute paths, allowing it to be run from anywhere on the system.
  4. Fix for Hanging Trap Handler:

    • Issue: The test suite was timing out because the life.sh script had a read command in its trap cleanup function, which would hang in a non-interactive environment. This issue was previously noted in the tour-the-gallery.sh learnings but the fix was not applied here.
    • Resolution: I removed the problematic read command from gallery/life/life.sh, allowing the script to terminate correctly when sent a signal by timeout.
  5. Fix for Incorrect Trap Handlers:

    • Issue: Some scripts, like cutesaver.sh, were only trapping SIGINT (Ctrl+C). This meant that when run under timeout (which sends SIGTERM), their cleanup functions would not execute, potentially leaving the terminal in a bad state.
    • Resolution: I updated the trap commands in these scripts to also catch EXIT, TERM, and QUIT, ensuring that cleanup always runs.
  6. New Screensaver Template Fix:

    • Issue: The template used to create new screensavers (screensaver.sh --new) contained the same incorrect trap handler, which would have propagated the bug to all new screensavers.
    • Resolution: I updated the template in screensaver.sh to use the correct, robust trap command.

๐Ÿ‘จโ€๐Ÿ’ป Jules's Corner

This section contains notes and learnings specific to the agent Jules.

Environment Setup Guide

To prepare the environment for development and testing, follow these steps:

  1. Install Core Dependencies: The project requires bc. You can install it using the appropriate package manager (e.g., apt-get install bc or brew install bc).
  2. Set up the Test Suite: The BATS test suite has dependencies that are not in the repository. Run the following script to download and install them locally into jury/test_libs/:
    ./jury/assemble-the-jury.sh
    
  3. Run the Tests: To verify the setup, run the full test suite using the automated runner script. The results will be saved in jury/verdict.txt and jury/verdict.tap.
    ./jury/render-the-verdict.sh
    
  4. Be Aware of Environment Constraints:
    • agg Installation: The agg tool for GIF generation is difficult to install. Refer to the "Learnings on agg Installation" section for details on what has been tried.
    • asciinema Version: The installed version of asciinema does not support the cut subcommand.
    • Filesystem Persistence: When running a series of commands that depend on each other (like downloading and then extracting a file), chain them together in a single run_in_bash_session call with && to avoid issues with filesystem persistence between tool calls.

Learnings on tour-the-gallery.sh

This document summarizes the issues I encountered and the solutions I implemented while debugging the spotlight/tour-the-gallery.sh script.

Key Issues and Resolutions

  1. Non-Standard Timeout Function:

    • Issue: The script initially used a custom run_with_timeout function which was not accessible within the subshell created by asciinema rec, causing recording failures.
    • Resolution: I replaced the custom function with the standard Linux timeout command for better portability and reliability.
  2. Hidden Dependency (bc):

    • Issue: The speaky.sh screensaver failed because it depends on the bc command-line calculator, which was not installed in the environment.
    • Resolution: I identified and installed the bc package to satisfy the dependency.
  3. Unsupported asciinema Subcommand:

    • Issue: The script used the asciinema cut subcommand, which is not available in the version of asciinema present in the execution environment.
    • Resolution: I refactored the recording logic. Instead of recording a long 10-second clip and cutting a 3-second snippet, the script now directly records a 3-second snippet after a 3-second pause (sleep 3; timeout 3s ...), eliminating the need for the cut command.
  4. Interactive Scripts in Non-Interactive Environment:

    • Issue: Several screensavers (e.g., cutesaver.sh, life.sh) used interactive read commands to pause between frames or wait for user input. This caused the main script to hang indefinitely.
    • Resolution: I replaced the interactive read commands in the affected screensavers with non-interactive sleep commands.

Unresolved Issues & Final State

  • Persistent Timeouts: Despite the fixes above, the tour-the-gallery.sh script continues to time out during the final step of converting the concatenated .cast file into a .gif using the agg command.
  • Hypothesis: The timeout is likely caused by one of two things:
    1. The agg command is extremely slow when processing the large, concatenated overview.cast file.
    2. One of the screensavers is still producing a subtly malformed .cast file that isn't caught by the validation logic, causing agg to hang or fail silently (by creating an empty GIF).

Learnings on agg Installation

The spotlight/smile-for-the-camera.sh script requires the agg tool to generate GIFs. During my work on this project, I encountered significant difficulties installing agg in the provided environment. This section documents the issues for future reference.

  • pip install agg: The pip package for agg does not seem to install an executable, but rather a library. This means that command -v agg will fail even after a successful pip installation.
  • Pre-built Binaries: The official documentation for agg recommends downloading a pre-built binary from the GitHub releases page. However, I was unable to find a direct download link for the correct architecture (x86_64-unknown-linux-gnu) on the releases page. My attempts to guess the URL resulted in 404 errors.
  • x-cmd: I found a third-party tool called x-cmd that simplifies the installation of command-line tools. However, x-cmd itself is not installed in this environment, so I was unable to use it.

Due to these issues, I was unable to get a working version of agg installed. The tasks related to fixing the GIF generation for the pipes and life screensavers have been postponed until this issue can be resolved.

Learnings on the Bats Test Environment

This section documents the issues encountered while attempting to fix the bats test suite in the jury/ directory.

Key Issues and Resolutions

  1. Dependency Management:

    • Issue: The bats test dependencies (bats-core, bats-support, bats-assert) are not checked into the repository.
    • Resolution: I created a setup script at jury/assemble-the-jury.sh to automate the download and extraction of these dependencies into a jury/test_libs/ directory. I also added this directory to the .gitignore file.
  2. Filesystem Persistence in the Environment:

    • Issue: The execution environment appears to have issues with filesystem persistence between separate run_in_bash_session tool calls. Changes made in one call (like downloading a file) were not always present in the next call, leading to "No such file or directory" errors.
    • Workaround: To get a consistent result, I had to chain all commands (dependency download, extraction, and test execution) into a single, long run_in_bash_session command using &&.

Unresolved Issues & Final State

  • Path Loading in Bats: The primary blocker is an issue with how bats loads dependency files. The test scripts use relative paths (e.g., load 'libs/bats-support/load'). My attempts to correct these paths to point to the new jury/test_libs directory were unsuccessful.
  • Hypothesis: The bats executable, when run from the repository root, seems to have an unexpected behavior in this environment when resolving the relative load paths from within the test files. For example, my attempts to change the path to jury/test_libs/bats-support/load resulted in bats looking for /app/jury/jury/test_libs/..., indicating a misinterpretation of the path. All attempts to modify the files programmatically resulted in corrupted paths.
  • Final State: The test environment setup is now automated via jury/assemble-the-jury.sh. However, the tests themselves are still not runnable due to the path loading issue. The .bats files have been restored to their original, incorrect state. A future developer should focus on fixing the load paths within the .bats files, perhaps by experimenting with different relative paths (../test_libs) or other bats loading mechanisms.

๐Ÿ“š External Resources

Here are some helpful resources for Bash scripting and BATS testing: