Ferry

Moving a project

ferry move carries a git project between machines, with its untracked files, its Claude and Codex sessions, and its Claude project memory.

ferry move ~/code/shop --dry-run          # see the plan
ferry move ~/code/shop                    # to default_box or the only box
ferry move ~/code/shop --to-box b         # to box b
ferry move ~/code/shop --from-box a       # back to this machine
ferry move ~/code/shop --from-box a --to-box b

The path must be inside the home directory. The destination uses the same path relative to its home. ferry move does not accept --box.

Before a move

Run ferry move <path> --dry-run first. It prints Carry:, Refuse:, Skip:, Note:, and Problem: lines and changes nothing.

Fix each Problem: line. Ferry refuses a move with one of these:

The destination clones the project from origin with its own SSH key. Run ferry auth gh for a box first.

What a move carries

A Refuse: file stays on the source machine. Do not copy it by hand without a check of its content.

Between two boxes, the files go through a temporary directory on the operator machine, and nothing stays there. The boxes do not connect to each other.

.env files

Large files

Ferry reads one file at a time to check it, and it does not read a file of more than 128 MiB, so that a box with little memory can do the check. Such a file, session, or skill file stays on its machine. The plan lists it as Skip: <path> (too large for Ferry to check), and you copy it by hand. --remove refuses the move when the project has such a file.

Remove the source copy

With --remove, after verification, Ferry moves the source copy to ~/.Trash on macOS, else to ~/.ferry/trash. It does not delete it. Ferry refuses --remove if it refuses any local-only file.

Sessions

The dry run prints a Carry sessions: line.

For a session transcript, Ferry reads each record. It looks for tokens, and for a password or secret key with a value in tool inputs and tool results: in JSON, in config text such as KEY=value lines, and in command flags such as --password <value>.

The limit of the session scan

The scan finds a secret only by a token pattern or next to a secret key or flag.

Use --no-sessions when a session can hold such a secret.

Where the check runs

The deny rules run on the source machine. It reads each file one time and sends only the bytes that pass. With --from-box, the Ferry on the box does this, and Ferry compares the SHA-256 of each file that arrives. --dry-run copies no file.

So the box needs a release of Ferry from ferry install or ferry update:

See the Security model.

The origin URL

When the origin URL on the source has a password, a token, or a secret query parameter, the plan has the line Note: The origin URL has a credential. Ferry carries the URL without it. The destination clones from the URL without the credential and needs its own login, for example gh auth login or a deploy key.

Locks

After the plan and the confirmation, a move holds the sync lock of each box that it uses. A sync, ferry update, or ferry box remove --uninstall does not run on that box during the move. When a box is busy, the move fails with sync-busy and changes nothing. Run it again later. --dry-run takes no lock.

Messages during a move

Message Meaning
<file> changed on <machine> after the check A file changed after the plan and no longer passes the deny rules. The source did not send it. Run the move again to see the new plan.
Refuse: <file> (Ferry cannot read the file) The source user cannot read the file. It stays on the source.
Refuse: <directory> (a file or directory in <directory> has a token in its name) A name there has the form of a token. Ferry does not print the name.
Ferry refused files from <box> after the copy The box sent a file that the operator machine refuses. Ferry wrote nothing of it to the destination. Run ferry update, and check the box when the message comes again.
WARNING: Ferry could not register <path> in Paseo Only the Paseo step failed. The move is complete. Do not run it again for this.

Paseo

With the Paseo integration on, ferry move registers the project in the Paseo of the destination and imports each carried session as a Paseo agent. See Integrations.