Skip to content

Latest commit

 

History

History
264 lines (142 loc) · 13.8 KB

File metadata and controls

264 lines (142 loc) · 13.8 KB

OS Environment

  • This computer is a Windows 11 system with Cygwin installed.

  • Cygwin's /bin directory is in the PATH environment variable.

  • Your Bash tool executes commands in the Cygwin Bash shell located at C:\apps\cygwin\bin\bash.exe, which is /bin/bash inside any Cygwin app.

  • Most Linux commands are available in the Cygwin Bash shell. If you need any that are not installed, ask me to install them.

  • My personal ~/bin directory (and some its sub-directories) are also in the PATH environment variable. I commonly put wrapper scripts that launch Windows apps in ~/bin/win32. This avoids adding a lot of directories to my PATH.

  • The Cygwin man pages are installed. Use man TOPIC >/tmp/TOPIC.txt to save a man page in plain text that you can read.

  • Cygwin symlinks corresponding to each Windows drive letter have been created as follows:

    /a -> /cygdrive/a
    /b -> /cygdrive/b
    /c -> /cygdrive/c
    ...
    /z -> /cygdrive/z
    
    • Native Windows apps and commands cannot follow Cygwin symlinks, even when invoked from a Cygwin Bash shell.

    • The target of a Cygwin symlink can found using Cygwin command readlink -m SYMLINK.

My Two Home Directories

  • My Cygwin home directory is C:\franl. My Windows home directory is C:\Users\flitt.

  • When I write ~, it always means my Cygwin home directory (/cygdrive/c/franl = C:\franl), never my Windows home directory.

  • When I mean my Windows home directory, I will write C:\Users\flitt or say "my Windows home directory" explicitly.

  • In a Cygwin Bash shell and all Cygwin apps, the value of environment variable HOME is /cygdrive/c/franl, my Cygwin home directory.

  • In all Windows apps, even those spawned by a Cygwin app, the value of HOME is C:\franl, even though that is not my Windows home directory. This causes some Windows apps to use my Cygwin home directory, though some still use C:\Users\flitt\. This can be confusing, so please be careful with any activity involving my home directories.

Pathname Handling

  • I will give pathnames to you in both Cygwin-style (/c/franl/bin/..., /c/temp, ~/bin, etc.), and Windows-style (C:\franl\bin, C:\temp, etc.). It is your responsibility to convert them between styles depending on which tool you are giving them to. This section and the next will guide you with this.

  • Use pathnames in Bash commands as follows:

    1. When invoking a Cygwin app from Bash, all pathnames should use forward slashes and, and absolute pathnames should have a /cygdrive/... prefix. Example: ls -l path/to/file /cygdrive/e/somefile.

    2. When invoking a native Windows app from Bash, all pathnames should use backslashes, be single-quoted to escape the backslashes, and absolute pathnames should have a Windows drive letter prefix. Examples: powershell -File 'path\to\script.ps1' and powershell -File 'C:\temp\script.ps1.

  • In all cases, if a pathname contains whitespace or Bash metacharacters, the entire pathname must be single-quoted, regardless of whether it is being given to a Cygwin app or a native Windows app.

  • If single-quotes are not an option for escaping metacharacters, escape each one with a backslash.

  • A oddity of Cygwin: When a native Windows process starts a Cygwin program, the Cygwin runtime re-parses the Windows command line and performs its own glob/brace expansion, which can corrupt the final command line. Additional argument quoting should fix this.

Pathnames and Your File Access Tools

  • Your file access tools do not understand Cygwin-style pathnames.

  • Always give Windows-style pathnames to your file access tools.

Finding Files

  • Do not use find to search the entire filesystem by file name, though it's OK to use it for searching by other criteria.

  • Search for files by name using the es command in Bash. es is a CLI front-end to the Everything search app that does extremely fast filesystem-wide pathname searches.

  • Run es --help to see this usage:

usage: $ME [ -d | -s | -f ] [ -u | -w ] [ STRING | -r REGEX ]

Shows pathnames on local disks matching STRING (or REGEX with switch '-r'). The search is
case-insensitive and matches anywhere in the absolute pathname, so STRING and REGEX can
match `/` characters in the pathname. Results are sorted by absolute pathname by default.

The output contains forward slashes (`/`) by default. Use -w to get backslashes.

IMPORTANT: If STRING or REGEX contain shell metacharacters (e.g., `*`, `?`, `|`, etc.),
they must be properly quoted.

-r  ->  Match filenames using the given REGEX instead of a fixed STRING.
-f  ->  Show only pathnames, without modification times or sizes.
-d  ->  Sort results by modification time (newest first).
-s  ->  Sort results by size (largest first)
-u  ->  Display pathnames with UNIX-style forward slashes (default).
-w  ->  Display pathnames with Windows-style backslashes.

Examples:

# Show all files and directories under D:/somedir, sorted by size.
$ es -s D:/somedir/

# Show all items with names starting 'foo' under any sub-directory of 'franl' on any drive.
$ es -f '/franl/.*/foo'

# Show all items named 'FETCH_HEAD' in a '.git' directory, sorted by modification time.
$ es -d -r '/.git/FETCH_HEAD$'
  • When running es, prefer to use forward slashes in STRING and REGEX, otherwise backslashes must be escaped.

  • es can produce a lot of output, depending on the search string/regex. Pipe its output through head or other tools to limit it.

  • es does not understand Cygwin-style /cygpath/... prefixes. When necessary, use a Windows-style drive letter prefix (C:/..., D:/..., etc.).

Searching File Contents

  • Never recursively grep the entire filesystem.

  • Recursive grep commands are acceptable in directories that don't contain too many files. Use the es tool to quickly count the files below a given directory, as follows: es -f 'C:/path/to/directory/' | wc -l.

  • The ugrep utility is available in PATH. It's' a drop-in replacement for Gnu grep that supports searching UTF-8, UTF-16 and UTF-32 encoded files, PDF documents, and image metadata. Use ugrep --help to see usage.

Installed Compilers and Tools

  • The following compilers and tools are installed and available in the Bash shell: gcc, g++, go, rustc, cargo, python, uv, uvx, npm, npx, git, and gh. Some of these are native Window apps, and some are Cygwin apps.

  • Node.js is installed and can be executed using command node.

  • When you need to perform non-trivial mathematical calculations, use Python to do the math.

  • If you need additional compilers or tools installed, confirm with the user before installing them.

Choosing a Python Interpreter

  • Two Python interpreters are available, and they behave differently in ways that cause subtle bugs, so choose deliberately:

    1. Cygwin's python (/usr/bin/python) is a POSIX build: os.path uses Cygwin-style pathnames, os.getcwd() returns a /cygdrive/... path, and it can follow Cygwin symlinks.

    2. The native Windows Python (/c/Windows/py.exe, which runs C:\Program Files\Python313\python.exe) uses backslash-aware ntpath semantics, os.getcwd() returns a C:\... path, and it cannot follow Cygwin symlinks.

  • Default to Cygwin's python for scripts you run yourself from the Bash shell, because it matches the shell's filesystem view (pipes, redirects, and symlinks).

  • For a script that something else launches, use and test with that same Python interpreter. Testing under the wrong interpreter can pass while production fails.

  • When a script may run under either interpreter, parse pathnames separator-agnostically (for example, split on both / and \) rather than relying on os.path.

  • For standalone script deliverables, keep using PEP 723 metadata with uv/uvx (see the Python Scripting Guidelines below); uv provisions its own interpreter.

Creating and Editing Files

File Encoding

  • When you create new files containing source code or text, always use UTF-8 text encoding.

  • When you modify existing files, use the same text encoding as the rest of the file.

Newline Conventions

  • When you create new files, you should use UNIX-style newlines (a single line-feed character).

  • When you modify existing files, you must use the same newline convention as the rest of the file.

  • Never convert an existing file from one newline convention to the other. If you have a compelling reason to do this, confirm with the user first.

Writing Markdown

  • It's OK to have indefinitely long lines (despite the below rule to limit the length of source code lines), because Markdown renderers handle that gracefully.

  • Avoid hard line breaks with <br/>, because not all renderers handle that.

  • Instead of <br/>, use two trailing spaces at the end of a line to indicate a line break.

  • When creating a new Markdown document, list yourself as the author.

Writing Skills

A skill is a collection of files (packaged in ZIP format) with the extension .skill that can be read by an AI at inference-time to learn new skills. When you write a skill, follow these guidelines:

  • The skill syntax specification is available at https://agentskills.io.

  • Do not add any directories to a skill other than the standard ones (and only if they are non-empty): scripts, references, and assets.

  • Always write a skill's markdown files in UTF-8 encoding without a BOM (byte-order mark).

  • Always use UNIX-style newlines (a single line-feed character) in skill files.

  • Use spaces for all indentation.

  • The name of the ZIP'ed skill file should have the .skill extension.

Writing Source Code

  • Keep lines of source code less than 100 columns wide.

  • Avoid single-character identfiers.

  • In loops, use meaningful identifiers, such as index, counter, and loopCount, instead of single-character identifiers.

  • Prefer Python and Bash as scripting languages. Avoid Windows batch scripts and Powershell scripts, unless absolutely necessary.

Editing Leading Whitespace

  • Many of my scripts and source files mix tabs and spaces in indentation. Mid-line tabs and spaces are also used to align columns in array literals and before trailing comments.

  • The string-replacement edit tool requires its old_string to match content in the file byte-for-byte, including every tab and space.

  • Although tabs and spaces are distinct characters that are present in the read tool's output, you cannot reproduce a mixed-whitespace region with byte-exact reliability by retyping it, so the match fails.

  • When an edit fails on such a file, do not keep retrying with guessed whitespace. Instead, use one of these reliable approaches:

    1. Anchor the old_string on a short, unique single line that has little or no leading whitespace.

    2. Run cat -A (or sed -n 'START,ENDp' FILE | cat -A) on the target region first to see the real tabs (^I) and spaces, then reproduce them exactly.

    3. For tricky multi-line regions, perform the replacement with a scripted literal str.replace (for example, a small Python script that reads the file, asserts the old text matches exactly once, replaces it, and writes it back).

  • Do not convert files from tabs to spaces (or vice versa) to make editing easier.

Python Scripting Guidelines

  • In Python scripts, use PEP 723 metadata to specify dependencies.

  • Using PEP 723 metadata allows uv and uvx to automatically obtain dependencies when the script is run.

Bash Scripting Guidelines

  • In Bash scripts, all variable names must be fully uppercase, as follows: COUNT=0, FILENAME="file.txt", etc.

  • In Bash scripts, local variables in Bash functions must start with a leading underscore to avoid shadowing global variables, as follows: local _COUNTER=0. Conversely, never use a leading underscore in a global variable.

  • Prefer the new test command ([[ ... ]]) instead of the traditional one ([ ... ]).

  • Use the proper argument syntax for the new test command, such as using && instead of -a to indicate Boolean AND operations, and || instead of -o to indicate Boolean OR operations. To see full usage details, run help [[ in Bash.

AutoHotkey Scripting Guidelines

  • After editing an AutoHotkey v2 script, syntax-check it without running it via AutoHotkey64.exe /validate 'C:\path\to\script.ahk' (exit code 0 and no output means success).

  • Validate the top-level script that #Includes the edited file, not the included fragment alone, so that globals and other includes resolve.

Comments in Source Code

  • Always write well-commented source code.

  • Comments should be complete sentences.

  • Put comments on the line above the code they reference, rather than on the same line.

  • Comments can appear on the same line as code only if the comment is very short. In this case, the comment is exempt from the rule that it must be a complete sentence.

  • Comments should explain the purpose and rationale of the code and not simply restate what the code does.

  • Do not talk to the user through comments in code.

  • Do not comment trivial code, such as Python and Go import statements or the initialization of local variables, unless the comment explains something important for a developer to understand.

Accessing GitHub

  • You have read access and write access to my GitHub repositories via command git.

  • git needs no credentials, because SSH access to GitHub is already configured.

  • My GitHub user name is fpl9000, and my GitHub profile is located at https://github.com/fpl9000.

Building Applications

  • When running commands to build executables, make sure the executable name ends with .exe, because this is a Windows system.

  • When building a graphical Go application, always pass switch -ldflags "-H windowsgui" so that the application does not create a console window when it is launched.

  • When using GCC to build a graphical application, always pass switch -Wl,--subsystem,windows so that the application does not create a console window when it is launched.