npx claudepluginhub edaniels/graft --plugin graftThis skill uses the workspace's default tool permissions.
`graft` is a local-first remote development tool. With shell activation in
Establishes SSH connections to remote servers for executing commands, checking logs, restarting services, and managing Docker containers via bash scripts.
Provides essential SSH commands for secure remote connections, key generation and management, port forwarding, tunneling, and file transfers. Useful for server administration and secure access.
Syncs projects via git to enable working from multiple devices. Guides git setup for beginners or assumes knowledge as needed.
Share bugs, ideas, or general feedback.
graft is a local-first remote development tool. With shell activation in
place, you cd into a directory and graft transparently routes commands,
files, and ports to the right remote machine. Because Claude Code's Bash tool
runs in that same shell, graft is already in effect for any command you run -
this skill exists so Claude knows when graft is active, which graft commands
to reach for, and how to read graft's structured output.
Graft is active for the current session if any of these are true:
# any of these signals graft is set up
[ -n "$GRAFT_SESSION" ] || [ -n "$GRAFT_CONNECTION" ]
command -v graft >/dev/null
# or there is a graft.yaml in CWD or any parent directory
If none of these hold, do not use graft commands - this skill does not apply.
Shell activation is a hard prerequisite for command shimming. GRAFT_SESSION
is set by eval "$(graft activate <shell>)", and only inside a shell that
sourced that activation will shimmed commands like make or python3 be
forwarded to the remote automatically. Without activation, graft run,
graft shell, graft sync, graft forward, and the status/doctor family
still work - but bare commands like make build will execute locally even
when a connection is forwarding make. If GRAFT_SESSION is unset, reach
for graft run -- <cmd> explicitly rather than trusting PATH.
localRoot) to a remote
destination (SSH or Docker), optionally with file sync and command/port
forwarding.--to <conn>graft use <conn>localRoot is an ancestor
of the current directorymake, a make shim is
injected into PATH. Running make build in that directory transparently
runs on the remote..gitignore, and
reports conflicts/problems in status output.--forward 8080), afterwards
(graft forward 8080), or in graft.yaml. Explicit forwards persist
even if the remote process restarts.Pick whichever fits the conversation. Neither is "more correct" than the other - they produce identical connections under the hood.
Use this when the user wants a one-shot connection or doesn't want a config file committed to the repo.
graft connect <local_dir> <user@host>[:<remote_dir>] [flags]
Flags:
| flag | purpose |
|---|---|
--name <n> | name the connection (defaults to host) |
--sync | enable bidirectional file sync |
--forward <arg> | forward a command OR a port (repeat the flag, or comma-separate). graft auto-partitions: anything matching a port spec becomes a port forward, everything else is a command shim |
--forward-prefix | prefix shimmed commands with the connection name to avoid collisions |
--background | exclude from CWD-based auto-selection (use with --to or graft use) |
--os <name> | docker only: container OS |
Destination forms:
user@host or ssh://user@host - SSH (default)docker://image[:tag] - Docker containerExample mixing commands and ports in a single --forward:
graft connect . ec2-user@build-box:~/work \
--sync \
--forward make --forward bazel \
--forward 8080 --forward 5432:5432/tcp \
--name build
graft.yamlUse this when the connection is stable and shared across teammates or
shells. graft init generates one from flags. With a graft.yaml in CWD,
graft connect with no positional arguments reads it automatically.
Minimal project config (graft.yaml):
version: v1
forward:
- make
- 8080
destinations:
build:
host: build-box
user: ec2-user
syncTo: ~/work
sync: true
Workspace root config (parent dir, opts entire workspace into syncing):
version: v1
workspace: true
defaults:
syncWorkspace: true
See references/config-schema.md for the full schema. Do not confuse this
with the daemon-internal state schema - users hand-author the project
schema above, not the connections[] structure used by graft's persistent
state file.
| command | when to use it |
|---|---|
graft connect | establish a connection (see paths above) |
graft disconnect <conn> | tear down a connection (destructive - confirm with user first) |
graft run <cmd> | run a command on the current connection. add --to <conn> to override CWD-based selection |
graft shell | open an interactive remote shell |
graft sync | trigger a sync (usually unnecessary - sync runs continuously when enabled) |
graft use <conn> | pin the current shell to a connection. graft use --clear resumes CWD-based selection |
graft status | human-readable status. add --json for parsing, --watch to follow |
graft doctor | diagnose environment and connection issues - run this FIRST when something looks broken |
graft init | scaffold a graft.yaml from flags |
graft connection available-commands | list which commands graft knows how to forward on the remote |
graft connection set-root <conn> <local_dir> [remote_dir] | reassign a connection's local (and optionally remote) root after the fact |
graft run --match <pattern> -- <cmd> | run the same command across all connections whose names match the pattern (multi-target run) |
Note: shell activation installs gr as an alias for graft, so gr run ...
and graft run ... are equivalent. Prefer graft in scripts and docs;
gr is for interactive use.
The forward family deserves its own table:
| command | purpose |
|---|---|
graft forward <arg>... | add forwards to the current connection. mixes commands and ports freely |
graft forward list | show all currently-shimmed commands and active port forwards (auto-detected and explicit) |
graft forward remove <arg>... | remove forwards. removing an auto-detected port emits a warning - it will start forwarding again as soon as the remote process listens |
graft forward which <command> | show which connection a shimmed command resolves to (port forwards are connection-wide and rejected here) |
Port spec grammar: [local_port:]remote_port[/protocol]
8080 -> remote 8080 to local 8080 (tcp)3000:8080 -> remote 8080 to local 30005432/tcp -> explicit protocol5353/udp -> UDP forward3000:8080/udp -> full formgraft run --to <conn> <cmd> over ssh <host> <cmd>.graft sync (or just letting sync run) over scp / rsync for
graft-managed directories.graft forward 8080 over ssh -L 8080:localhost:8080 <host>. Often
you don't need to declare anything: graft auto-detects and forwards remote
listeners.graft status --json. Before
assuming a port is reachable, read graft forward list or the
port_forward_statuses[] field of graft status --json and check
conflict / conflict_reason for "address already in use" failures on the
local side.graft doctor BEFORE guessing. It is
faster and more accurate than poking at logs.graft use <conn> to pin a session instead of passing --to to every
command in a sequence.graft connect with no positional args reads graft.yaml from CWD; with
positional args + flags it ignores any yaml.Walk this in order. Stop at the first step that surfaces the problem.
graft status --json - is the connection in CONNECTION_STATE_CONNECTED?
what does state_reason say? are sync conflicts or port conflicts
reported?graft doctor - runs the full check suite (shell activation, local
daemon, SSH reachability, transport mode, remote daemon, remote dirs).
Read references/doctor-playbook.md for failure modes.graft daemon logs - recent local daemon logs.graft ping - is the local daemon even reachable?graft daemon restart - last resort. Confirm with the user first if
other connections might be in use.Always confirm before:
graft disconnect <conn> or removing a connection from daemon stategraft.yaml that is tracked in gitgraft daemon stop / restart while other connections are activeLoaded on demand:
references/commands.md - full per-command flag referencereferences/config-schema.md - complete graft.yaml schema (project +
workspace), with the daemon-state-vs-user-config distinctionreferences/status-json-shape.md - field-by-field meaning of
graft status --jsonreferences/doctor-playbook.md - one section per graft doctor check,
with failure modes and fixesexamples/connect-flag-cheatsheet.md - worked graft connect
invocations covering the common combinationsexamples/forward-cheatsheet.md - port spec grammar and forward
workflowsexamples/project.graft.yaml, examples/workspace.graft.yaml - copy-
paste starting points