fwdit 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fwdit-0.1.2/.gitignore +14 -0
- fwdit-0.1.2/PKG-INFO +155 -0
- fwdit-0.1.2/README.md +144 -0
- fwdit-0.1.2/SKILL.md +76 -0
- fwdit-0.1.2/agents/openai.yaml +6 -0
- fwdit-0.1.2/dev-docs/README.md +39 -0
- fwdit-0.1.2/docs/README.md +20 -0
- fwdit-0.1.2/pyproject.toml +47 -0
- fwdit-0.1.2/references/agent-transfer.md +83 -0
- fwdit-0.1.2/references/commands-and-lifecycle.md +232 -0
- fwdit-0.1.2/references/targets-and-config.md +149 -0
- fwdit-0.1.2/src/fwd/__init__.py +22 -0
- fwdit-0.1.2/src/fwd/agents/README.md +71 -0
- fwdit-0.1.2/src/fwd/agents/__init__.py +27 -0
- fwdit-0.1.2/src/fwd/agents/base.py +127 -0
- fwdit-0.1.2/src/fwd/agents/claude.py +178 -0
- fwdit-0.1.2/src/fwd/agents/claude_state.py +625 -0
- fwdit-0.1.2/src/fwd/agents/codex.py +102 -0
- fwdit-0.1.2/src/fwd/agents/codex_state.py +73 -0
- fwdit-0.1.2/src/fwd/agents/remote_state.py +74 -0
- fwdit-0.1.2/src/fwd/backends/README.md +71 -0
- fwdit-0.1.2/src/fwd/backends/__init__.py +93 -0
- fwdit-0.1.2/src/fwd/backends/base.py +328 -0
- fwdit-0.1.2/src/fwd/backends/lambda_cloud.py +812 -0
- fwdit-0.1.2/src/fwd/backends/runpod.py +926 -0
- fwdit-0.1.2/src/fwd/backends/slurm.py +599 -0
- fwdit-0.1.2/src/fwd/backends/slurm_job.py +192 -0
- fwdit-0.1.2/src/fwd/backends/ssh.py +269 -0
- fwdit-0.1.2/src/fwd/cli.py +1041 -0
- fwdit-0.1.2/src/fwd/cli_completion.py +225 -0
- fwdit-0.1.2/src/fwd/cli_help.py +104 -0
- fwdit-0.1.2/src/fwd/command_docs.py +92 -0
- fwdit-0.1.2/src/fwd/completion_setup.py +73 -0
- fwdit-0.1.2/src/fwd/config.py +674 -0
- fwdit-0.1.2/src/fwd/credentials.py +188 -0
- fwdit-0.1.2/src/fwd/doctor.py +205 -0
- fwdit-0.1.2/src/fwd/github_auth.py +338 -0
- fwdit-0.1.2/src/fwd/launch_stream.py +173 -0
- fwdit-0.1.2/src/fwd/ops/__init__.py +11 -0
- fwdit-0.1.2/src/fwd/ops/attach.py +326 -0
- fwdit-0.1.2/src/fwd/ops/configcmd.py +643 -0
- fwdit-0.1.2/src/fwd/ops/diff.py +217 -0
- fwdit-0.1.2/src/fwd/ops/launch.py +810 -0
- fwdit-0.1.2/src/fwd/ops/lifecycle.py +543 -0
- fwdit-0.1.2/src/fwd/ops/machines.py +73 -0
- fwdit-0.1.2/src/fwd/ops/ports.py +262 -0
- fwdit-0.1.2/src/fwd/ops/send.py +536 -0
- fwdit-0.1.2/src/fwd/ops/session_select.py +286 -0
- fwdit-0.1.2/src/fwd/ops/target_alias.py +177 -0
- fwdit-0.1.2/src/fwd/ops/transfer.py +116 -0
- fwdit-0.1.2/src/fwd/ops/uninstall.py +277 -0
- fwdit-0.1.2/src/fwd/output.py +160 -0
- fwdit-0.1.2/src/fwd/port_forwarding.py +164 -0
- fwdit-0.1.2/src/fwd/remote.py +216 -0
- fwdit-0.1.2/src/fwd/remote_env.py +19 -0
- fwdit-0.1.2/src/fwd/remote_tasks.py +136 -0
- fwdit-0.1.2/src/fwd/rsync_transport.py +124 -0
- fwdit-0.1.2/src/fwd/scripts/bootstrap.sh +120 -0
- fwdit-0.1.2/src/fwd/scripts/codex_tui_send.py +229 -0
- fwdit-0.1.2/src/fwd/selection.py +226 -0
- fwdit-0.1.2/src/fwd/send_tasks.py +179 -0
- fwdit-0.1.2/src/fwd/session_columns.py +50 -0
- fwdit-0.1.2/src/fwd/skill_setup.py +169 -0
- fwdit-0.1.2/src/fwd/ssh_keys.py +232 -0
- fwdit-0.1.2/src/fwd/sshexec.py +480 -0
- fwdit-0.1.2/src/fwd/state.py +281 -0
- fwdit-0.1.2/src/fwd/stop_after.py +220 -0
- fwdit-0.1.2/src/fwd/sync.py +765 -0
- fwdit-0.1.2/src/fwd/task_stream.py +214 -0
- fwdit-0.1.2/src/fwd/tmux_config.py +87 -0
- fwdit-0.1.2/src/fwd/toolchains/README.md +120 -0
- fwdit-0.1.2/src/fwd/toolchains/__init__.py +31 -0
- fwdit-0.1.2/src/fwd/toolchains/javascript.py +38 -0
- fwdit-0.1.2/src/fwd/toolchains/python.py +28 -0
- fwdit-0.1.2/src/fwd/toolchains/swift.py +27 -0
- fwdit-0.1.2/src/fwd/tooling/__init__.py +6 -0
- fwdit-0.1.2/src/fwd/tooling/base.py +99 -0
- fwdit-0.1.2/src/fwd/tooling/requirements.py +286 -0
- fwdit-0.1.2/src/fwd/tooling/resolver.py +86 -0
- fwdit-0.1.2/src/fwd/ui.py +376 -0
- fwdit-0.1.2/src/fwd/wizard.py +582 -0
- fwdit-0.1.2/src/fwd/worktree_safety.py +92 -0
- fwdit-0.1.2/tests/__init__.py +0 -0
- fwdit-0.1.2/tests/fixtures/runpod/gpu-list.json +183 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-create-help.txt +51 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-create.json +32 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-get-missing.json +14 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-get-running.json +36 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-get-stopped.json +28 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-list-empty.json +1 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-list.json +20 -0
- fwdit-0.1.2/tests/fixtures/runpod/pod-start.json +22 -0
- fwdit-0.1.2/tests/fixtures/runpod/restart-persistence.txt +18 -0
- fwdit-0.1.2/tests/fixtures/runpod/root-help.txt +60 -0
- fwdit-0.1.2/tests/fixtures/runpod/rsync-test.txt +48 -0
- fwdit-0.1.2/tests/fixtures/runpod/ssh-info-proxy.json +11 -0
- fwdit-0.1.2/tests/fixtures/runpod/ssh-info-verbose.json +14 -0
- fwdit-0.1.2/tests/fixtures/runpod/ssh-info.json +14 -0
- fwdit-0.1.2/tests/fixtures/runpod/ssh-test.txt +16 -0
- fwdit-0.1.2/tests/fixtures/runpod/stop-test.txt +46 -0
- fwdit-0.1.2/tests/fixtures/runpod/subcommand-help.txt +88 -0
- fwdit-0.1.2/tests/fixtures/runpod/version.txt +1 -0
- fwdit-0.1.2/tests/fixtures/runpod/volume-persistence.txt +31 -0
- fwdit-0.1.2/tests/harness/docker-sshd/Dockerfile +45 -0
- fwdit-0.1.2/tests/harness/docker-sshd/checks.py +165 -0
- fwdit-0.1.2/tests/harness/docker-sshd/run_integration.sh +135 -0
- fwdit-0.1.2/tests/harness/docker-sshd/scenarios.py +253 -0
- fwdit-0.1.2/tests/test_agents.py +128 -0
- fwdit-0.1.2/tests/test_claude_state.py +475 -0
- fwdit-0.1.2/tests/test_completion.py +145 -0
- fwdit-0.1.2/tests/test_completion_setup.py +85 -0
- fwdit-0.1.2/tests/test_config_cmd.py +352 -0
- fwdit-0.1.2/tests/test_diff.py +111 -0
- fwdit-0.1.2/tests/test_ops.py +1029 -0
- fwdit-0.1.2/tests/test_output.py +89 -0
- fwdit-0.1.2/tests/test_remote.py +437 -0
- fwdit-0.1.2/tests/test_runpod_parse.py +494 -0
- fwdit-0.1.2/tests/test_send_tasks.py +318 -0
- fwdit-0.1.2/tests/test_session_select.py +294 -0
- fwdit-0.1.2/tests/test_skill_package.py +44 -0
- fwdit-0.1.2/tests/test_skill_setup.py +192 -0
- fwdit-0.1.2/tests/test_slurm.py +498 -0
- fwdit-0.1.2/tests/test_smoke.py +363 -0
- fwdit-0.1.2/tests/test_ssh_keys.py +78 -0
- fwdit-0.1.2/tests/test_stop_after.py +114 -0
- fwdit-0.1.2/tests/test_sync.py +542 -0
- fwdit-0.1.2/tests/test_target_alias.py +187 -0
- fwdit-0.1.2/tests/test_tooling.py +269 -0
- fwdit-0.1.2/tests/test_wizard.py +161 -0
fwdit-0.1.2/.gitignore
ADDED
fwdit-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fwdit
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Move coding work and agent sessions to remote compute
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: prompt-toolkit>=3.0
|
|
7
|
+
Requires-Dist: rich>=13
|
|
8
|
+
Requires-Dist: tomlkit>=0.13
|
|
9
|
+
Requires-Dist: typer>=0.12
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# fwd
|
|
13
|
+
|
|
14
|
+
**Move your coding project and agent session to remote compute.**
|
|
15
|
+
|
|
16
|
+
`fwd` provisions or connects to a remote target, synchronizes the current project, prepares its toolchain, and starts a persistent shell, command, Claude Code, or Codex session in tmux. Disconnect your laptop and return later: the session, durable tasks, and logs remain available.
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
laptop remote SSH / RunPod / Lambda / Slurm
|
|
20
|
+
project ───────────── sync ──────────▶ project checkout
|
|
21
|
+
agent context ──────── optional ──────▶ Claude or Codex state
|
|
22
|
+
tmux session + durable task manager
|
|
23
|
+
terminal ◀────────── attach / stream ── persistent work
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
uv tool install fwdit
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or try it without installing:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
uvx --from fwdit fwd --help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Requires Python 3.12+, `ssh`, and `rsync` locally. Run `fwd doctor` to check target-specific requirements.
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
Run fwd from the project you want to move:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
fwd # attach to this project's session, or create one interactively
|
|
46
|
+
fwd up runpod codex # launch Codex on RunPod; auto-attach in a human terminal
|
|
47
|
+
fwd up --detach runpod codex # launch Codex but stay in the local terminal
|
|
48
|
+
fwd up --target work # use a configured SSH/cloud/HPC target
|
|
49
|
+
fwd up -- python train.py # launch and stream a durable command
|
|
50
|
+
fwd ls # inspect sessions and live status
|
|
51
|
+
fwd attach SESSION # reconnect from a human terminal
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Bare `fwd` is the interactive reuse workflow. Agent launches auto-attach in a human terminal; pass `--detach` to stay local. Scripts and coding-agent environments remain non-attaching. Detach from tmux with `Ctrl-B D`.
|
|
55
|
+
|
|
56
|
+
Need a saved target first?
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
fwd setup # interactive target setup
|
|
60
|
+
fwd setup ssh --host my-box --target-name work
|
|
61
|
+
fwd config --example runpod # current generated config reference
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Read [Getting started](docs/getting-started.md) for the full first-session walkthrough.
|
|
65
|
+
|
|
66
|
+
## Choose a target
|
|
67
|
+
|
|
68
|
+
- **SSH:** an existing host, direct address, or OpenSSH alias.
|
|
69
|
+
- **RunPod:** CPU or GPU Pods with per-session persistent network volumes by default.
|
|
70
|
+
- **Lambda Cloud:** GPU instances with persistent filesystems and local-only API credentials.
|
|
71
|
+
- **Slurm:** allocations launched through persistent login-node tmux on shared scratch.
|
|
72
|
+
|
|
73
|
+
See [Configuration and backends](docs/configuration.md#target-setup) for setup, storage, and lifecycle differences.
|
|
74
|
+
|
|
75
|
+
## Common workflows
|
|
76
|
+
|
|
77
|
+
### Run durable work
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
fwd send -- pytest -q
|
|
81
|
+
fwd send --detach -- python train.py
|
|
82
|
+
fwd send --ls --json
|
|
83
|
+
fwd send TASK_ID # reattach to its log
|
|
84
|
+
fwd send TASK_ID --stop # cancel the task, not the session
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Every command runs in remote tmux with a durable ID and log. Streaming returns the remote exit code; `Ctrl-C` cancels and `Ctrl-B` backgrounds the viewer.
|
|
88
|
+
|
|
89
|
+
### Synchronize results
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
fwd diff # compare without changing either side
|
|
93
|
+
fwd push # mirror local synchronized files to remote
|
|
94
|
+
fwd pull outputs/ # additive download; never deletes local files
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Sync honors `.gitignore`, `.fwdignore`, and configured exclusions. Upload includes `.git/` for remote agent continuity; pull and diff exclude Git metadata.
|
|
98
|
+
|
|
99
|
+
### Forward a service
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
fwd ports 3000 # localhost:3000 to remote localhost:3000
|
|
103
|
+
fwd ports work 8080:3000
|
|
104
|
+
fwd ports --ls
|
|
105
|
+
fwd ports --close 3000
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Forwards are loopback-only and persist through a managed SSH control connection.
|
|
109
|
+
|
|
110
|
+
### Stop or destroy compute
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
fwd stop SESSION # stop compute and retain configured persistent storage
|
|
114
|
+
fwd rm SESSION # permanently destroy remote resources
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Both commands protect a reachable dirty remote Git worktree. `rm` is irreversible; force flags explicitly accept possible loss. See [Lifecycle safety](docs/commands.md#stop-remove-and-uninstall) before automating cleanup.
|
|
118
|
+
|
|
119
|
+
## Coding-agent skill
|
|
120
|
+
|
|
121
|
+
fwd ships an Agent Skills-compatible workflow for Codex, Claude Code, and other supporting agents. The first interactive invocation offers to install the bundled skill. It can also be installed directly:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
npx skills add Sid-MB/fwd --skill fwd -g -a codex -a claude-code
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Invoke it as `$fwd ...` in Codex or `/fwd ...` in Claude Code. See [Coding agents](docs/agents.md#install-the-fwd-skill) for behavior and credential guidance.
|
|
128
|
+
|
|
129
|
+
## Documentation
|
|
130
|
+
|
|
131
|
+
### User guide
|
|
132
|
+
|
|
133
|
+
- [Getting started](docs/getting-started.md): installation, first launch, target setup, and the everyday workflow.
|
|
134
|
+
- [Commands and lifecycle](docs/commands.md): durable tasks, synchronization, inspection, port forwarding, stopping, and removal.
|
|
135
|
+
- [Configuration and backends](docs/configuration.md): config layers, SSH, RunPod, Lambda Cloud, Slurm, toolchains, and defaults.
|
|
136
|
+
- [Coding agents](docs/agents.md): Claude/Codex transfer, follow-up turns, credentials, runtime policy, and skill installation.
|
|
137
|
+
- [Troubleshooting](docs/troubleshooting.md): diagnostics, launch recovery, dirty worktrees, sync limits, and destructive operations.
|
|
138
|
+
- [User documentation index](docs/README.md): the complete end-user map.
|
|
139
|
+
|
|
140
|
+
The installed CLI is the authoritative option reference:
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
fwd --help
|
|
144
|
+
fwd COMMAND --help
|
|
145
|
+
fwd config --example
|
|
146
|
+
fwd config --schema
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Developer guide
|
|
150
|
+
|
|
151
|
+
- [Developer documentation index](dev-docs/README.md): architecture, provider notes, validation evidence, and repository map.
|
|
152
|
+
- [Adding a target backend](dev-docs/adding-target-backends.md)
|
|
153
|
+
- [Adding a project toolchain](dev-docs/adding-toolchains.md)
|
|
154
|
+
- [Performance benchmarking](dev-docs/benchmarking.md)
|
|
155
|
+
- [Contributing](CONTRIBUTING.md)
|
fwdit-0.1.2/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# fwd
|
|
2
|
+
|
|
3
|
+
**Move your coding project and agent session to remote compute.**
|
|
4
|
+
|
|
5
|
+
`fwd` provisions or connects to a remote target, synchronizes the current project, prepares its toolchain, and starts a persistent shell, command, Claude Code, or Codex session in tmux. Disconnect your laptop and return later: the session, durable tasks, and logs remain available.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
laptop remote SSH / RunPod / Lambda / Slurm
|
|
9
|
+
project ───────────── sync ──────────▶ project checkout
|
|
10
|
+
agent context ──────── optional ──────▶ Claude or Codex state
|
|
11
|
+
tmux session + durable task manager
|
|
12
|
+
terminal ◀────────── attach / stream ── persistent work
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
uv tool install fwdit
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or try it without installing:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
uvx --from fwdit fwd --help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Requires Python 3.12+, `ssh`, and `rsync` locally. Run `fwd doctor` to check target-specific requirements.
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
Run fwd from the project you want to move:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
fwd # attach to this project's session, or create one interactively
|
|
35
|
+
fwd up runpod codex # launch Codex on RunPod; auto-attach in a human terminal
|
|
36
|
+
fwd up --detach runpod codex # launch Codex but stay in the local terminal
|
|
37
|
+
fwd up --target work # use a configured SSH/cloud/HPC target
|
|
38
|
+
fwd up -- python train.py # launch and stream a durable command
|
|
39
|
+
fwd ls # inspect sessions and live status
|
|
40
|
+
fwd attach SESSION # reconnect from a human terminal
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Bare `fwd` is the interactive reuse workflow. Agent launches auto-attach in a human terminal; pass `--detach` to stay local. Scripts and coding-agent environments remain non-attaching. Detach from tmux with `Ctrl-B D`.
|
|
44
|
+
|
|
45
|
+
Need a saved target first?
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
fwd setup # interactive target setup
|
|
49
|
+
fwd setup ssh --host my-box --target-name work
|
|
50
|
+
fwd config --example runpod # current generated config reference
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Read [Getting started](docs/getting-started.md) for the full first-session walkthrough.
|
|
54
|
+
|
|
55
|
+
## Choose a target
|
|
56
|
+
|
|
57
|
+
- **SSH:** an existing host, direct address, or OpenSSH alias.
|
|
58
|
+
- **RunPod:** CPU or GPU Pods with per-session persistent network volumes by default.
|
|
59
|
+
- **Lambda Cloud:** GPU instances with persistent filesystems and local-only API credentials.
|
|
60
|
+
- **Slurm:** allocations launched through persistent login-node tmux on shared scratch.
|
|
61
|
+
|
|
62
|
+
See [Configuration and backends](docs/configuration.md#target-setup) for setup, storage, and lifecycle differences.
|
|
63
|
+
|
|
64
|
+
## Common workflows
|
|
65
|
+
|
|
66
|
+
### Run durable work
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
fwd send -- pytest -q
|
|
70
|
+
fwd send --detach -- python train.py
|
|
71
|
+
fwd send --ls --json
|
|
72
|
+
fwd send TASK_ID # reattach to its log
|
|
73
|
+
fwd send TASK_ID --stop # cancel the task, not the session
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Every command runs in remote tmux with a durable ID and log. Streaming returns the remote exit code; `Ctrl-C` cancels and `Ctrl-B` backgrounds the viewer.
|
|
77
|
+
|
|
78
|
+
### Synchronize results
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
fwd diff # compare without changing either side
|
|
82
|
+
fwd push # mirror local synchronized files to remote
|
|
83
|
+
fwd pull outputs/ # additive download; never deletes local files
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Sync honors `.gitignore`, `.fwdignore`, and configured exclusions. Upload includes `.git/` for remote agent continuity; pull and diff exclude Git metadata.
|
|
87
|
+
|
|
88
|
+
### Forward a service
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
fwd ports 3000 # localhost:3000 to remote localhost:3000
|
|
92
|
+
fwd ports work 8080:3000
|
|
93
|
+
fwd ports --ls
|
|
94
|
+
fwd ports --close 3000
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Forwards are loopback-only and persist through a managed SSH control connection.
|
|
98
|
+
|
|
99
|
+
### Stop or destroy compute
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
fwd stop SESSION # stop compute and retain configured persistent storage
|
|
103
|
+
fwd rm SESSION # permanently destroy remote resources
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Both commands protect a reachable dirty remote Git worktree. `rm` is irreversible; force flags explicitly accept possible loss. See [Lifecycle safety](docs/commands.md#stop-remove-and-uninstall) before automating cleanup.
|
|
107
|
+
|
|
108
|
+
## Coding-agent skill
|
|
109
|
+
|
|
110
|
+
fwd ships an Agent Skills-compatible workflow for Codex, Claude Code, and other supporting agents. The first interactive invocation offers to install the bundled skill. It can also be installed directly:
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
npx skills add Sid-MB/fwd --skill fwd -g -a codex -a claude-code
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Invoke it as `$fwd ...` in Codex or `/fwd ...` in Claude Code. See [Coding agents](docs/agents.md#install-the-fwd-skill) for behavior and credential guidance.
|
|
117
|
+
|
|
118
|
+
## Documentation
|
|
119
|
+
|
|
120
|
+
### User guide
|
|
121
|
+
|
|
122
|
+
- [Getting started](docs/getting-started.md): installation, first launch, target setup, and the everyday workflow.
|
|
123
|
+
- [Commands and lifecycle](docs/commands.md): durable tasks, synchronization, inspection, port forwarding, stopping, and removal.
|
|
124
|
+
- [Configuration and backends](docs/configuration.md): config layers, SSH, RunPod, Lambda Cloud, Slurm, toolchains, and defaults.
|
|
125
|
+
- [Coding agents](docs/agents.md): Claude/Codex transfer, follow-up turns, credentials, runtime policy, and skill installation.
|
|
126
|
+
- [Troubleshooting](docs/troubleshooting.md): diagnostics, launch recovery, dirty worktrees, sync limits, and destructive operations.
|
|
127
|
+
- [User documentation index](docs/README.md): the complete end-user map.
|
|
128
|
+
|
|
129
|
+
The installed CLI is the authoritative option reference:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
fwd --help
|
|
133
|
+
fwd COMMAND --help
|
|
134
|
+
fwd config --example
|
|
135
|
+
fwd config --schema
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Developer guide
|
|
139
|
+
|
|
140
|
+
- [Developer documentation index](dev-docs/README.md): architecture, provider notes, validation evidence, and repository map.
|
|
141
|
+
- [Adding a target backend](dev-docs/adding-target-backends.md)
|
|
142
|
+
- [Adding a project toolchain](dev-docs/adding-toolchains.md)
|
|
143
|
+
- [Performance benchmarking](dev-docs/benchmarking.md)
|
|
144
|
+
- [Contributing](CONTRIBUTING.md)
|
fwdit-0.1.2/SKILL.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fwd
|
|
3
|
+
description: Move a coding project or active Claude Code/Codex workflow to remote compute with fwd. Use for remote development, SSH, RunPod, Lambda Cloud, Slurm, extra CPU/GPU/memory, persistent remote agents, durable commands, synchronization, attaching, stopping, or destroying remote sessions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# fwd remote development
|
|
7
|
+
|
|
8
|
+
Use `fwd` to provision or reuse remote compute, synchronize the current project, prepare its tools, and run a persistent coding agent or command in tmux. Invoking this skill means the user wants fwd used.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. Preserve the user's task, requested target, hardware, and shutdown requirements. Use the caller's agent (`codex` from Codex, `claude` from Claude) unless the user specifies another.
|
|
13
|
+
2. If a provider machine must be chosen, inspect exact values before launch with `fwd up --machines` or `fwd up TARGET --machines`. Prefer CPU unless the user requests a GPU; never guess or abbreviate a provider identifier.
|
|
14
|
+
3. Launch without taking over the terminal: `fwd up --detach --agent AGENT`, adding `--target TARGET` and `--machine MACHINE` only when selected. Never use a bare/reuse/attach form as a tool call.
|
|
15
|
+
4. Read the exact session name and live state from `fwd ls --json`.
|
|
16
|
+
5. Send the preserved task with `fwd send --name SESSION agent "TASK"`. Stream and iterate by default; use `--detach` only when the user asks to background the task.
|
|
17
|
+
6. Inspect changed work with `fwd diff -q SESSION`, use `fwd diff SESSION` when details matter, and retrieve accepted files with `fwd pull --name SESSION`.
|
|
18
|
+
7. Report the result and exact commands the user may need, especially `fwd attach SESSION`, `fwd send --name SESSION --ls`, and `fwd stop SESSION`.
|
|
19
|
+
|
|
20
|
+
If setup is required, follow the exact flags printed by fwd. Do not open an interactive setup wizard or invent target values.
|
|
21
|
+
|
|
22
|
+
For a requested shell command instead of agent work, use `fwd send --name SESSION -- COMMAND...`. Reattach with `fwd send --name SESSION TASK_ID`; cancel only that task with `fwd send --name SESSION TASK_ID --stop`.
|
|
23
|
+
|
|
24
|
+
If `fwd` is unavailable, install the published distribution with `uv tool install fwdit`. If `uv` is unavailable, report that Python 3.12+, `uv`, `ssh`, and `rsync` are required instead of improvising another installer.
|
|
25
|
+
|
|
26
|
+
## Safe automation
|
|
27
|
+
|
|
28
|
+
- Prefer `--json` for `fwd ls`, `fwd doctor`, `fwd info`, and task listings. Diagnostics remain on stderr.
|
|
29
|
+
- Never run bare `fwd`, `fwd TARGET`, `fwd attach`, `fwd a`, `fwd up --reuse`, or `fwd up --attach` as a tool call; they can take over a human terminal. Hand the exact attach command to the user.
|
|
30
|
+
- Do not use `--restart` unless the user authorizes restarting stopped billable compute.
|
|
31
|
+
- Do not use `--creds` unless the user authorizes copying live Claude credentials. GitHub setup defaults on; use `--no-setup-github` when credentials must stay local.
|
|
32
|
+
- Never force `stop`, `rm`, or stop-after past a dirty or unreachable worktree unless the user explicitly accepts losing remote-only changes.
|
|
33
|
+
- Never run `fwd rm --all --force` unless the user explicitly requests destruction of every tracked remote resource.
|
|
34
|
+
- Run `fwd uninstall --force` only for an explicit local-uninstall request after explaining that it does not destroy remote resources; prefer `fwd rm --all` first.
|
|
35
|
+
- Prefer `fwd diff -q` before push or pull. Exit 0 means synchronized, 1 different, and 2 error.
|
|
36
|
+
- If upload exceeds `sync.max_size_gb`, confirm the directory is intentional before using the exact project-scoped limit command printed by fwd.
|
|
37
|
+
- Missing `npx` or a failed optional skill refresh must not block normal fwd commands.
|
|
38
|
+
- If preparation fails after provisioning and sync, give the human `fwd attach SESSION --raw` for a recovery shell. This does not authorize restarting stopped compute.
|
|
39
|
+
|
|
40
|
+
## Stop after work
|
|
41
|
+
|
|
42
|
+
For supported backends, use remote-owned shutdown so it survives local disconnection:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
fwd up --stop-after -- COMMAND...
|
|
46
|
+
fwd send --name SESSION --stop-after agent "TASK"
|
|
47
|
+
fwd send --name SESSION stopafter
|
|
48
|
+
fwd send --name SESSION cancel stopafter
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Confirm the lifecycle task with `fwd send --name SESSION --ls --json`. Stop-after refuses a dirty remote worktree; never force it without explicit acceptance of data loss.
|
|
52
|
+
|
|
53
|
+
Lambda does not support remote stop-after because its broad API key stays local. Retrieve durable results, then tell the user to run `fwd stop SESSION` from a connected machine.
|
|
54
|
+
|
|
55
|
+
## Useful commands
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
fwd up --detach --target runpod --agent codex
|
|
59
|
+
fwd up --detach --new --target runpod --agent codex
|
|
60
|
+
fwd up -- COMMAND...
|
|
61
|
+
fwd send --name SESSION agent "TASK"
|
|
62
|
+
fwd send --name SESSION -- COMMAND...
|
|
63
|
+
fwd send --name SESSION --ls --json
|
|
64
|
+
fwd diff -q SESSION
|
|
65
|
+
fwd pull --name SESSION outputs/
|
|
66
|
+
fwd ls --all-projects --json
|
|
67
|
+
fwd doctor --json
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## References
|
|
71
|
+
|
|
72
|
+
- Read [targets and configuration](references/targets-and-config.md) for resolution, setup, defaults, machines, and backend behavior.
|
|
73
|
+
- Read [commands and lifecycle](references/commands-and-lifecycle.md) for launch, durable tasks, synchronization, ports, attachment, stopping, and destruction.
|
|
74
|
+
- Read [agent transfer](references/agent-transfer.md) before launching Claude Code or Codex when transcripts, settings, skills, authentication, or remote control matter.
|
|
75
|
+
|
|
76
|
+
`fwd --help` and `fwd COMMAND --help` are authoritative for the installed version.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# fwd developer documentation
|
|
2
|
+
|
|
3
|
+
This folder contains architecture, extension, validation, and implementation notes for contributors working on fwd.
|
|
4
|
+
|
|
5
|
+
## Extend fwd
|
|
6
|
+
|
|
7
|
+
- [Adding a target backend](adding-target-backends.md): backend contract, configuration schema, lifecycle safety, registration, and verification.
|
|
8
|
+
- [Adding a project toolchain](adding-toolchains.md): detection, requirements, installation, registration, and testing.
|
|
9
|
+
|
|
10
|
+
## Understand provider implementations
|
|
11
|
+
|
|
12
|
+
- [RunPod notes](runpod-notes.md): observed `runpodctl` behavior, endpoint churn, persistence, and fixtures.
|
|
13
|
+
- [Lambda Cloud notes](lambda-notes.md): API, credential handling, deterministic ownership, storage, and lifecycle.
|
|
14
|
+
- [Slurm notes](slurm-notes.md): login-node tmux, allocation scripts, path guards, and shared scratch.
|
|
15
|
+
|
|
16
|
+
## Validation and performance
|
|
17
|
+
|
|
18
|
+
- [Live end-to-end report](live-e2e-report.md): dated RunPod validation evidence and discovered regressions.
|
|
19
|
+
- [Session transfer notes](session-transfer-notes.md): Claude transcript relocation experiment and encoding rules.
|
|
20
|
+
- [Performance benchmarking](benchmarking.md): in-process command benchmarks and baseline comparison.
|
|
21
|
+
|
|
22
|
+
## Repository map
|
|
23
|
+
|
|
24
|
+
- `src/fwd/backends/`: provider lifecycle implementations.
|
|
25
|
+
- `src/fwd/toolchains/` and `src/fwd/tooling.py`: project detection and remote requirements.
|
|
26
|
+
- `src/fwd/ops/`: launch, attach, synchronization, lifecycle, and task orchestration.
|
|
27
|
+
- `src/fwd/agents/`: Claude and Codex transfer/runtime integrations.
|
|
28
|
+
- `tests/`: offline unit and integration tests; provider fixtures are under `tests/fixtures/`.
|
|
29
|
+
- `references/`: compact references packaged with the coding-agent skill, not the end-user documentation site.
|
|
30
|
+
|
|
31
|
+
## Development workflow
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
uv sync
|
|
35
|
+
uv run pytest
|
|
36
|
+
uv run fwd --help
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
See [CONTRIBUTING.md](../CONTRIBUTING.md) for contribution and publishing policy. User-facing behavior belongs in [docs](../docs/README.md), and concise project orientation belongs in the [top-level README](../README.md).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# fwd user guide
|
|
2
|
+
|
|
3
|
+
This folder contains the user documentation for `fwd`. Start with the guide that matches what you want to do:
|
|
4
|
+
|
|
5
|
+
- [Getting started](getting-started.md): install fwd, create a target, and launch your first remote session.
|
|
6
|
+
- [Commands and lifecycle](commands.md): launch, attach, run durable tasks, synchronize files, forward ports, stop, and remove sessions.
|
|
7
|
+
- [Configuration and backends](configuration.md): layered configuration, SSH, RunPod, Lambda Cloud, Slurm, defaults, and project setup.
|
|
8
|
+
- [Coding agents](agents.md): move Claude Code or Codex work, send follow-up turns, manage credentials, and install the fwd skill.
|
|
9
|
+
- [Troubleshooting](troubleshooting.md): diagnose failures, recover partial launches, and avoid data loss.
|
|
10
|
+
|
|
11
|
+
The installed CLI is the authoritative option reference:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
fwd --help
|
|
15
|
+
fwd COMMAND --help
|
|
16
|
+
fwd config --example
|
|
17
|
+
fwd config --schema
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Contributing to fwd? See the [developer documentation](../dev-docs/README.md).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "fwdit"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "Move coding work and agent sessions to remote compute"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"prompt-toolkit>=3.0",
|
|
9
|
+
"typer>=0.12",
|
|
10
|
+
"rich>=13",
|
|
11
|
+
"tomlkit>=0.13",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
fwd = "fwd.cli:entrypoint"
|
|
16
|
+
|
|
17
|
+
[dependency-groups]
|
|
18
|
+
dev = ["pytest>=8"]
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
22
|
+
build-backend = "hatchling.build"
|
|
23
|
+
|
|
24
|
+
[tool.hatch.version]
|
|
25
|
+
# The shared release workflow creates the next vX.Y.Z tag before building, so the wheel, sdist, Git tag, and GitHub Release all receive the same immutable version.
|
|
26
|
+
source = "vcs"
|
|
27
|
+
|
|
28
|
+
[tool.hatch.version.raw-options]
|
|
29
|
+
# Source archives without Git metadata still expose a valid diagnostic version instead of failing to build.
|
|
30
|
+
fallback_version = "0.0.0"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["src/fwd"]
|
|
34
|
+
|
|
35
|
+
# bootstrap.sh must land inside the installed package so remote.BOOTSTRAP_PATH can resolve it via importlib.resources.
|
|
36
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
37
|
+
"src/fwd/scripts/bootstrap.sh" = "fwd/scripts/bootstrap.sh"
|
|
38
|
+
"src/fwd/scripts/codex_tui_send.py" = "fwd/scripts/codex_tui_send.py"
|
|
39
|
+
"SKILL.md" = "fwd/SKILL.md"
|
|
40
|
+
"agents" = "fwd/skill_agents"
|
|
41
|
+
"references" = "fwd/references"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.sdist]
|
|
44
|
+
include = ["src/fwd", "tests", "README.md", "/SKILL.md", "/agents", "/references"]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Claude Code and Codex transfer
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Shared behavior
|
|
6
|
+
- Claude Code
|
|
7
|
+
- Codex
|
|
8
|
+
- Authentication
|
|
9
|
+
- Human handoff
|
|
10
|
+
|
|
11
|
+
## Shared behavior
|
|
12
|
+
|
|
13
|
+
Both magic commands synchronize the project, bootstrap remote tooling, start a persistent tmux session, and auto-attach only from a human terminal:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
fwd up --target TARGET --agent claude
|
|
17
|
+
fwd up --target TARGET --agent codex
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Agents should run them without `--attach`. Non-interactive detection keeps the launch in the background.
|
|
21
|
+
|
|
22
|
+
On RunPod, fwd prepares agent state before tool installation because `/root` is erased on every stop. GPU pods keep
|
|
23
|
+
`~/.claude` or `~/.codex` beneath the persistent tool prefix and recreate the home symlink on relaunch, so remote
|
|
24
|
+
authentication, conversations, settings, and Codex's managed standalone payload survive. CPU pods have no persistent
|
|
25
|
+
volume; their full relaunch reconstructs local inputs but cannot retain state that existed only on the stopped pod.
|
|
26
|
+
|
|
27
|
+
After launch, communicate with the running remote conversation through durable send tasks:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
fwd send agent --detach "run the tests and fix failures"
|
|
31
|
+
fwd send --ls --json
|
|
32
|
+
fwd send TASK_ID
|
|
33
|
+
fwd send TASK_ID --stop
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Use `--immediate MESSAGE` when a new instruction should cancel and replace the active turn. A plain message queues
|
|
37
|
+
behind an active managed turn. Send-task cancellation never stops the fwd session or its remote compute.
|
|
38
|
+
|
|
39
|
+
## Claude Code
|
|
40
|
+
|
|
41
|
+
The default `--session` mode moves the real local transcript and asks remote Claude to resume it. Transfer failures degrade to a plain Claude launch with a warning.
|
|
42
|
+
|
|
43
|
+
`--handoff` replaces transcript transfer with a generated `HANDOFF.md`; use it only when the user requests a summary handoff. `--user-config` uploads portable Claude configuration while excluding credentials and history.
|
|
44
|
+
|
|
45
|
+
## Codex
|
|
46
|
+
|
|
47
|
+
Codex receives portable settings, configuration, and skills. It does not receive the current Codex transcript or authentication. Tell the user that the remote agent begins with the synchronized project and personal workflow configuration, not the local conversation.
|
|
48
|
+
|
|
49
|
+
Once remote Codex has started, `fwd send agent MESSAGE` resumes its most recent remote project conversation through
|
|
50
|
+
Codex's JSONL non-interactive interface. Human terminals receive concise text/tool events; non-interactive callers
|
|
51
|
+
receive the original machine-readable event stream.
|
|
52
|
+
|
|
53
|
+
Use JSON output and non-attaching commands when Codex is driving fwd:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
fwd doctor --json
|
|
57
|
+
fwd up codex --target TARGET
|
|
58
|
+
fwd ls --json
|
|
59
|
+
fwd diff -q TARGET
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Authentication
|
|
63
|
+
|
|
64
|
+
Prefer logging in on the remote machine for coding-agent authentication. `--creds` writes a live Claude OAuth token to remote disk and requires explicit authorization in the current conversation. Codex authentication is never copied.
|
|
65
|
+
|
|
66
|
+
GitHub authentication defaults on for development VMs and can be disabled with `[github] auth = false` or
|
|
67
|
+
`--no-setup-github`. Fwd resolves `GH_TOKEN`, `GITHUB_TOKEN`, the active local gh account, Git's credential helper,
|
|
68
|
+
then `~/.netrc`; an interactive caller can paste a PAT as the final fallback. It streams the selected credential to remote standard
|
|
69
|
+
input, configures HTTPS Git access, and persists the remote credential on RunPod volumes. The token never enters
|
|
70
|
+
project files, argv, logs, config, or session state. A direct `fwd send git push`, any sent coding-agent turn, and
|
|
71
|
+
`fwd attach` can repair an older session in place. Do not describe `fwd pull && git push` as a way to transfer a remote
|
|
72
|
+
commit: pull intentionally omits `.git/`. It can retrieve uncommitted files for a new local commit; preserving an
|
|
73
|
+
existing remote commit requires a remote push or an explicitly exported patch or Git bundle.
|
|
74
|
+
|
|
75
|
+
## Human handoff
|
|
76
|
+
|
|
77
|
+
After launch, report the exact resolved target/session and tell the human:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
fwd attach SESSION
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If the user wants a result without attaching, use `fwd send agent`, `fwd send -- COMMAND`, or `fwd pull`.
|