airscp
CLAUDE.md1 starsChanged 20 days agoApache-2.0View on GitHub
AirSCP is a native macOS app (Swift, AppKit + SwiftUI, macOS 13.1+) for SSH servers and Windows desktops: saved hosts, a two-pane SCP/SFTP browser with a background transfer queue, Synchronize, Find Files, a Linux monitor, tunnels, jump hosts and HTTP proxies, and a built-in Remote Desktop client (FreeRDP). For SSH it is a GUI over macOS's own OpenSSH tools. AI agents drive it over MCP (agent control). The app was called Porter before v1: internal names (the Docker lab porter-lab,…
- Reads credentials
- Commits and pushes
We split this CLAUDE.md into the rules it gives an agent
6 rules. About 0 are common, 3 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 21
The app explains itself: every interactive control and menu item has a one-line tooltip (.help / toolTip, verb first, no full stop).
- Distinctive: line 35
The repository is public: no passwords, keys, real server names, personal paths or e-mail addresses in code, tests, docs, screenshots or …
- Very specific: line 40
Never read or write ~/.ssh.
- Distinctive: line 43
Test against the local throwaway sshd (the tests make their own), the shared Docker lab (never recreate or stop it.
- Very specific: line 46
Never run the x86_64 slice.
- Distinctive: line 48
Never wait blind: when driving the app: if nothing changes for ~20–30 s, take a snapshot and a screenshot you look at, and answer the sheet …
≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AirSCP: notes for Claude (and other coding agents)
AirSCP is a native macOS app (Swift, AppKit + SwiftUI, macOS 13.1+) for SSH servers and Windows desktops: saved
hosts, a two-pane SCP/SFTP browser with a background transfer queue, Synchronize, Find Files, a Linux monitor,
tunnels, jump hosts and HTTP proxies, and a built-in Remote Desktop client (FreeRDP). For SSH it is a GUI over macOS's
own OpenSSH tools. AI agents drive it over MCP (agent control). The app was called Porter before v1: internal names
(the Docker lab porter-lab, the VM "Porter Test Windows", PORTER_* env aliases) keep that name; nothing users see
may say Porter.
Knowledge beyond this file: docs/dev/ (architecture, feature map, regression history, agent control, UX copy,
release, self-hosted runner) and CONTRIBUTING.md. User docs: docs/ (published at https://kleash.github.io/airscp/).
Rules for every change
- Simplicity first: the smallest change that solves the problem; no speculative abstractions, no new layers or settings unless the problem needs them. Read the surrounding code and follow its patterns; comments say why, not what.
- Toolchain: Command Line Tools only (no Xcode project), Swift 5 language mode, code that compiles with Swift 5.9,
deployment target macOS 13.1. No third-party Swift packages. Nothing from Homebrew in the build or the app.
FreeRDP + OpenSSL come from
scripts/build-freerdp.sh(pinned, checksummed, static, universal). - The app explains itself: every interactive control and menu item has a one-line tooltip (
.help/toolTip, verb first, no full stop); disabled items say why; non-obvious fields get a grey caption and "Optional" where optional; plain words before jargon ("Jump host — connect through another server first (ProxyJump)"); rare options under Advanced; empty states say what to do next.HelpTests.everyControlSaysWhatItDoesandeveryMenuItemSaysWhatItDoesfail on a control without help. Wording conventions: docs/dev/ux-copy.md. - Docs follow the code: the user page in
docs/(very simple English, task-first;DocsTestschecks links, pictures and that every menu command is named),Resources/AgentGuide.mdfor anything agents reach (the MCP server serves it;AgentBridgeTestscheck it names only real tools, menu paths and ids), thenscripts/llms.sh(CI fails whiledocs/llms*.txtare stale). Pictures come fromscripts/docs-screenshots.sh(neutral demo data). - Versions:
VERSIONis the source of truth;plugins/airscp/.claude-plugin/plugin.json,mcpb/manifest.jsonandserver.jsonmust match it (CI checks). After changingVERSIONor a pin inscripts/build-freerdp.sh, runscripts/sbom.sh(SBOMTestscheckssbom.spdx.json; security.yml scans it for known vulnerabilities). - Commits: short imperative messages that say what the code now does, no attribution trailers. Never commit
build outputs,
vendor/,testenv/.keys,testenv/.windows,testenv/.uidriver. - The repository is public: no passwords, keys, real server names, personal paths or e-mail addresses in code, tests, docs, screenshots or commit messages (the Docker lab's documented throwaway credentials excepted).
Safety (you are working on someone's own Mac and accounts)
- Never read or write
~/.ssh. A throwaway AirSCP followstestenv/AGENT.md: its ownAIRSCP_SUPPORT_DIRand anAIRSCP_SSH_DIRwhoseconfigsetsUserKnownHostsFile,IdentityAgent noneandIdentityFile none. A throwaway AirSCP never touches the login Keychain; don't write it any other way either. - Test against the local throwaway sshd (the tests make their own), the shared Docker lab (never recreate or stop it;
destructive tests in your own
porter-*containers) and the Windows VM (never toggle its network adapter — that crashes Windows — and never stop or destroy it; one RDP session at a time). - Never run the x86_64 slice. Don't install into
~/Applications(./install.shis for the person at the Mac). Kill what you start. - Never wait blind when driving the app: if nothing changes for ~20–30 s, take a snapshot and a screenshot you look at, and answer the sheet that is open (Trust, password, conflict…). A wait that times out reports what was on screen.
Architecture (where things are)
| Path | What |
Package.swift | Targets: CPTY (C: run on a pseudo-terminal), CRDP (C shim over FreeRDP + airscp_crypto.c), AirSCPCore (no UI), AirSCP (the app), AirSCPTests |
Sources/AirSCPCore/Commands.swift | Every ssh/scp/sftp command line, built in one place (OpenSSH.*) |
…/Session.swift | One master ssh per host (ControlMaster), capability probe, reconnect, tunnels |
…/Runner.swift | Process and pty runner, socketpair pipes, the pump for tar streams, cancellation |
…/RemoteFS.swift, RemoteOps.swift | Listing (ls -lan parser, sftp fallback), remote file operations, Find |
…/Transfer.swift | The transfer queue: scp, tar streams, .airscp-<id>.part files, resume, pause, SHA-256 checks, relays |
…/Askpass.swift, ProxyConnect.swift | The app binary as SSH_ASKPASS and as ProxyCommand (private socket + token) |
…/Certificates.swift (+ CRDP/airscp_pki.c) | The Certificate Manager's model: PEM/DER/PKCS#7/PKCS#12/JKS reading, details, exports (OpenSSL in process) |
…/Keychain.swift, Keys.swift, PuTTYKey.swift, WinSCP.swift | Saved passwords (one Keychain item), key pairs, PuTTY .ppk, Import from WinSCP (WinSCP.ini) |
…/Monitor.swift, RDP.swift, Models.swift, ErrorMapping.swift | Linux monitor parser, the RDP session, airscp.json models (append-only fields), plain-language errors |
…/AgentBridge.swift | AirSCP --mcp (MCP over stdio) and --agent (one tool from a shell); the tool list and the guide |
Sources/AirSCP/main.swift | Helper modes first (--proxy-connect, --mcp, --agent, askpass when AIRSCP_ASKPASS_SOCK is set), then the app |
…/AppDelegate.swift, MainWindow.swift, HostsSidebar.swift, HostWorkspace.swift | Menu bar, the one main window, sidebar, per-host workspace |
…/BrowserContent.swift, FilePane.swift, FileActions.swift, FileSheets.swift, Synchronize.swift, DiskUsageSheet.swift | The Files tab (Disk Usage's scan and tree: Core's DiskUsage.swift) |
…/TransfersPanel.swift, MonitorTab.swift, Tunnels.swift, TerminalTab.swift, RDPWorkspace.swift, RDPDesktopView.swift | Panels and tabs (TerminalTab: the shell inside AirSCP over Core's TerminalScreen + TerminalSession) |
…/AgentServer.swift, AgentSnapshot.swift | Agent control inside the app: socket, tools, in-process accessibility tree, screenshots |
…/Help.swift | Tooltips of menu commands, Help menu, the docs URL table (HelpPage) |
…/Themes.swift | The Night Harbor (dark) and Paper (light) looks from system colours: ground, content, bar, pill; chips, dots, pills, bars, cards (card()), and primaryTint() for a sheet's default button |
Resources/ | Info.plist, entitlements (release signing), icon, licences, AgentGuide.md |
Tests/AirSCPTests/ | Swift Testing; Support.swift = throwaway sshd harness; Lab* need AIRSCP_DOCKER=1, RDP VM tests AIRSCP_WINDOWS=1 |
testenv/ | Docker lab, Windows VM, uidriver (real-screen ui tool), AGENT.md |
scripts/ | FreeRDP build, docs site + screenshots, agent-session.sh (CI), release-local.sh, llms.sh, sbom.sh |
plugins/airscp/, .claude-plugin/, mcpb/, server.json, glama.json | Claude Code plugin, MCP bundle, MCP Registry entry |
Build and test (on a Mac)
./build.sh --native # build/AirSCP.app for this Mac; ./build.sh = universal; first run builds FreeRDP (minutes);
# with Xcode installed it also makes the App Intents metadata (Shortcuts), else it says so
swift build # debug build: must have 0 warnings
./test.sh # Swift Testing suite (needs Swift 6), throwaway sshd servers; extra args go to swift test
AIRSCP_DOCKER=1 ./test.sh # + Docker lab suites (starts the lab: testenv/up.sh)
AIRSCP_WINDOWS=1 ./test.sh --filter RDPWindowsTests # + Windows VM (one suite: its tests run one at a time)
scripts/agent-session.sh # the scripted agent-control session CI runs (needs build/AirSCP.app)
scripts/docs-site.sh # build the docs site as GitHub Pages does and check every link (Docker)
scripts/release-local.sh # signed + notarized release zip (docs/dev/release.md); --adhoc to try the hardened runtimeGates for a change that touches the app: swift build 0 warnings; ./test.sh green twice; the lab and VM suites
when the change can affect them; ./build.sh + codesign --verify --deep --strict build/AirSCP.app; a smoke launch
of a throwaway AirSCP in light and dark; AgentLabTests (agent control end to end, against build/AirSCP.app when it
is newer than the sources; run it as testenv/AGENT.md says, with the shared lab left as it is). Tests wait on conditions,
not timings, so the suite passes on a busy runner (docs/dev/regression-history.md); don't add fixed sleeps or tight bounds.
Without a Mac (a cloud session on Linux)
Such a session can't build or run the app. It edits, pushes, and lets GitHub's Macs do the rest:
- Branch, edit, commit,
git push -u origin <branch>. - CI (
.github/workflows/ci.yml, macos-26, Command Line Tools) runs: versions +docs/llms*.txtup to date, FreeRDP (cached byscripts/build-freerdp.sh's hash),swift build(fails on any warning),./test.sh,./build.sh --native,scripts/agent-session.sh, and uploads the session's screenshots + snapshot JSON as theagent-sessionartifact. A second job,xcode, builds the same commit with Xcode: the App Intents metadata (checked byscripts/check-intents.sh) and the signature; artifactAirSCP-xcode. gh run watch(orgh run list --branch <branch>), thengh run view <id> --log-failed; download the pictures:gh run download <id> -n agent-session -D /tmp/agent-sessionand look at them (failed.png/failed.jsonsay what AirSCP showed when a step failed).- Fix and push again; when green,
gh pr create. The skill.claude/skills/airscp-dev/SKILL.mdhas the details.
The Docker lab suite (GitHub's Macs have no Docker), the Windows VM's Remote Desktop suite and real-screen checks
(menus, Quick Look, Open panels, appearance with the ui tool) run only on the maintainer's Mac, through a
self-hosted runner (.github/workflows/lab.yml, docs/dev/self-hosted-runner.md): a maintainer starts them, after
reading the change, when it needs them.
In this repository4 other files it gives its agents.
- AGENTS.mdAGENTS.md
- docs/llms-full.txtllms.txt
- docs/llms.txtllms.txt
- airscp-devSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

