You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(sync): configurable sync direction (spec.sync.direction: bi|up|down)
A single bidirectional folder carries both inputs (code, local->pod) and
outputs (results, pod->local), so a bad local write can clobber
pod-generated data. Per-path direction inside one folder is impossible
in Syncthing (.stignore lives in the directory; per-path folder types
were rejected upstream), so the direction is a per-folder setting:
- spec.sync.direction: bi (default) | up (local sendonly, pod
receiveonly) | down (pod sendonly, local receiveonly — a local write
can never clobber pod results).
- `okdev sync --mode` now defaults to the configured direction; an
explicit flag still wins. Mode values are validated.
- `okdev up` starts sync in the configured direction and skips the
two-phase bootstrap for directional folders (one side is already
sendonly, so the final folder types are safe from the first start).
Direction is part of the sync config hash, so editing it takes effect
on the next up; explicit "bi" hashes like the legacy default to avoid
a restart on upgrade.
- `up --reset-workspace` and `sync reset-remote` are rejected with
direction "down": they reseed the remote from local, which would sync
back as deletions over the pod's data.
- `status --details` shows the direction; docs cover choosing a
direction and keeping generated outputs out of the synced path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Advanced command. Starts detached background sync by default; use `--foreground` for sync debugging, or explicit one-way sync (`up`/`down`).
307
+
-`--mode` defaults to `spec.sync.direction` from the config (falling back to `bi`); an explicit flag overrides it for that invocation. See `spec.sync.direction` in the config manifest for choosing a persistent direction — `down` makes the pod the authority so local writes can never clobber pod-generated results.
307
308
- For default `--mode bi`, no-op when background sync is already active for the session.
-`--reset`: check local-to-hub sync and mesh receiver health, then reset only what is broken. Skips the local sync teardown when the primary sync is already healthy. For sessions with mesh receivers, probes each receiver and re-runs mesh setup only when broken or disconnected receivers are found.
| `direction` | `string` | `bi` | Sync direction for the local↔pod folder: `bi`(bidirectional), `up` (local is the authority: local sendonly, pod receiveonly), `down` (pod is the authority: pod sendonly, local receiveonly) |
236
237
| `paths` | `[]string` | — | Mappings in `local:remote` format (max 1 entry) |
237
238
| `syncthing.version` | `string` | `v1.29.7` | Local Syncthing binary version |
| `syncthing.compression` | `bool` | `false` | Use Syncthing `always` compression for peer connections instead of the default `metadata` mode |
243
244
| `syncthing.versioningDays` | `int` | `30` | Keep files overwritten or deleted by sync in `.stversions` for this many days (staggered versioning, both sides); `0` disables |
244
245
245
-
**Validation:** `engine` must be `syncthing`; each `paths[]` entry must be `local:remote`; `versioningDays` must be `>= 0`.
246
+
**Validation:** `engine` must be `syncthing`; `direction` must be `bi`, `up`, or `down`; each `paths[]` entry must be `local:remote`; `versioningDays` must be `>= 0`.
247
+
248
+
**Sync direction.** `direction` applies to the whole synced folder — per-path direction inside one folder is impossible with Syncthing (ignore rules live in the directory itself; per-path folder types were rejected upstream). Pick the direction by what the folder carries:
249
+
250
+
- `bi` (default): source code you edit on both sides. Either side can overwrite the other, so **keep generated outputs (results, checkpoints, logs) out of the synced path** — write them to a non-synced location and fetch with `okdev cp` or `okdev jobs logs`. Versioning (`.stversions/`) is the safety net, not the design.
251
+
- `up`: the folder is a code drop. Nothing the pod writes can ever touch local files; pod-side writes into the folder are flagged by Syncthing but not propagated.
252
+
- `down`: the folder carries pod-generated results. A stray local write (for example an empty file from a failed redirect) can never clobber the pod's data. `okdev up --reset-workspace` and `okdev sync reset-remote` are rejected in this direction because they reseed the remote from local.
253
+
254
+
An explicit `okdev sync --mode` overrides the configured direction for that invocation. Changing `direction` takes effect on the next `okdev up` (it restarts sync with the new folder types). Mesh receiver pods are always receiveonly regardless of direction.
246
255
247
256
Local ignore rules come from the synced workspace's `.stignore`. `okdev init` writes a starter `.stignore` for built-in templates, and `okdev up` creates one with default patterns if the local sync root does not already have one. Editing `.stignore` takes effect automatically as Syncthing notices the change, but it does not remove files that were already synced to the remote workspace. For faster initial syncs, consider ignoring large generated build outputs or local test artifacts such as `debug/`, `release/`, caches, and dataset directories when they do not need to exist remotely.
248
257
@@ -254,6 +263,7 @@ The `syncthing.version` field controls the local binary on your machine. The Syn
// reset-workspace clears the remote and reseeds it from local; with
161
+
// direction "down" the pod is the authority and local is
162
+
// receiveonly, so the combination would wipe the remote and then
163
+
// pull the deletions back over the local files.
164
+
returnnil, fmt.Errorf("--reset-workspace conflicts with spec.sync.direction: down (the pod is the sync authority); remove the flag or switch direction")
0 commit comments